Completed
Branch fix-dummy-related-question-qst... (e5efcf)
by
unknown
07:49 queued 03:45
created
core/db_classes/EE_Line_Item.class.php 2 patches
Spacing   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -88,7 +88,7 @@  discard block
 block discarded – undo
88 88
     protected function __construct($fieldValues = array(), $bydb = false, $timezone = '')
89 89
     {
90 90
         parent::__construct($fieldValues, $bydb, $timezone);
91
-        if (! $this->get('LIN_code')) {
91
+        if ( ! $this->get('LIN_code')) {
92 92
             $this->set_code($this->generate_code());
93 93
         }
94 94
     }
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
     public function name()
156 156
     {
157 157
         $name = $this->get('LIN_name');
158
-        if (! $name) {
158
+        if ( ! $name) {
159 159
             $name = ucwords(str_replace('-', ' ', $this->type()));
160 160
         }
161 161
         return $name;
@@ -615,7 +615,7 @@  discard block
 block discarded – undo
615 615
                 )
616 616
             );
617 617
         }
618
-        if (! is_array($this->_children)) {
618
+        if ( ! is_array($this->_children)) {
619 619
             $this->_children = array();
620 620
         }
621 621
         return $this->_children;
@@ -856,7 +856,7 @@  discard block
 block discarded – undo
856 856
             }
857 857
             return $line_item->save();
858 858
         }
859
-        $this->_children[ $line_item->code() ] = $line_item;
859
+        $this->_children[$line_item->code()] = $line_item;
860 860
         if ($line_item->parent() !== $this) {
861 861
             $line_item->set_parent($this);
862 862
         }
@@ -880,7 +880,7 @@  discard block
 block discarded – undo
880 880
     public function set_parent($line_item)
881 881
     {
882 882
         if ($this->ID()) {
883
-            if (! $line_item->ID()) {
883
+            if ( ! $line_item->ID()) {
884 884
                 $line_item->save();
885 885
             }
886 886
             $this->set_parent_ID($line_item->ID());
@@ -912,8 +912,8 @@  discard block
 block discarded – undo
912 912
                 array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code))
913 913
             );
914 914
         }
915
-        return isset($this->_children[ $code ])
916
-            ? $this->_children[ $code ]
915
+        return isset($this->_children[$code])
916
+            ? $this->_children[$code]
917 917
             : null;
918 918
     }
919 919
 
@@ -973,8 +973,8 @@  discard block
 block discarded – undo
973 973
             }
974 974
             return $items_deleted;
975 975
         }
976
-        if (isset($this->_children[ $code ])) {
977
-            unset($this->_children[ $code ]);
976
+        if (isset($this->_children[$code])) {
977
+            unset($this->_children[$code]);
978 978
             return 1;
979 979
         }
980 980
         return 0;
@@ -1015,7 +1015,7 @@  discard block
 block discarded – undo
1015 1015
     public function generate_code()
1016 1016
     {
1017 1017
         // each line item in the cart requires a unique identifier
1018
-        return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime());
1018
+        return md5($this->get('OBJ_type').$this->get('OBJ_ID').microtime());
1019 1019
     }
1020 1020
 
1021 1021
 
@@ -1228,7 +1228,7 @@  discard block
 block discarded – undo
1228 1228
         $has_children = ! empty($my_children);
1229 1229
         if ($has_children && $this->is_line_item()) {
1230 1230
             $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children);
1231
-        } elseif (! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) {
1231
+        } elseif ( ! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) {
1232 1232
             $total = $this->unit_price() * $this->quantity();
1233 1233
         } elseif ($this->is_sub_total() || $this->is_total()) {
1234 1234
             $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children);
@@ -1243,13 +1243,13 @@  discard block
 block discarded – undo
1243 1243
             if ($this->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_EVENT) {
1244 1244
                 $this->set_quantity(1);
1245 1245
             }
1246
-            if (! $this->is_percent()) {
1246
+            if ( ! $this->is_percent()) {
1247 1247
                 $this->set_unit_price($total);
1248 1248
             }
1249 1249
         }
1250 1250
         // we don't want to bother saving grand totals, because that needs to factor in taxes anyways
1251 1251
         // so it ought to be
1252
-        if (! $this->is_total()) {
1252
+        if ( ! $this->is_total()) {
1253 1253
             $this->set_total($total);
1254 1254
             // if not a percent line item, make sure we keep the unit price in sync
1255 1255
             if (
@@ -1597,7 +1597,7 @@  discard block
 block discarded – undo
1597 1597
     public function save_this_and_descendants_to_txn($txn_id = null)
1598 1598
     {
1599 1599
         $count = 0;
1600
-        if (! $txn_id) {
1600
+        if ( ! $txn_id) {
1601 1601
             $txn_id = $this->TXN_ID();
1602 1602
         }
1603 1603
         $this->set_TXN_ID($txn_id);
Please login to merge, or discard this patch.
Indentation   +1738 added lines, -1738 removed lines patch added patch discarded remove patch
@@ -13,1742 +13,1742 @@
 block discarded – undo
13 13
  */
14 14
 class EE_Line_Item extends EE_Base_Class implements EEI_Line_Item
15 15
 {
16
-    /**
17
-     * for children line items (currently not a normal relation)
18
-     *
19
-     * @type EE_Line_Item[]
20
-     */
21
-    protected $_children = array();
22
-
23
-    /**
24
-     * for the parent line item
25
-     *
26
-     * @var EE_Line_Item
27
-     */
28
-    protected $_parent;
29
-
30
-
31
-    /**
32
-     * @param array  $props_n_values          incoming values
33
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
34
-     *                                        used.)
35
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
36
-     *                                        date_format and the second value is the time format
37
-     * @return EE_Line_Item
38
-     * @throws EE_Error
39
-     * @throws InvalidArgumentException
40
-     * @throws InvalidDataTypeException
41
-     * @throws InvalidInterfaceException
42
-     * @throws ReflectionException
43
-     */
44
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
45
-    {
46
-        $has_object = parent::_check_for_object(
47
-            $props_n_values,
48
-            __CLASS__,
49
-            $timezone,
50
-            $date_formats
51
-        );
52
-        return $has_object
53
-            ? $has_object
54
-            : new self($props_n_values, false, $timezone);
55
-    }
56
-
57
-
58
-    /**
59
-     * @param array  $props_n_values  incoming values from the database
60
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
61
-     *                                the website will be used.
62
-     * @return EE_Line_Item
63
-     * @throws EE_Error
64
-     * @throws InvalidArgumentException
65
-     * @throws InvalidDataTypeException
66
-     * @throws InvalidInterfaceException
67
-     * @throws ReflectionException
68
-     */
69
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
70
-    {
71
-        return new self($props_n_values, true, $timezone);
72
-    }
73
-
74
-
75
-    /**
76
-     * Adds some defaults if they're not specified
77
-     *
78
-     * @param array  $fieldValues
79
-     * @param bool   $bydb
80
-     * @param string $timezone
81
-     * @throws EE_Error
82
-     * @throws InvalidArgumentException
83
-     * @throws InvalidDataTypeException
84
-     * @throws InvalidInterfaceException
85
-     * @throws ReflectionException
86
-     */
87
-    protected function __construct($fieldValues = array(), $bydb = false, $timezone = '')
88
-    {
89
-        parent::__construct($fieldValues, $bydb, $timezone);
90
-        if (! $this->get('LIN_code')) {
91
-            $this->set_code($this->generate_code());
92
-        }
93
-    }
94
-
95
-
96
-    /**
97
-     * Gets ID
98
-     *
99
-     * @return int
100
-     * @throws EE_Error
101
-     * @throws InvalidArgumentException
102
-     * @throws InvalidDataTypeException
103
-     * @throws InvalidInterfaceException
104
-     * @throws ReflectionException
105
-     */
106
-    public function ID()
107
-    {
108
-        return $this->get('LIN_ID');
109
-    }
110
-
111
-
112
-    /**
113
-     * Gets TXN_ID
114
-     *
115
-     * @return int
116
-     * @throws EE_Error
117
-     * @throws InvalidArgumentException
118
-     * @throws InvalidDataTypeException
119
-     * @throws InvalidInterfaceException
120
-     * @throws ReflectionException
121
-     */
122
-    public function TXN_ID()
123
-    {
124
-        return $this->get('TXN_ID');
125
-    }
126
-
127
-
128
-    /**
129
-     * Sets TXN_ID
130
-     *
131
-     * @param int $TXN_ID
132
-     * @throws EE_Error
133
-     * @throws InvalidArgumentException
134
-     * @throws InvalidDataTypeException
135
-     * @throws InvalidInterfaceException
136
-     * @throws ReflectionException
137
-     */
138
-    public function set_TXN_ID($TXN_ID)
139
-    {
140
-        $this->set('TXN_ID', $TXN_ID);
141
-    }
142
-
143
-
144
-    /**
145
-     * Gets name
146
-     *
147
-     * @return string
148
-     * @throws EE_Error
149
-     * @throws InvalidArgumentException
150
-     * @throws InvalidDataTypeException
151
-     * @throws InvalidInterfaceException
152
-     * @throws ReflectionException
153
-     */
154
-    public function name()
155
-    {
156
-        $name = $this->get('LIN_name');
157
-        if (! $name) {
158
-            $name = ucwords(str_replace('-', ' ', $this->type()));
159
-        }
160
-        return $name;
161
-    }
162
-
163
-
164
-    /**
165
-     * Sets name
166
-     *
167
-     * @param string $name
168
-     * @throws EE_Error
169
-     * @throws InvalidArgumentException
170
-     * @throws InvalidDataTypeException
171
-     * @throws InvalidInterfaceException
172
-     * @throws ReflectionException
173
-     */
174
-    public function set_name($name)
175
-    {
176
-        $this->set('LIN_name', $name);
177
-    }
178
-
179
-
180
-    /**
181
-     * Gets desc
182
-     *
183
-     * @return string
184
-     * @throws EE_Error
185
-     * @throws InvalidArgumentException
186
-     * @throws InvalidDataTypeException
187
-     * @throws InvalidInterfaceException
188
-     * @throws ReflectionException
189
-     */
190
-    public function desc()
191
-    {
192
-        return $this->get('LIN_desc');
193
-    }
194
-
195
-
196
-    /**
197
-     * Sets desc
198
-     *
199
-     * @param string $desc
200
-     * @throws EE_Error
201
-     * @throws InvalidArgumentException
202
-     * @throws InvalidDataTypeException
203
-     * @throws InvalidInterfaceException
204
-     * @throws ReflectionException
205
-     */
206
-    public function set_desc($desc)
207
-    {
208
-        $this->set('LIN_desc', $desc);
209
-    }
210
-
211
-
212
-    /**
213
-     * Gets quantity
214
-     *
215
-     * @return int
216
-     * @throws EE_Error
217
-     * @throws InvalidArgumentException
218
-     * @throws InvalidDataTypeException
219
-     * @throws InvalidInterfaceException
220
-     * @throws ReflectionException
221
-     */
222
-    public function quantity()
223
-    {
224
-        return $this->get('LIN_quantity');
225
-    }
226
-
227
-
228
-    /**
229
-     * Sets quantity
230
-     *
231
-     * @param int $quantity
232
-     * @throws EE_Error
233
-     * @throws InvalidArgumentException
234
-     * @throws InvalidDataTypeException
235
-     * @throws InvalidInterfaceException
236
-     * @throws ReflectionException
237
-     */
238
-    public function set_quantity($quantity)
239
-    {
240
-        $this->set('LIN_quantity', max($quantity, 0));
241
-    }
242
-
243
-
244
-    /**
245
-     * Gets item_id
246
-     *
247
-     * @return string
248
-     * @throws EE_Error
249
-     * @throws InvalidArgumentException
250
-     * @throws InvalidDataTypeException
251
-     * @throws InvalidInterfaceException
252
-     * @throws ReflectionException
253
-     */
254
-    public function OBJ_ID()
255
-    {
256
-        return $this->get('OBJ_ID');
257
-    }
258
-
259
-
260
-    /**
261
-     * Sets item_id
262
-     *
263
-     * @param string $item_id
264
-     * @throws EE_Error
265
-     * @throws InvalidArgumentException
266
-     * @throws InvalidDataTypeException
267
-     * @throws InvalidInterfaceException
268
-     * @throws ReflectionException
269
-     */
270
-    public function set_OBJ_ID($item_id)
271
-    {
272
-        $this->set('OBJ_ID', $item_id);
273
-    }
274
-
275
-
276
-    /**
277
-     * Gets item_type
278
-     *
279
-     * @return string
280
-     * @throws EE_Error
281
-     * @throws InvalidArgumentException
282
-     * @throws InvalidDataTypeException
283
-     * @throws InvalidInterfaceException
284
-     * @throws ReflectionException
285
-     */
286
-    public function OBJ_type()
287
-    {
288
-        return $this->get('OBJ_type');
289
-    }
290
-
291
-
292
-    /**
293
-     * Gets item_type
294
-     *
295
-     * @return string
296
-     * @throws EE_Error
297
-     * @throws InvalidArgumentException
298
-     * @throws InvalidDataTypeException
299
-     * @throws InvalidInterfaceException
300
-     * @throws ReflectionException
301
-     */
302
-    public function OBJ_type_i18n()
303
-    {
304
-        $obj_type = $this->OBJ_type();
305
-        switch ($obj_type) {
306
-            case EEM_Line_Item::OBJ_TYPE_EVENT:
307
-                $obj_type = esc_html__('Event', 'event_espresso');
308
-                break;
309
-            case EEM_Line_Item::OBJ_TYPE_PRICE:
310
-                $obj_type = esc_html__('Price', 'event_espresso');
311
-                break;
312
-            case EEM_Line_Item::OBJ_TYPE_PROMOTION:
313
-                $obj_type = esc_html__('Promotion', 'event_espresso');
314
-                break;
315
-            case EEM_Line_Item::OBJ_TYPE_TICKET:
316
-                $obj_type = esc_html__('Ticket', 'event_espresso');
317
-                break;
318
-            case EEM_Line_Item::OBJ_TYPE_TRANSACTION:
319
-                $obj_type = esc_html__('Transaction', 'event_espresso');
320
-                break;
321
-        }
322
-        return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this);
323
-    }
324
-
325
-
326
-    /**
327
-     * Sets item_type
328
-     *
329
-     * @param string $OBJ_type
330
-     * @throws EE_Error
331
-     * @throws InvalidArgumentException
332
-     * @throws InvalidDataTypeException
333
-     * @throws InvalidInterfaceException
334
-     * @throws ReflectionException
335
-     */
336
-    public function set_OBJ_type($OBJ_type)
337
-    {
338
-        $this->set('OBJ_type', $OBJ_type);
339
-    }
340
-
341
-
342
-    /**
343
-     * Gets unit_price
344
-     *
345
-     * @return float
346
-     * @throws EE_Error
347
-     * @throws InvalidArgumentException
348
-     * @throws InvalidDataTypeException
349
-     * @throws InvalidInterfaceException
350
-     * @throws ReflectionException
351
-     */
352
-    public function unit_price()
353
-    {
354
-        return $this->get('LIN_unit_price');
355
-    }
356
-
357
-
358
-    /**
359
-     * Sets unit_price
360
-     *
361
-     * @param float $unit_price
362
-     * @throws EE_Error
363
-     * @throws InvalidArgumentException
364
-     * @throws InvalidDataTypeException
365
-     * @throws InvalidInterfaceException
366
-     * @throws ReflectionException
367
-     */
368
-    public function set_unit_price($unit_price)
369
-    {
370
-        $this->set('LIN_unit_price', $unit_price);
371
-    }
372
-
373
-
374
-    /**
375
-     * Checks if this item is a percentage modifier or not
376
-     *
377
-     * @return boolean
378
-     * @throws EE_Error
379
-     * @throws InvalidArgumentException
380
-     * @throws InvalidDataTypeException
381
-     * @throws InvalidInterfaceException
382
-     * @throws ReflectionException
383
-     */
384
-    public function is_percent()
385
-    {
386
-        if ($this->is_tax_sub_total()) {
387
-            // tax subtotals HAVE a percent on them, that percentage only applies
388
-            // to taxable items, so its' an exception. Treat it like a flat line item
389
-            return false;
390
-        }
391
-        $unit_price = abs($this->get('LIN_unit_price'));
392
-        $percent = abs($this->get('LIN_percent'));
393
-        if ($unit_price < .001 && $percent) {
394
-            return true;
395
-        }
396
-        if ($unit_price >= .001 && ! $percent) {
397
-            return false;
398
-        }
399
-        if ($unit_price >= .001 && $percent) {
400
-            throw new EE_Error(
401
-                sprintf(
402
-                    esc_html__(
403
-                        'A Line Item can not have a unit price of (%s) AND a percent (%s)!',
404
-                        'event_espresso'
405
-                    ),
406
-                    $unit_price,
407
-                    $percent
408
-                )
409
-            );
410
-        }
411
-        // if they're both 0, assume its not a percent item
412
-        return false;
413
-    }
414
-
415
-
416
-    /**
417
-     * Gets percent (between 100-.001)
418
-     *
419
-     * @return float
420
-     * @throws EE_Error
421
-     * @throws InvalidArgumentException
422
-     * @throws InvalidDataTypeException
423
-     * @throws InvalidInterfaceException
424
-     * @throws ReflectionException
425
-     */
426
-    public function percent()
427
-    {
428
-        return $this->get('LIN_percent');
429
-    }
430
-
431
-
432
-    /**
433
-     * Sets percent (between 100-0.01)
434
-     *
435
-     * @param float $percent
436
-     * @throws EE_Error
437
-     * @throws InvalidArgumentException
438
-     * @throws InvalidDataTypeException
439
-     * @throws InvalidInterfaceException
440
-     * @throws ReflectionException
441
-     */
442
-    public function set_percent($percent)
443
-    {
444
-        $this->set('LIN_percent', $percent);
445
-    }
446
-
447
-
448
-    /**
449
-     * Gets total
450
-     *
451
-     * @return float
452
-     * @throws EE_Error
453
-     * @throws InvalidArgumentException
454
-     * @throws InvalidDataTypeException
455
-     * @throws InvalidInterfaceException
456
-     * @throws ReflectionException
457
-     */
458
-    public function total()
459
-    {
460
-        return $this->get('LIN_total');
461
-    }
462
-
463
-
464
-    /**
465
-     * Sets total
466
-     *
467
-     * @param float $total
468
-     * @throws EE_Error
469
-     * @throws InvalidArgumentException
470
-     * @throws InvalidDataTypeException
471
-     * @throws InvalidInterfaceException
472
-     * @throws ReflectionException
473
-     */
474
-    public function set_total($total)
475
-    {
476
-        $this->set('LIN_total', $total);
477
-    }
478
-
479
-
480
-    /**
481
-     * Gets order
482
-     *
483
-     * @return int
484
-     * @throws EE_Error
485
-     * @throws InvalidArgumentException
486
-     * @throws InvalidDataTypeException
487
-     * @throws InvalidInterfaceException
488
-     * @throws ReflectionException
489
-     */
490
-    public function order()
491
-    {
492
-        return $this->get('LIN_order');
493
-    }
494
-
495
-
496
-    /**
497
-     * Sets order
498
-     *
499
-     * @param int $order
500
-     * @throws EE_Error
501
-     * @throws InvalidArgumentException
502
-     * @throws InvalidDataTypeException
503
-     * @throws InvalidInterfaceException
504
-     * @throws ReflectionException
505
-     */
506
-    public function set_order($order)
507
-    {
508
-        $this->set('LIN_order', $order);
509
-    }
510
-
511
-
512
-    /**
513
-     * Gets parent
514
-     *
515
-     * @return int
516
-     * @throws EE_Error
517
-     * @throws InvalidArgumentException
518
-     * @throws InvalidDataTypeException
519
-     * @throws InvalidInterfaceException
520
-     * @throws ReflectionException
521
-     */
522
-    public function parent_ID()
523
-    {
524
-        return $this->get('LIN_parent');
525
-    }
526
-
527
-
528
-    /**
529
-     * Sets parent
530
-     *
531
-     * @param int $parent
532
-     * @throws EE_Error
533
-     * @throws InvalidArgumentException
534
-     * @throws InvalidDataTypeException
535
-     * @throws InvalidInterfaceException
536
-     * @throws ReflectionException
537
-     */
538
-    public function set_parent_ID($parent)
539
-    {
540
-        $this->set('LIN_parent', $parent);
541
-    }
542
-
543
-
544
-    /**
545
-     * Gets type
546
-     *
547
-     * @return string
548
-     * @throws EE_Error
549
-     * @throws InvalidArgumentException
550
-     * @throws InvalidDataTypeException
551
-     * @throws InvalidInterfaceException
552
-     * @throws ReflectionException
553
-     */
554
-    public function type()
555
-    {
556
-        return $this->get('LIN_type');
557
-    }
558
-
559
-
560
-    /**
561
-     * Sets type
562
-     *
563
-     * @param string $type
564
-     * @throws EE_Error
565
-     * @throws InvalidArgumentException
566
-     * @throws InvalidDataTypeException
567
-     * @throws InvalidInterfaceException
568
-     * @throws ReflectionException
569
-     */
570
-    public function set_type($type)
571
-    {
572
-        $this->set('LIN_type', $type);
573
-    }
574
-
575
-
576
-    /**
577
-     * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\
578
-     * 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
579
-     * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()`
580
-     * or indirectly by `EE_Line_item::add_child_line_item()`)
581
-     *
582
-     * @return EE_Base_Class|EE_Line_Item
583
-     * @throws EE_Error
584
-     * @throws InvalidArgumentException
585
-     * @throws InvalidDataTypeException
586
-     * @throws InvalidInterfaceException
587
-     * @throws ReflectionException
588
-     */
589
-    public function parent()
590
-    {
591
-        return $this->ID()
592
-            ? $this->get_model()->get_one_by_ID($this->parent_ID())
593
-            : $this->_parent;
594
-    }
595
-
596
-
597
-    /**
598
-     * Gets ALL the children of this line item (ie, all the parts that contribute towards this total).
599
-     *
600
-     * @return EE_Base_Class[]|EE_Line_Item[]
601
-     * @throws EE_Error
602
-     * @throws InvalidArgumentException
603
-     * @throws InvalidDataTypeException
604
-     * @throws InvalidInterfaceException
605
-     * @throws ReflectionException
606
-     */
607
-    public function children()
608
-    {
609
-        if ($this->ID()) {
610
-            return $this->get_model()->get_all(
611
-                array(
612
-                    array('LIN_parent' => $this->ID()),
613
-                    'order_by' => array('LIN_order' => 'ASC'),
614
-                )
615
-            );
616
-        }
617
-        if (! is_array($this->_children)) {
618
-            $this->_children = array();
619
-        }
620
-        return $this->_children;
621
-    }
622
-
623
-
624
-    /**
625
-     * Gets code
626
-     *
627
-     * @return string
628
-     * @throws EE_Error
629
-     * @throws InvalidArgumentException
630
-     * @throws InvalidDataTypeException
631
-     * @throws InvalidInterfaceException
632
-     * @throws ReflectionException
633
-     */
634
-    public function code()
635
-    {
636
-        return $this->get('LIN_code');
637
-    }
638
-
639
-
640
-    /**
641
-     * Sets code
642
-     *
643
-     * @param string $code
644
-     * @throws EE_Error
645
-     * @throws InvalidArgumentException
646
-     * @throws InvalidDataTypeException
647
-     * @throws InvalidInterfaceException
648
-     * @throws ReflectionException
649
-     */
650
-    public function set_code($code)
651
-    {
652
-        $this->set('LIN_code', $code);
653
-    }
654
-
655
-
656
-    /**
657
-     * Gets is_taxable
658
-     *
659
-     * @return boolean
660
-     * @throws EE_Error
661
-     * @throws InvalidArgumentException
662
-     * @throws InvalidDataTypeException
663
-     * @throws InvalidInterfaceException
664
-     * @throws ReflectionException
665
-     */
666
-    public function is_taxable()
667
-    {
668
-        return $this->get('LIN_is_taxable');
669
-    }
670
-
671
-
672
-    /**
673
-     * Sets is_taxable
674
-     *
675
-     * @param boolean $is_taxable
676
-     * @throws EE_Error
677
-     * @throws InvalidArgumentException
678
-     * @throws InvalidDataTypeException
679
-     * @throws InvalidInterfaceException
680
-     * @throws ReflectionException
681
-     */
682
-    public function set_is_taxable($is_taxable)
683
-    {
684
-        $this->set('LIN_is_taxable', $is_taxable);
685
-    }
686
-
687
-
688
-    /**
689
-     * Gets the object that this model-joins-to.
690
-     * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on
691
-     * EEM_Promotion_Object
692
-     *        Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object
693
-     *
694
-     * @return EE_Base_Class | NULL
695
-     * @throws EE_Error
696
-     * @throws InvalidArgumentException
697
-     * @throws InvalidDataTypeException
698
-     * @throws InvalidInterfaceException
699
-     * @throws ReflectionException
700
-     */
701
-    public function get_object()
702
-    {
703
-        $model_name_of_related_obj = $this->OBJ_type();
704
-        return $this->get_model()->has_relation($model_name_of_related_obj)
705
-            ? $this->get_first_related($model_name_of_related_obj)
706
-            : null;
707
-    }
708
-
709
-
710
-    /**
711
-     * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket.
712
-     * (IE, if this line item is for a price or something else, will return NULL)
713
-     *
714
-     * @param array $query_params
715
-     * @return EE_Base_Class|EE_Ticket
716
-     * @throws EE_Error
717
-     * @throws InvalidArgumentException
718
-     * @throws InvalidDataTypeException
719
-     * @throws InvalidInterfaceException
720
-     * @throws ReflectionException
721
-     */
722
-    public function ticket($query_params = array())
723
-    {
724
-        // we're going to assume that when this method is called
725
-        // we always want to receive the attached ticket EVEN if that ticket is archived.
726
-        // This can be overridden via the incoming $query_params argument
727
-        $remove_defaults = array('default_where_conditions' => 'none');
728
-        $query_params = array_merge($remove_defaults, $query_params);
729
-        return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TICKET, $query_params);
730
-    }
731
-
732
-
733
-    /**
734
-     * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket
735
-     *
736
-     * @return EE_Datetime | NULL
737
-     * @throws EE_Error
738
-     * @throws InvalidArgumentException
739
-     * @throws InvalidDataTypeException
740
-     * @throws InvalidInterfaceException
741
-     * @throws ReflectionException
742
-     */
743
-    public function get_ticket_datetime()
744
-    {
745
-        if ($this->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
746
-            $ticket = $this->ticket();
747
-            if ($ticket instanceof EE_Ticket) {
748
-                $datetime = $ticket->first_datetime();
749
-                if ($datetime instanceof EE_Datetime) {
750
-                    return $datetime;
751
-                }
752
-            }
753
-        }
754
-        return null;
755
-    }
756
-
757
-
758
-    /**
759
-     * Gets the event's name that's related to the ticket, if this is for
760
-     * a ticket
761
-     *
762
-     * @return string
763
-     * @throws EE_Error
764
-     * @throws InvalidArgumentException
765
-     * @throws InvalidDataTypeException
766
-     * @throws InvalidInterfaceException
767
-     * @throws ReflectionException
768
-     */
769
-    public function ticket_event_name()
770
-    {
771
-        $event_name = esc_html__('Unknown', 'event_espresso');
772
-        $event = $this->ticket_event();
773
-        if ($event instanceof EE_Event) {
774
-            $event_name = $event->name();
775
-        }
776
-        return $event_name;
777
-    }
778
-
779
-
780
-    /**
781
-     * Gets the event that's related to the ticket, if this line item represents a ticket.
782
-     *
783
-     * @return EE_Event|null
784
-     * @throws EE_Error
785
-     * @throws InvalidArgumentException
786
-     * @throws InvalidDataTypeException
787
-     * @throws InvalidInterfaceException
788
-     * @throws ReflectionException
789
-     */
790
-    public function ticket_event()
791
-    {
792
-        $event = null;
793
-        $ticket = $this->ticket();
794
-        if ($ticket instanceof EE_Ticket) {
795
-            $datetime = $ticket->first_datetime();
796
-            if ($datetime instanceof EE_Datetime) {
797
-                $event = $datetime->event();
798
-            }
799
-        }
800
-        return $event;
801
-    }
802
-
803
-
804
-    /**
805
-     * Gets the first datetime for this lien item, assuming it's for a ticket
806
-     *
807
-     * @param string $date_format
808
-     * @param string $time_format
809
-     * @return string
810
-     * @throws EE_Error
811
-     * @throws InvalidArgumentException
812
-     * @throws InvalidDataTypeException
813
-     * @throws InvalidInterfaceException
814
-     * @throws ReflectionException
815
-     */
816
-    public function ticket_datetime_start($date_format = '', $time_format = '')
817
-    {
818
-        $first_datetime_string = esc_html__('Unknown', 'event_espresso');
819
-        $datetime = $this->get_ticket_datetime();
820
-        if ($datetime) {
821
-            $first_datetime_string = $datetime->start_date_and_time($date_format, $time_format);
822
-        }
823
-        return $first_datetime_string;
824
-    }
825
-
826
-
827
-    /**
828
-     * Adds the line item as a child to this line item. If there is another child line
829
-     * item with the same LIN_code, it is overwritten by this new one
830
-     *
831
-     * @param EEI_Line_Item $line_item
832
-     * @param bool          $set_order
833
-     * @return bool success
834
-     * @throws EE_Error
835
-     * @throws InvalidArgumentException
836
-     * @throws InvalidDataTypeException
837
-     * @throws InvalidInterfaceException
838
-     * @throws ReflectionException
839
-     */
840
-    public function add_child_line_item(EEI_Line_Item $line_item, $set_order = true)
841
-    {
842
-        // should we calculate the LIN_order for this line item ?
843
-        if ($set_order || $line_item->order() === null) {
844
-            $line_item->set_order(count($this->children()));
845
-        }
846
-        if ($this->ID()) {
847
-            // check for any duplicate line items (with the same code), if so, this replaces it
848
-            $line_item_with_same_code = $this->get_child_line_item($line_item->code());
849
-            if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) {
850
-                $this->delete_child_line_item($line_item_with_same_code->code());
851
-            }
852
-            $line_item->set_parent_ID($this->ID());
853
-            if ($this->TXN_ID()) {
854
-                $line_item->set_TXN_ID($this->TXN_ID());
855
-            }
856
-            return $line_item->save();
857
-        }
858
-        $this->_children[ $line_item->code() ] = $line_item;
859
-        if ($line_item->parent() !== $this) {
860
-            $line_item->set_parent($this);
861
-        }
862
-        return true;
863
-    }
864
-
865
-
866
-    /**
867
-     * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation.
868
-     * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save()
869
-     * However, if this line item is NOT saved to the DB, this just caches the parent on
870
-     * the EE_Line_Item::_parent property.
871
-     *
872
-     * @param EE_Line_Item $line_item
873
-     * @throws EE_Error
874
-     * @throws InvalidArgumentException
875
-     * @throws InvalidDataTypeException
876
-     * @throws InvalidInterfaceException
877
-     * @throws ReflectionException
878
-     */
879
-    public function set_parent($line_item)
880
-    {
881
-        if ($this->ID()) {
882
-            if (! $line_item->ID()) {
883
-                $line_item->save();
884
-            }
885
-            $this->set_parent_ID($line_item->ID());
886
-            $this->save();
887
-        } else {
888
-            $this->_parent = $line_item;
889
-            $this->set_parent_ID($line_item->ID());
890
-        }
891
-    }
892
-
893
-
894
-    /**
895
-     * Gets the child line item as specified by its code. Because this returns an object (by reference)
896
-     * you can modify this child line item and the parent (this object) can know about them
897
-     * because it also has a reference to that line item
898
-     *
899
-     * @param string $code
900
-     * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
901
-     * @throws EE_Error
902
-     * @throws InvalidArgumentException
903
-     * @throws InvalidDataTypeException
904
-     * @throws InvalidInterfaceException
905
-     * @throws ReflectionException
906
-     */
907
-    public function get_child_line_item($code)
908
-    {
909
-        if ($this->ID()) {
910
-            return $this->get_model()->get_one(
911
-                array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code))
912
-            );
913
-        }
914
-        return isset($this->_children[ $code ])
915
-            ? $this->_children[ $code ]
916
-            : null;
917
-    }
918
-
919
-
920
-    /**
921
-     * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD
922
-     * cached on it)
923
-     *
924
-     * @return int
925
-     * @throws EE_Error
926
-     * @throws InvalidArgumentException
927
-     * @throws InvalidDataTypeException
928
-     * @throws InvalidInterfaceException
929
-     * @throws ReflectionException
930
-     */
931
-    public function delete_children_line_items()
932
-    {
933
-        if ($this->ID()) {
934
-            return $this->get_model()->delete(array(array('LIN_parent' => $this->ID())));
935
-        }
936
-        $count = count($this->_children);
937
-        $this->_children = array();
938
-        return $count;
939
-    }
940
-
941
-
942
-    /**
943
-     * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line
944
-     * HAS NOT been saved to the DB, removes the child line item with index $code.
945
-     * Also searches through the child's children for a matching line item. However, once a line item has been found
946
-     * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be
947
-     * deleted)
948
-     *
949
-     * @param string $code
950
-     * @param bool   $stop_search_once_found
951
-     * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to
952
-     *             the DB yet)
953
-     * @throws EE_Error
954
-     * @throws InvalidArgumentException
955
-     * @throws InvalidDataTypeException
956
-     * @throws InvalidInterfaceException
957
-     * @throws ReflectionException
958
-     */
959
-    public function delete_child_line_item($code, $stop_search_once_found = true)
960
-    {
961
-        if ($this->ID()) {
962
-            $items_deleted = 0;
963
-            if ($this->code() === $code) {
964
-                $items_deleted += EEH_Line_Item::delete_all_child_items($this);
965
-                $items_deleted += (int) $this->delete();
966
-                if ($stop_search_once_found) {
967
-                    return $items_deleted;
968
-                }
969
-            }
970
-            foreach ($this->children() as $child_line_item) {
971
-                $items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found);
972
-            }
973
-            return $items_deleted;
974
-        }
975
-        if (isset($this->_children[ $code ])) {
976
-            unset($this->_children[ $code ]);
977
-            return 1;
978
-        }
979
-        return 0;
980
-    }
981
-
982
-
983
-    /**
984
-     * If this line item is in the database, is of the type subtotal, and
985
-     * has no children, why do we have it? It should be deleted so this function
986
-     * does that
987
-     *
988
-     * @return boolean
989
-     * @throws EE_Error
990
-     * @throws InvalidArgumentException
991
-     * @throws InvalidDataTypeException
992
-     * @throws InvalidInterfaceException
993
-     * @throws ReflectionException
994
-     */
995
-    public function delete_if_childless_subtotal()
996
-    {
997
-        if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) {
998
-            return $this->delete();
999
-        }
1000
-        return false;
1001
-    }
1002
-
1003
-
1004
-    /**
1005
-     * Creates a code and returns a string. doesn't assign the code to this model object
1006
-     *
1007
-     * @return string
1008
-     * @throws EE_Error
1009
-     * @throws InvalidArgumentException
1010
-     * @throws InvalidDataTypeException
1011
-     * @throws InvalidInterfaceException
1012
-     * @throws ReflectionException
1013
-     */
1014
-    public function generate_code()
1015
-    {
1016
-        // each line item in the cart requires a unique identifier
1017
-        return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime());
1018
-    }
1019
-
1020
-
1021
-    /**
1022
-     * @return bool
1023
-     * @throws EE_Error
1024
-     * @throws InvalidArgumentException
1025
-     * @throws InvalidDataTypeException
1026
-     * @throws InvalidInterfaceException
1027
-     * @throws ReflectionException
1028
-     */
1029
-    public function is_tax()
1030
-    {
1031
-        return $this->type() === EEM_Line_Item::type_tax;
1032
-    }
1033
-
1034
-
1035
-    /**
1036
-     * @return bool
1037
-     * @throws EE_Error
1038
-     * @throws InvalidArgumentException
1039
-     * @throws InvalidDataTypeException
1040
-     * @throws InvalidInterfaceException
1041
-     * @throws ReflectionException
1042
-     */
1043
-    public function is_tax_sub_total()
1044
-    {
1045
-        return $this->type() === EEM_Line_Item::type_tax_sub_total;
1046
-    }
1047
-
1048
-
1049
-    /**
1050
-     * @return bool
1051
-     * @throws EE_Error
1052
-     * @throws InvalidArgumentException
1053
-     * @throws InvalidDataTypeException
1054
-     * @throws InvalidInterfaceException
1055
-     * @throws ReflectionException
1056
-     */
1057
-    public function is_line_item()
1058
-    {
1059
-        return $this->type() === EEM_Line_Item::type_line_item;
1060
-    }
1061
-
1062
-
1063
-    /**
1064
-     * @return bool
1065
-     * @throws EE_Error
1066
-     * @throws InvalidArgumentException
1067
-     * @throws InvalidDataTypeException
1068
-     * @throws InvalidInterfaceException
1069
-     * @throws ReflectionException
1070
-     */
1071
-    public function is_sub_line_item()
1072
-    {
1073
-        return $this->type() === EEM_Line_Item::type_sub_line_item;
1074
-    }
1075
-
1076
-
1077
-    /**
1078
-     * @return bool
1079
-     * @throws EE_Error
1080
-     * @throws InvalidArgumentException
1081
-     * @throws InvalidDataTypeException
1082
-     * @throws InvalidInterfaceException
1083
-     * @throws ReflectionException
1084
-     */
1085
-    public function is_sub_total()
1086
-    {
1087
-        return $this->type() === EEM_Line_Item::type_sub_total;
1088
-    }
1089
-
1090
-
1091
-    /**
1092
-     * Whether or not this line item is a cancellation line item
1093
-     *
1094
-     * @return boolean
1095
-     * @throws EE_Error
1096
-     * @throws InvalidArgumentException
1097
-     * @throws InvalidDataTypeException
1098
-     * @throws InvalidInterfaceException
1099
-     * @throws ReflectionException
1100
-     */
1101
-    public function is_cancellation()
1102
-    {
1103
-        return EEM_Line_Item::type_cancellation === $this->type();
1104
-    }
1105
-
1106
-
1107
-    /**
1108
-     * @return bool
1109
-     * @throws EE_Error
1110
-     * @throws InvalidArgumentException
1111
-     * @throws InvalidDataTypeException
1112
-     * @throws InvalidInterfaceException
1113
-     * @throws ReflectionException
1114
-     */
1115
-    public function is_total()
1116
-    {
1117
-        return $this->type() === EEM_Line_Item::type_total;
1118
-    }
1119
-
1120
-
1121
-    /**
1122
-     * @return bool
1123
-     * @throws EE_Error
1124
-     * @throws InvalidArgumentException
1125
-     * @throws InvalidDataTypeException
1126
-     * @throws InvalidInterfaceException
1127
-     * @throws ReflectionException
1128
-     */
1129
-    public function is_cancelled()
1130
-    {
1131
-        return $this->type() === EEM_Line_Item::type_cancellation;
1132
-    }
1133
-
1134
-
1135
-    /**
1136
-     * @return string like '2, 004.00', formatted according to the localized currency
1137
-     * @throws EE_Error
1138
-     * @throws InvalidArgumentException
1139
-     * @throws InvalidDataTypeException
1140
-     * @throws InvalidInterfaceException
1141
-     * @throws ReflectionException
1142
-     */
1143
-    public function unit_price_no_code()
1144
-    {
1145
-        return $this->get_pretty('LIN_unit_price', 'no_currency_code');
1146
-    }
1147
-
1148
-
1149
-    /**
1150
-     * @return string like '2, 004.00', formatted according to the localized currency
1151
-     * @throws EE_Error
1152
-     * @throws InvalidArgumentException
1153
-     * @throws InvalidDataTypeException
1154
-     * @throws InvalidInterfaceException
1155
-     * @throws ReflectionException
1156
-     */
1157
-    public function total_no_code()
1158
-    {
1159
-        return $this->get_pretty('LIN_total', 'no_currency_code');
1160
-    }
1161
-
1162
-
1163
-    /**
1164
-     * Gets the final total on this item, taking taxes into account.
1165
-     * Has the side-effect of setting the sub-total as it was just calculated.
1166
-     * If this is used on a grand-total line item, also updates the transaction's
1167
-     * TXN_total (provided this line item is allowed to persist, otherwise we don't
1168
-     * want to change a persistable transaction with info from a non-persistent line item)
1169
-     *
1170
-     * @param bool $update_txn_status
1171
-     * @return float
1172
-     * @throws EE_Error
1173
-     * @throws InvalidArgumentException
1174
-     * @throws InvalidDataTypeException
1175
-     * @throws InvalidInterfaceException
1176
-     * @throws ReflectionException
1177
-     * @throws RuntimeException
1178
-     */
1179
-    public function recalculate_total_including_taxes($update_txn_status = false)
1180
-    {
1181
-        $pre_tax_total = $this->recalculate_pre_tax_total();
1182
-        $tax_total = $this->recalculate_taxes_and_tax_total();
1183
-        $total = $pre_tax_total + $tax_total;
1184
-        // no negative totals plz
1185
-        $total = max($total, 0);
1186
-        $this->set_total($total);
1187
-        // only update the related transaction's total
1188
-        // if we intend to save this line item and its a grand total
1189
-        if (
1190
-            $this->allow_persist() && $this->type() === EEM_Line_Item::type_total
1191
-            && $this->transaction()
1192
-               instanceof
1193
-               EE_Transaction
1194
-        ) {
1195
-            $this->transaction()->set_total($total);
1196
-            if ($update_txn_status) {
1197
-                // don't save the TXN because that will be done below
1198
-                // and the following method only saves if the status changes
1199
-                $this->transaction()->update_status_based_on_total_paid(false);
1200
-            }
1201
-            if ($this->transaction()->ID()) {
1202
-                $this->transaction()->save();
1203
-            }
1204
-        }
1205
-        $this->maybe_save();
1206
-        return $total;
1207
-    }
1208
-
1209
-
1210
-    /**
1211
-     * Recursively goes through all the children and recalculates sub-totals EXCEPT for
1212
-     * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its
1213
-     * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
1214
-     * when this is called on the grand total
1215
-     *
1216
-     * @return float
1217
-     * @throws EE_Error
1218
-     * @throws InvalidArgumentException
1219
-     * @throws InvalidDataTypeException
1220
-     * @throws InvalidInterfaceException
1221
-     * @throws ReflectionException
1222
-     */
1223
-    public function recalculate_pre_tax_total()
1224
-    {
1225
-        $total = 0;
1226
-        $my_children = $this->children();
1227
-        $has_children = ! empty($my_children);
1228
-        if ($has_children && $this->is_line_item()) {
1229
-            $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children);
1230
-        } elseif (! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) {
1231
-            $total = $this->unit_price() * $this->quantity();
1232
-        } elseif ($this->is_sub_total() || $this->is_total()) {
1233
-            $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children);
1234
-        } elseif ($this->is_tax_sub_total() || $this->is_tax() || $this->is_cancelled()) {
1235
-            // completely ignore tax totals, tax sub-totals, and cancelled line items, when calculating the pre-tax-total
1236
-            return 0;
1237
-        }
1238
-        // ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events)
1239
-        if (
1240
-            ! $this->is_line_item() && ! $this->is_sub_line_item() && ! $this->is_cancellation()
1241
-        ) {
1242
-            if ($this->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_EVENT) {
1243
-                $this->set_quantity(1);
1244
-            }
1245
-            if (! $this->is_percent()) {
1246
-                $this->set_unit_price($total);
1247
-            }
1248
-        }
1249
-        // we don't want to bother saving grand totals, because that needs to factor in taxes anyways
1250
-        // so it ought to be
1251
-        if (! $this->is_total()) {
1252
-            $this->set_total($total);
1253
-            // if not a percent line item, make sure we keep the unit price in sync
1254
-            if (
1255
-                $has_children
1256
-                && $this->is_line_item()
1257
-                && ! $this->is_percent()
1258
-            ) {
1259
-                if ($this->quantity() === 0) {
1260
-                    $new_unit_price = 0;
1261
-                } else {
1262
-                    $new_unit_price = $this->total() / $this->quantity();
1263
-                }
1264
-                $this->set_unit_price($new_unit_price);
1265
-            }
1266
-            $this->maybe_save();
1267
-        }
1268
-        return $total;
1269
-    }
1270
-
1271
-
1272
-    /**
1273
-     * Calculates the pretax total when this line item is a subtotal or total line item.
1274
-     * Basically does a sum-then-round approach (ie, any percent line item that are children
1275
-     * will calculate their total based on the un-rounded total we're working with so far, and
1276
-     * THEN round the result; instead of rounding as we go like with sub-line-items)
1277
-     *
1278
-     * @param float          $calculated_total_so_far
1279
-     * @param EE_Line_Item[] $my_children
1280
-     * @return float
1281
-     * @throws EE_Error
1282
-     * @throws InvalidArgumentException
1283
-     * @throws InvalidDataTypeException
1284
-     * @throws InvalidInterfaceException
1285
-     * @throws ReflectionException
1286
-     */
1287
-    protected function _recalculate_pretax_total_for_subtotal($calculated_total_so_far, $my_children = null)
1288
-    {
1289
-        if ($my_children === null) {
1290
-            $my_children = $this->children();
1291
-        }
1292
-        $subtotal_quantity = 0;
1293
-        // get the total of all its children
1294
-        foreach ($my_children as $child_line_item) {
1295
-            if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) {
1296
-                // percentage line items are based on total so far
1297
-                if ($child_line_item->is_percent()) {
1298
-                    // round as we go so that the line items add up ok
1299
-                    $percent_total = round(
1300
-                        $calculated_total_so_far * $child_line_item->percent() / 100,
1301
-                        EE_Registry::instance()->CFG->currency->dec_plc
1302
-                    );
1303
-                    $child_line_item->set_total($percent_total);
1304
-                    // so far all percent line items should have a quantity of 1
1305
-                    // (ie, no double percent discounts. Although that might be requested someday)
1306
-                    $child_line_item->set_quantity(1);
1307
-                    $child_line_item->maybe_save();
1308
-                    $calculated_total_so_far += $percent_total;
1309
-                } else {
1310
-                    // verify flat sub-line-item quantities match their parent
1311
-                    if ($child_line_item->is_sub_line_item()) {
1312
-                        $child_line_item->set_quantity($this->quantity());
1313
-                    }
1314
-                    $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total();
1315
-                    $subtotal_quantity += $child_line_item->quantity();
1316
-                }
1317
-            }
1318
-        }
1319
-        if ($this->is_sub_total()) {
1320
-            // no negative totals plz
1321
-            $calculated_total_so_far = max($calculated_total_so_far, 0);
1322
-            $subtotal_quantity = $subtotal_quantity > 0 ? 1 : 0;
1323
-            $this->set_quantity($subtotal_quantity);
1324
-            $this->maybe_save();
1325
-        }
1326
-        return $calculated_total_so_far;
1327
-    }
1328
-
1329
-
1330
-    /**
1331
-     * Calculates the pretax total for a normal line item, in a round-then-sum approach
1332
-     * (where each sub-line-item is applied to the base price for the line item
1333
-     * and the result is immediately rounded, rather than summing all the sub-line-items
1334
-     * then rounding, like we do when recalculating pretax totals on totals and subtotals).
1335
-     *
1336
-     * @param float          $calculated_total_so_far
1337
-     * @param EE_Line_Item[] $my_children
1338
-     * @return float
1339
-     * @throws EE_Error
1340
-     * @throws InvalidArgumentException
1341
-     * @throws InvalidDataTypeException
1342
-     * @throws InvalidInterfaceException
1343
-     * @throws ReflectionException
1344
-     */
1345
-    protected function _recalculate_pretax_total_for_line_item($calculated_total_so_far, $my_children = null)
1346
-    {
1347
-        if ($my_children === null) {
1348
-            $my_children = $this->children();
1349
-        }
1350
-        // we need to keep track of the running total for a single item,
1351
-        // because we need to round as we go
1352
-        $unit_price_for_total = 0;
1353
-        $quantity_for_total = 1;
1354
-        // get the total of all its children
1355
-        foreach ($my_children as $child_line_item) {
1356
-            if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) {
1357
-                if ($child_line_item->is_percent()) {
1358
-                    // it should be the unit-price-so-far multiplied by teh percent multiplied by the quantity
1359
-                    // not total multiplied by percent, because that ignores rounding along-the-way
1360
-                    $percent_unit_price = round(
1361
-                        $unit_price_for_total * $child_line_item->percent() / 100,
1362
-                        EE_Registry::instance()->CFG->currency->dec_plc
1363
-                    );
1364
-                    $percent_total = $percent_unit_price * $quantity_for_total;
1365
-                    $child_line_item->set_total($percent_total);
1366
-                    // so far all percent line items should have a quantity of 1
1367
-                    // (ie, no double percent discounts. Although that might be requested someday)
1368
-                    $child_line_item->set_quantity(1);
1369
-                    $child_line_item->maybe_save();
1370
-                    $calculated_total_so_far += $percent_total;
1371
-                    $unit_price_for_total += $percent_unit_price;
1372
-                } else {
1373
-                    // verify flat sub-line-item quantities match their parent
1374
-                    if ($child_line_item->is_sub_line_item()) {
1375
-                        $child_line_item->set_quantity($this->quantity());
1376
-                    }
1377
-                    $quantity_for_total = $child_line_item->quantity();
1378
-                    $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total();
1379
-                    $unit_price_for_total += $child_line_item->unit_price();
1380
-                }
1381
-            }
1382
-        }
1383
-        return $calculated_total_so_far;
1384
-    }
1385
-
1386
-
1387
-    /**
1388
-     * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
1389
-     * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
1390
-     * and tax sub-total if already in the DB
1391
-     *
1392
-     * @return float
1393
-     * @throws EE_Error
1394
-     * @throws InvalidArgumentException
1395
-     * @throws InvalidDataTypeException
1396
-     * @throws InvalidInterfaceException
1397
-     * @throws ReflectionException
1398
-     */
1399
-    public function recalculate_taxes_and_tax_total()
1400
-    {
1401
-        // get all taxes
1402
-        $taxes = $this->tax_descendants();
1403
-        // calculate the pretax total
1404
-        $taxable_total = $this->taxable_total();
1405
-        $tax_total = 0;
1406
-        foreach ($taxes as $tax) {
1407
-            $total_on_this_tax = $taxable_total * $tax->percent() / 100;
1408
-            // remember the total on this line item
1409
-            $tax->set_total($total_on_this_tax);
1410
-            $tax->maybe_save();
1411
-            $tax_total += $tax->total();
1412
-        }
1413
-        $this->_recalculate_tax_sub_total();
1414
-        return $tax_total;
1415
-    }
1416
-
1417
-
1418
-    /**
1419
-     * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated
1420
-     *
1421
-     * @return void
1422
-     * @throws EE_Error
1423
-     * @throws InvalidArgumentException
1424
-     * @throws InvalidDataTypeException
1425
-     * @throws InvalidInterfaceException
1426
-     * @throws ReflectionException
1427
-     */
1428
-    private function _recalculate_tax_sub_total()
1429
-    {
1430
-        if ($this->is_tax_sub_total()) {
1431
-            $total = 0;
1432
-            $total_percent = 0;
1433
-            // simply loop through all its children (which should be taxes) and sum their total
1434
-            foreach ($this->children() as $child_tax) {
1435
-                if ($child_tax instanceof EE_Line_Item) {
1436
-                    $total += $child_tax->total();
1437
-                    $total_percent += $child_tax->percent();
1438
-                }
1439
-            }
1440
-            $this->set_total($total);
1441
-            $this->set_percent($total_percent);
1442
-            $this->maybe_save();
1443
-        } elseif ($this->is_total()) {
1444
-            foreach ($this->children() as $maybe_tax_subtotal) {
1445
-                if ($maybe_tax_subtotal instanceof EE_Line_Item) {
1446
-                    $maybe_tax_subtotal->_recalculate_tax_sub_total();
1447
-                }
1448
-            }
1449
-        }
1450
-    }
1451
-
1452
-
1453
-    /**
1454
-     * Gets the total tax on this line item. Assumes taxes have already been calculated using
1455
-     * recalculate_taxes_and_total
1456
-     *
1457
-     * @return float
1458
-     * @throws EE_Error
1459
-     * @throws InvalidArgumentException
1460
-     * @throws InvalidDataTypeException
1461
-     * @throws InvalidInterfaceException
1462
-     * @throws ReflectionException
1463
-     */
1464
-    public function get_total_tax()
1465
-    {
1466
-        $this->_recalculate_tax_sub_total();
1467
-        $total = 0;
1468
-        foreach ($this->tax_descendants() as $tax_line_item) {
1469
-            if ($tax_line_item instanceof EE_Line_Item) {
1470
-                $total += $tax_line_item->total();
1471
-            }
1472
-        }
1473
-        return $total;
1474
-    }
1475
-
1476
-
1477
-    /**
1478
-     * Gets the total for all the items purchased only
1479
-     *
1480
-     * @return float
1481
-     * @throws EE_Error
1482
-     * @throws InvalidArgumentException
1483
-     * @throws InvalidDataTypeException
1484
-     * @throws InvalidInterfaceException
1485
-     * @throws ReflectionException
1486
-     */
1487
-    public function get_items_total()
1488
-    {
1489
-        // by default, let's make sure we're consistent with the existing line item
1490
-        if ($this->is_total()) {
1491
-            $pretax_subtotal_li = EEH_Line_Item::get_pre_tax_subtotal($this);
1492
-            if ($pretax_subtotal_li instanceof EE_Line_Item) {
1493
-                return $pretax_subtotal_li->total();
1494
-            }
1495
-        }
1496
-        $total = 0;
1497
-        foreach ($this->get_items() as $item) {
1498
-            if ($item instanceof EE_Line_Item) {
1499
-                $total += $item->total();
1500
-            }
1501
-        }
1502
-        return $total;
1503
-    }
1504
-
1505
-
1506
-    /**
1507
-     * Gets all the descendants (ie, children or children of children etc) that
1508
-     * are of the type 'tax'
1509
-     *
1510
-     * @return EE_Line_Item[]
1511
-     * @throws EE_Error
1512
-     */
1513
-    public function tax_descendants()
1514
-    {
1515
-        return EEH_Line_Item::get_tax_descendants($this);
1516
-    }
1517
-
1518
-
1519
-    /**
1520
-     * Gets all the real items purchased which are children of this item
1521
-     *
1522
-     * @return EE_Line_Item[]
1523
-     * @throws EE_Error
1524
-     */
1525
-    public function get_items()
1526
-    {
1527
-        return EEH_Line_Item::get_line_item_descendants($this);
1528
-    }
1529
-
1530
-
1531
-    /**
1532
-     * Returns the amount taxable among this line item's children (or if it has no children,
1533
-     * how much of it is taxable). Does not recalculate totals or subtotals.
1534
-     * If the taxable total is negative, (eg, if none of the tickets were taxable,
1535
-     * but there is a "Taxable" discount), returns 0.
1536
-     *
1537
-     * @return float
1538
-     * @throws EE_Error
1539
-     * @throws InvalidArgumentException
1540
-     * @throws InvalidDataTypeException
1541
-     * @throws InvalidInterfaceException
1542
-     * @throws ReflectionException
1543
-     */
1544
-    public function taxable_total()
1545
-    {
1546
-        $total = 0;
1547
-        if ($this->children()) {
1548
-            foreach ($this->children() as $child_line_item) {
1549
-                if ($child_line_item->type() === EEM_Line_Item::type_line_item && $child_line_item->is_taxable()) {
1550
-                    // if it's a percent item, only take into account the percent
1551
-                    // that's taxable too (the taxable total so far)
1552
-                    if ($child_line_item->is_percent()) {
1553
-                        $total += ($total * $child_line_item->percent() / 100);
1554
-                    } else {
1555
-                        $total += $child_line_item->total();
1556
-                    }
1557
-                } elseif ($child_line_item->type() === EEM_Line_Item::type_sub_total) {
1558
-                    $total += $child_line_item->taxable_total();
1559
-                }
1560
-            }
1561
-        }
1562
-        return max($total, 0);
1563
-    }
1564
-
1565
-
1566
-    /**
1567
-     * Gets the transaction for this line item
1568
-     *
1569
-     * @return EE_Base_Class|EE_Transaction
1570
-     * @throws EE_Error
1571
-     * @throws InvalidArgumentException
1572
-     * @throws InvalidDataTypeException
1573
-     * @throws InvalidInterfaceException
1574
-     * @throws ReflectionException
1575
-     */
1576
-    public function transaction()
1577
-    {
1578
-        return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TRANSACTION);
1579
-    }
1580
-
1581
-
1582
-    /**
1583
-     * Saves this line item to the DB, and recursively saves its descendants.
1584
-     * Because there currently is no proper parent-child relation on the model,
1585
-     * save_this_and_cached() will NOT save the descendants.
1586
-     * Also sets the transaction on this line item and all its descendants before saving
1587
-     *
1588
-     * @param int $txn_id if none is provided, assumes $this->TXN_ID()
1589
-     * @return int count of items saved
1590
-     * @throws EE_Error
1591
-     * @throws InvalidArgumentException
1592
-     * @throws InvalidDataTypeException
1593
-     * @throws InvalidInterfaceException
1594
-     * @throws ReflectionException
1595
-     */
1596
-    public function save_this_and_descendants_to_txn($txn_id = null)
1597
-    {
1598
-        $count = 0;
1599
-        if (! $txn_id) {
1600
-            $txn_id = $this->TXN_ID();
1601
-        }
1602
-        $this->set_TXN_ID($txn_id);
1603
-        $children = $this->children();
1604
-        $count += $this->save()
1605
-            ? 1
1606
-            : 0;
1607
-        foreach ($children as $child_line_item) {
1608
-            if ($child_line_item instanceof EE_Line_Item) {
1609
-                $child_line_item->set_parent_ID($this->ID());
1610
-                $count += $child_line_item->save_this_and_descendants_to_txn($txn_id);
1611
-            }
1612
-        }
1613
-        return $count;
1614
-    }
1615
-
1616
-
1617
-    /**
1618
-     * Saves this line item to the DB, and recursively saves its descendants.
1619
-     *
1620
-     * @return int count of items saved
1621
-     * @throws EE_Error
1622
-     * @throws InvalidArgumentException
1623
-     * @throws InvalidDataTypeException
1624
-     * @throws InvalidInterfaceException
1625
-     * @throws ReflectionException
1626
-     */
1627
-    public function save_this_and_descendants()
1628
-    {
1629
-        $count = 0;
1630
-        $children = $this->children();
1631
-        $count += $this->save()
1632
-            ? 1
1633
-            : 0;
1634
-        foreach ($children as $child_line_item) {
1635
-            if ($child_line_item instanceof EE_Line_Item) {
1636
-                $child_line_item->set_parent_ID($this->ID());
1637
-                $count += $child_line_item->save_this_and_descendants();
1638
-            }
1639
-        }
1640
-        return $count;
1641
-    }
1642
-
1643
-
1644
-    /**
1645
-     * returns the cancellation line item if this item was cancelled
1646
-     *
1647
-     * @return EE_Line_Item[]
1648
-     * @throws InvalidArgumentException
1649
-     * @throws InvalidInterfaceException
1650
-     * @throws InvalidDataTypeException
1651
-     * @throws ReflectionException
1652
-     * @throws EE_Error
1653
-     */
1654
-    public function get_cancellations()
1655
-    {
1656
-        EE_Registry::instance()->load_helper('Line_Item');
1657
-        return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation);
1658
-    }
1659
-
1660
-
1661
-    /**
1662
-     * If this item has an ID, then this saves it again to update the db
1663
-     *
1664
-     * @return int count of items saved
1665
-     * @throws EE_Error
1666
-     * @throws InvalidArgumentException
1667
-     * @throws InvalidDataTypeException
1668
-     * @throws InvalidInterfaceException
1669
-     * @throws ReflectionException
1670
-     */
1671
-    public function maybe_save()
1672
-    {
1673
-        if ($this->ID()) {
1674
-            return $this->save();
1675
-        }
1676
-        return false;
1677
-    }
1678
-
1679
-
1680
-    /**
1681
-     * clears the cached children and parent from the line item
1682
-     *
1683
-     * @return void
1684
-     */
1685
-    public function clear_related_line_item_cache()
1686
-    {
1687
-        $this->_children = array();
1688
-        $this->_parent = null;
1689
-    }
1690
-
1691
-
1692
-    /**
1693
-     * @param bool $raw
1694
-     * @return int
1695
-     * @throws EE_Error
1696
-     * @throws InvalidArgumentException
1697
-     * @throws InvalidDataTypeException
1698
-     * @throws InvalidInterfaceException
1699
-     * @throws ReflectionException
1700
-     */
1701
-    public function timestamp($raw = false)
1702
-    {
1703
-        return $raw
1704
-            ? $this->get_raw('LIN_timestamp')
1705
-            : $this->get('LIN_timestamp');
1706
-    }
1707
-
1708
-
1709
-
1710
-
1711
-    /************************* DEPRECATED *************************/
1712
-    /**
1713
-     * @deprecated 4.6.0
1714
-     * @param string $type one of the constants on EEM_Line_Item
1715
-     * @return EE_Line_Item[]
1716
-     * @throws EE_Error
1717
-     */
1718
-    protected function _get_descendants_of_type($type)
1719
-    {
1720
-        EE_Error::doing_it_wrong(
1721
-            'EE_Line_Item::_get_descendants_of_type()',
1722
-            sprintf(
1723
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
1724
-                'EEH_Line_Item::get_descendants_of_type()'
1725
-            ),
1726
-            '4.6.0'
1727
-        );
1728
-        return EEH_Line_Item::get_descendants_of_type($this, $type);
1729
-    }
1730
-
1731
-
1732
-    /**
1733
-     * @deprecated 4.6.0
1734
-     * @param string $type like one of the EEM_Line_Item::type_*
1735
-     * @return EE_Line_Item
1736
-     * @throws EE_Error
1737
-     * @throws InvalidArgumentException
1738
-     * @throws InvalidDataTypeException
1739
-     * @throws InvalidInterfaceException
1740
-     * @throws ReflectionException
1741
-     */
1742
-    public function get_nearest_descendant_of_type($type)
1743
-    {
1744
-        EE_Error::doing_it_wrong(
1745
-            'EE_Line_Item::get_nearest_descendant_of_type()',
1746
-            sprintf(
1747
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
1748
-                'EEH_Line_Item::get_nearest_descendant_of_type()'
1749
-            ),
1750
-            '4.6.0'
1751
-        );
1752
-        return EEH_Line_Item::get_nearest_descendant_of_type($this, $type);
1753
-    }
16
+	/**
17
+	 * for children line items (currently not a normal relation)
18
+	 *
19
+	 * @type EE_Line_Item[]
20
+	 */
21
+	protected $_children = array();
22
+
23
+	/**
24
+	 * for the parent line item
25
+	 *
26
+	 * @var EE_Line_Item
27
+	 */
28
+	protected $_parent;
29
+
30
+
31
+	/**
32
+	 * @param array  $props_n_values          incoming values
33
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
34
+	 *                                        used.)
35
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
36
+	 *                                        date_format and the second value is the time format
37
+	 * @return EE_Line_Item
38
+	 * @throws EE_Error
39
+	 * @throws InvalidArgumentException
40
+	 * @throws InvalidDataTypeException
41
+	 * @throws InvalidInterfaceException
42
+	 * @throws ReflectionException
43
+	 */
44
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
45
+	{
46
+		$has_object = parent::_check_for_object(
47
+			$props_n_values,
48
+			__CLASS__,
49
+			$timezone,
50
+			$date_formats
51
+		);
52
+		return $has_object
53
+			? $has_object
54
+			: new self($props_n_values, false, $timezone);
55
+	}
56
+
57
+
58
+	/**
59
+	 * @param array  $props_n_values  incoming values from the database
60
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
61
+	 *                                the website will be used.
62
+	 * @return EE_Line_Item
63
+	 * @throws EE_Error
64
+	 * @throws InvalidArgumentException
65
+	 * @throws InvalidDataTypeException
66
+	 * @throws InvalidInterfaceException
67
+	 * @throws ReflectionException
68
+	 */
69
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
70
+	{
71
+		return new self($props_n_values, true, $timezone);
72
+	}
73
+
74
+
75
+	/**
76
+	 * Adds some defaults if they're not specified
77
+	 *
78
+	 * @param array  $fieldValues
79
+	 * @param bool   $bydb
80
+	 * @param string $timezone
81
+	 * @throws EE_Error
82
+	 * @throws InvalidArgumentException
83
+	 * @throws InvalidDataTypeException
84
+	 * @throws InvalidInterfaceException
85
+	 * @throws ReflectionException
86
+	 */
87
+	protected function __construct($fieldValues = array(), $bydb = false, $timezone = '')
88
+	{
89
+		parent::__construct($fieldValues, $bydb, $timezone);
90
+		if (! $this->get('LIN_code')) {
91
+			$this->set_code($this->generate_code());
92
+		}
93
+	}
94
+
95
+
96
+	/**
97
+	 * Gets ID
98
+	 *
99
+	 * @return int
100
+	 * @throws EE_Error
101
+	 * @throws InvalidArgumentException
102
+	 * @throws InvalidDataTypeException
103
+	 * @throws InvalidInterfaceException
104
+	 * @throws ReflectionException
105
+	 */
106
+	public function ID()
107
+	{
108
+		return $this->get('LIN_ID');
109
+	}
110
+
111
+
112
+	/**
113
+	 * Gets TXN_ID
114
+	 *
115
+	 * @return int
116
+	 * @throws EE_Error
117
+	 * @throws InvalidArgumentException
118
+	 * @throws InvalidDataTypeException
119
+	 * @throws InvalidInterfaceException
120
+	 * @throws ReflectionException
121
+	 */
122
+	public function TXN_ID()
123
+	{
124
+		return $this->get('TXN_ID');
125
+	}
126
+
127
+
128
+	/**
129
+	 * Sets TXN_ID
130
+	 *
131
+	 * @param int $TXN_ID
132
+	 * @throws EE_Error
133
+	 * @throws InvalidArgumentException
134
+	 * @throws InvalidDataTypeException
135
+	 * @throws InvalidInterfaceException
136
+	 * @throws ReflectionException
137
+	 */
138
+	public function set_TXN_ID($TXN_ID)
139
+	{
140
+		$this->set('TXN_ID', $TXN_ID);
141
+	}
142
+
143
+
144
+	/**
145
+	 * Gets name
146
+	 *
147
+	 * @return string
148
+	 * @throws EE_Error
149
+	 * @throws InvalidArgumentException
150
+	 * @throws InvalidDataTypeException
151
+	 * @throws InvalidInterfaceException
152
+	 * @throws ReflectionException
153
+	 */
154
+	public function name()
155
+	{
156
+		$name = $this->get('LIN_name');
157
+		if (! $name) {
158
+			$name = ucwords(str_replace('-', ' ', $this->type()));
159
+		}
160
+		return $name;
161
+	}
162
+
163
+
164
+	/**
165
+	 * Sets name
166
+	 *
167
+	 * @param string $name
168
+	 * @throws EE_Error
169
+	 * @throws InvalidArgumentException
170
+	 * @throws InvalidDataTypeException
171
+	 * @throws InvalidInterfaceException
172
+	 * @throws ReflectionException
173
+	 */
174
+	public function set_name($name)
175
+	{
176
+		$this->set('LIN_name', $name);
177
+	}
178
+
179
+
180
+	/**
181
+	 * Gets desc
182
+	 *
183
+	 * @return string
184
+	 * @throws EE_Error
185
+	 * @throws InvalidArgumentException
186
+	 * @throws InvalidDataTypeException
187
+	 * @throws InvalidInterfaceException
188
+	 * @throws ReflectionException
189
+	 */
190
+	public function desc()
191
+	{
192
+		return $this->get('LIN_desc');
193
+	}
194
+
195
+
196
+	/**
197
+	 * Sets desc
198
+	 *
199
+	 * @param string $desc
200
+	 * @throws EE_Error
201
+	 * @throws InvalidArgumentException
202
+	 * @throws InvalidDataTypeException
203
+	 * @throws InvalidInterfaceException
204
+	 * @throws ReflectionException
205
+	 */
206
+	public function set_desc($desc)
207
+	{
208
+		$this->set('LIN_desc', $desc);
209
+	}
210
+
211
+
212
+	/**
213
+	 * Gets quantity
214
+	 *
215
+	 * @return int
216
+	 * @throws EE_Error
217
+	 * @throws InvalidArgumentException
218
+	 * @throws InvalidDataTypeException
219
+	 * @throws InvalidInterfaceException
220
+	 * @throws ReflectionException
221
+	 */
222
+	public function quantity()
223
+	{
224
+		return $this->get('LIN_quantity');
225
+	}
226
+
227
+
228
+	/**
229
+	 * Sets quantity
230
+	 *
231
+	 * @param int $quantity
232
+	 * @throws EE_Error
233
+	 * @throws InvalidArgumentException
234
+	 * @throws InvalidDataTypeException
235
+	 * @throws InvalidInterfaceException
236
+	 * @throws ReflectionException
237
+	 */
238
+	public function set_quantity($quantity)
239
+	{
240
+		$this->set('LIN_quantity', max($quantity, 0));
241
+	}
242
+
243
+
244
+	/**
245
+	 * Gets item_id
246
+	 *
247
+	 * @return string
248
+	 * @throws EE_Error
249
+	 * @throws InvalidArgumentException
250
+	 * @throws InvalidDataTypeException
251
+	 * @throws InvalidInterfaceException
252
+	 * @throws ReflectionException
253
+	 */
254
+	public function OBJ_ID()
255
+	{
256
+		return $this->get('OBJ_ID');
257
+	}
258
+
259
+
260
+	/**
261
+	 * Sets item_id
262
+	 *
263
+	 * @param string $item_id
264
+	 * @throws EE_Error
265
+	 * @throws InvalidArgumentException
266
+	 * @throws InvalidDataTypeException
267
+	 * @throws InvalidInterfaceException
268
+	 * @throws ReflectionException
269
+	 */
270
+	public function set_OBJ_ID($item_id)
271
+	{
272
+		$this->set('OBJ_ID', $item_id);
273
+	}
274
+
275
+
276
+	/**
277
+	 * Gets item_type
278
+	 *
279
+	 * @return string
280
+	 * @throws EE_Error
281
+	 * @throws InvalidArgumentException
282
+	 * @throws InvalidDataTypeException
283
+	 * @throws InvalidInterfaceException
284
+	 * @throws ReflectionException
285
+	 */
286
+	public function OBJ_type()
287
+	{
288
+		return $this->get('OBJ_type');
289
+	}
290
+
291
+
292
+	/**
293
+	 * Gets item_type
294
+	 *
295
+	 * @return string
296
+	 * @throws EE_Error
297
+	 * @throws InvalidArgumentException
298
+	 * @throws InvalidDataTypeException
299
+	 * @throws InvalidInterfaceException
300
+	 * @throws ReflectionException
301
+	 */
302
+	public function OBJ_type_i18n()
303
+	{
304
+		$obj_type = $this->OBJ_type();
305
+		switch ($obj_type) {
306
+			case EEM_Line_Item::OBJ_TYPE_EVENT:
307
+				$obj_type = esc_html__('Event', 'event_espresso');
308
+				break;
309
+			case EEM_Line_Item::OBJ_TYPE_PRICE:
310
+				$obj_type = esc_html__('Price', 'event_espresso');
311
+				break;
312
+			case EEM_Line_Item::OBJ_TYPE_PROMOTION:
313
+				$obj_type = esc_html__('Promotion', 'event_espresso');
314
+				break;
315
+			case EEM_Line_Item::OBJ_TYPE_TICKET:
316
+				$obj_type = esc_html__('Ticket', 'event_espresso');
317
+				break;
318
+			case EEM_Line_Item::OBJ_TYPE_TRANSACTION:
319
+				$obj_type = esc_html__('Transaction', 'event_espresso');
320
+				break;
321
+		}
322
+		return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this);
323
+	}
324
+
325
+
326
+	/**
327
+	 * Sets item_type
328
+	 *
329
+	 * @param string $OBJ_type
330
+	 * @throws EE_Error
331
+	 * @throws InvalidArgumentException
332
+	 * @throws InvalidDataTypeException
333
+	 * @throws InvalidInterfaceException
334
+	 * @throws ReflectionException
335
+	 */
336
+	public function set_OBJ_type($OBJ_type)
337
+	{
338
+		$this->set('OBJ_type', $OBJ_type);
339
+	}
340
+
341
+
342
+	/**
343
+	 * Gets unit_price
344
+	 *
345
+	 * @return float
346
+	 * @throws EE_Error
347
+	 * @throws InvalidArgumentException
348
+	 * @throws InvalidDataTypeException
349
+	 * @throws InvalidInterfaceException
350
+	 * @throws ReflectionException
351
+	 */
352
+	public function unit_price()
353
+	{
354
+		return $this->get('LIN_unit_price');
355
+	}
356
+
357
+
358
+	/**
359
+	 * Sets unit_price
360
+	 *
361
+	 * @param float $unit_price
362
+	 * @throws EE_Error
363
+	 * @throws InvalidArgumentException
364
+	 * @throws InvalidDataTypeException
365
+	 * @throws InvalidInterfaceException
366
+	 * @throws ReflectionException
367
+	 */
368
+	public function set_unit_price($unit_price)
369
+	{
370
+		$this->set('LIN_unit_price', $unit_price);
371
+	}
372
+
373
+
374
+	/**
375
+	 * Checks if this item is a percentage modifier or not
376
+	 *
377
+	 * @return boolean
378
+	 * @throws EE_Error
379
+	 * @throws InvalidArgumentException
380
+	 * @throws InvalidDataTypeException
381
+	 * @throws InvalidInterfaceException
382
+	 * @throws ReflectionException
383
+	 */
384
+	public function is_percent()
385
+	{
386
+		if ($this->is_tax_sub_total()) {
387
+			// tax subtotals HAVE a percent on them, that percentage only applies
388
+			// to taxable items, so its' an exception. Treat it like a flat line item
389
+			return false;
390
+		}
391
+		$unit_price = abs($this->get('LIN_unit_price'));
392
+		$percent = abs($this->get('LIN_percent'));
393
+		if ($unit_price < .001 && $percent) {
394
+			return true;
395
+		}
396
+		if ($unit_price >= .001 && ! $percent) {
397
+			return false;
398
+		}
399
+		if ($unit_price >= .001 && $percent) {
400
+			throw new EE_Error(
401
+				sprintf(
402
+					esc_html__(
403
+						'A Line Item can not have a unit price of (%s) AND a percent (%s)!',
404
+						'event_espresso'
405
+					),
406
+					$unit_price,
407
+					$percent
408
+				)
409
+			);
410
+		}
411
+		// if they're both 0, assume its not a percent item
412
+		return false;
413
+	}
414
+
415
+
416
+	/**
417
+	 * Gets percent (between 100-.001)
418
+	 *
419
+	 * @return float
420
+	 * @throws EE_Error
421
+	 * @throws InvalidArgumentException
422
+	 * @throws InvalidDataTypeException
423
+	 * @throws InvalidInterfaceException
424
+	 * @throws ReflectionException
425
+	 */
426
+	public function percent()
427
+	{
428
+		return $this->get('LIN_percent');
429
+	}
430
+
431
+
432
+	/**
433
+	 * Sets percent (between 100-0.01)
434
+	 *
435
+	 * @param float $percent
436
+	 * @throws EE_Error
437
+	 * @throws InvalidArgumentException
438
+	 * @throws InvalidDataTypeException
439
+	 * @throws InvalidInterfaceException
440
+	 * @throws ReflectionException
441
+	 */
442
+	public function set_percent($percent)
443
+	{
444
+		$this->set('LIN_percent', $percent);
445
+	}
446
+
447
+
448
+	/**
449
+	 * Gets total
450
+	 *
451
+	 * @return float
452
+	 * @throws EE_Error
453
+	 * @throws InvalidArgumentException
454
+	 * @throws InvalidDataTypeException
455
+	 * @throws InvalidInterfaceException
456
+	 * @throws ReflectionException
457
+	 */
458
+	public function total()
459
+	{
460
+		return $this->get('LIN_total');
461
+	}
462
+
463
+
464
+	/**
465
+	 * Sets total
466
+	 *
467
+	 * @param float $total
468
+	 * @throws EE_Error
469
+	 * @throws InvalidArgumentException
470
+	 * @throws InvalidDataTypeException
471
+	 * @throws InvalidInterfaceException
472
+	 * @throws ReflectionException
473
+	 */
474
+	public function set_total($total)
475
+	{
476
+		$this->set('LIN_total', $total);
477
+	}
478
+
479
+
480
+	/**
481
+	 * Gets order
482
+	 *
483
+	 * @return int
484
+	 * @throws EE_Error
485
+	 * @throws InvalidArgumentException
486
+	 * @throws InvalidDataTypeException
487
+	 * @throws InvalidInterfaceException
488
+	 * @throws ReflectionException
489
+	 */
490
+	public function order()
491
+	{
492
+		return $this->get('LIN_order');
493
+	}
494
+
495
+
496
+	/**
497
+	 * Sets order
498
+	 *
499
+	 * @param int $order
500
+	 * @throws EE_Error
501
+	 * @throws InvalidArgumentException
502
+	 * @throws InvalidDataTypeException
503
+	 * @throws InvalidInterfaceException
504
+	 * @throws ReflectionException
505
+	 */
506
+	public function set_order($order)
507
+	{
508
+		$this->set('LIN_order', $order);
509
+	}
510
+
511
+
512
+	/**
513
+	 * Gets parent
514
+	 *
515
+	 * @return int
516
+	 * @throws EE_Error
517
+	 * @throws InvalidArgumentException
518
+	 * @throws InvalidDataTypeException
519
+	 * @throws InvalidInterfaceException
520
+	 * @throws ReflectionException
521
+	 */
522
+	public function parent_ID()
523
+	{
524
+		return $this->get('LIN_parent');
525
+	}
526
+
527
+
528
+	/**
529
+	 * Sets parent
530
+	 *
531
+	 * @param int $parent
532
+	 * @throws EE_Error
533
+	 * @throws InvalidArgumentException
534
+	 * @throws InvalidDataTypeException
535
+	 * @throws InvalidInterfaceException
536
+	 * @throws ReflectionException
537
+	 */
538
+	public function set_parent_ID($parent)
539
+	{
540
+		$this->set('LIN_parent', $parent);
541
+	}
542
+
543
+
544
+	/**
545
+	 * Gets type
546
+	 *
547
+	 * @return string
548
+	 * @throws EE_Error
549
+	 * @throws InvalidArgumentException
550
+	 * @throws InvalidDataTypeException
551
+	 * @throws InvalidInterfaceException
552
+	 * @throws ReflectionException
553
+	 */
554
+	public function type()
555
+	{
556
+		return $this->get('LIN_type');
557
+	}
558
+
559
+
560
+	/**
561
+	 * Sets type
562
+	 *
563
+	 * @param string $type
564
+	 * @throws EE_Error
565
+	 * @throws InvalidArgumentException
566
+	 * @throws InvalidDataTypeException
567
+	 * @throws InvalidInterfaceException
568
+	 * @throws ReflectionException
569
+	 */
570
+	public function set_type($type)
571
+	{
572
+		$this->set('LIN_type', $type);
573
+	}
574
+
575
+
576
+	/**
577
+	 * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\
578
+	 * 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
579
+	 * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()`
580
+	 * or indirectly by `EE_Line_item::add_child_line_item()`)
581
+	 *
582
+	 * @return EE_Base_Class|EE_Line_Item
583
+	 * @throws EE_Error
584
+	 * @throws InvalidArgumentException
585
+	 * @throws InvalidDataTypeException
586
+	 * @throws InvalidInterfaceException
587
+	 * @throws ReflectionException
588
+	 */
589
+	public function parent()
590
+	{
591
+		return $this->ID()
592
+			? $this->get_model()->get_one_by_ID($this->parent_ID())
593
+			: $this->_parent;
594
+	}
595
+
596
+
597
+	/**
598
+	 * Gets ALL the children of this line item (ie, all the parts that contribute towards this total).
599
+	 *
600
+	 * @return EE_Base_Class[]|EE_Line_Item[]
601
+	 * @throws EE_Error
602
+	 * @throws InvalidArgumentException
603
+	 * @throws InvalidDataTypeException
604
+	 * @throws InvalidInterfaceException
605
+	 * @throws ReflectionException
606
+	 */
607
+	public function children()
608
+	{
609
+		if ($this->ID()) {
610
+			return $this->get_model()->get_all(
611
+				array(
612
+					array('LIN_parent' => $this->ID()),
613
+					'order_by' => array('LIN_order' => 'ASC'),
614
+				)
615
+			);
616
+		}
617
+		if (! is_array($this->_children)) {
618
+			$this->_children = array();
619
+		}
620
+		return $this->_children;
621
+	}
622
+
623
+
624
+	/**
625
+	 * Gets code
626
+	 *
627
+	 * @return string
628
+	 * @throws EE_Error
629
+	 * @throws InvalidArgumentException
630
+	 * @throws InvalidDataTypeException
631
+	 * @throws InvalidInterfaceException
632
+	 * @throws ReflectionException
633
+	 */
634
+	public function code()
635
+	{
636
+		return $this->get('LIN_code');
637
+	}
638
+
639
+
640
+	/**
641
+	 * Sets code
642
+	 *
643
+	 * @param string $code
644
+	 * @throws EE_Error
645
+	 * @throws InvalidArgumentException
646
+	 * @throws InvalidDataTypeException
647
+	 * @throws InvalidInterfaceException
648
+	 * @throws ReflectionException
649
+	 */
650
+	public function set_code($code)
651
+	{
652
+		$this->set('LIN_code', $code);
653
+	}
654
+
655
+
656
+	/**
657
+	 * Gets is_taxable
658
+	 *
659
+	 * @return boolean
660
+	 * @throws EE_Error
661
+	 * @throws InvalidArgumentException
662
+	 * @throws InvalidDataTypeException
663
+	 * @throws InvalidInterfaceException
664
+	 * @throws ReflectionException
665
+	 */
666
+	public function is_taxable()
667
+	{
668
+		return $this->get('LIN_is_taxable');
669
+	}
670
+
671
+
672
+	/**
673
+	 * Sets is_taxable
674
+	 *
675
+	 * @param boolean $is_taxable
676
+	 * @throws EE_Error
677
+	 * @throws InvalidArgumentException
678
+	 * @throws InvalidDataTypeException
679
+	 * @throws InvalidInterfaceException
680
+	 * @throws ReflectionException
681
+	 */
682
+	public function set_is_taxable($is_taxable)
683
+	{
684
+		$this->set('LIN_is_taxable', $is_taxable);
685
+	}
686
+
687
+
688
+	/**
689
+	 * Gets the object that this model-joins-to.
690
+	 * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on
691
+	 * EEM_Promotion_Object
692
+	 *        Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object
693
+	 *
694
+	 * @return EE_Base_Class | NULL
695
+	 * @throws EE_Error
696
+	 * @throws InvalidArgumentException
697
+	 * @throws InvalidDataTypeException
698
+	 * @throws InvalidInterfaceException
699
+	 * @throws ReflectionException
700
+	 */
701
+	public function get_object()
702
+	{
703
+		$model_name_of_related_obj = $this->OBJ_type();
704
+		return $this->get_model()->has_relation($model_name_of_related_obj)
705
+			? $this->get_first_related($model_name_of_related_obj)
706
+			: null;
707
+	}
708
+
709
+
710
+	/**
711
+	 * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket.
712
+	 * (IE, if this line item is for a price or something else, will return NULL)
713
+	 *
714
+	 * @param array $query_params
715
+	 * @return EE_Base_Class|EE_Ticket
716
+	 * @throws EE_Error
717
+	 * @throws InvalidArgumentException
718
+	 * @throws InvalidDataTypeException
719
+	 * @throws InvalidInterfaceException
720
+	 * @throws ReflectionException
721
+	 */
722
+	public function ticket($query_params = array())
723
+	{
724
+		// we're going to assume that when this method is called
725
+		// we always want to receive the attached ticket EVEN if that ticket is archived.
726
+		// This can be overridden via the incoming $query_params argument
727
+		$remove_defaults = array('default_where_conditions' => 'none');
728
+		$query_params = array_merge($remove_defaults, $query_params);
729
+		return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TICKET, $query_params);
730
+	}
731
+
732
+
733
+	/**
734
+	 * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket
735
+	 *
736
+	 * @return EE_Datetime | NULL
737
+	 * @throws EE_Error
738
+	 * @throws InvalidArgumentException
739
+	 * @throws InvalidDataTypeException
740
+	 * @throws InvalidInterfaceException
741
+	 * @throws ReflectionException
742
+	 */
743
+	public function get_ticket_datetime()
744
+	{
745
+		if ($this->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
746
+			$ticket = $this->ticket();
747
+			if ($ticket instanceof EE_Ticket) {
748
+				$datetime = $ticket->first_datetime();
749
+				if ($datetime instanceof EE_Datetime) {
750
+					return $datetime;
751
+				}
752
+			}
753
+		}
754
+		return null;
755
+	}
756
+
757
+
758
+	/**
759
+	 * Gets the event's name that's related to the ticket, if this is for
760
+	 * a ticket
761
+	 *
762
+	 * @return string
763
+	 * @throws EE_Error
764
+	 * @throws InvalidArgumentException
765
+	 * @throws InvalidDataTypeException
766
+	 * @throws InvalidInterfaceException
767
+	 * @throws ReflectionException
768
+	 */
769
+	public function ticket_event_name()
770
+	{
771
+		$event_name = esc_html__('Unknown', 'event_espresso');
772
+		$event = $this->ticket_event();
773
+		if ($event instanceof EE_Event) {
774
+			$event_name = $event->name();
775
+		}
776
+		return $event_name;
777
+	}
778
+
779
+
780
+	/**
781
+	 * Gets the event that's related to the ticket, if this line item represents a ticket.
782
+	 *
783
+	 * @return EE_Event|null
784
+	 * @throws EE_Error
785
+	 * @throws InvalidArgumentException
786
+	 * @throws InvalidDataTypeException
787
+	 * @throws InvalidInterfaceException
788
+	 * @throws ReflectionException
789
+	 */
790
+	public function ticket_event()
791
+	{
792
+		$event = null;
793
+		$ticket = $this->ticket();
794
+		if ($ticket instanceof EE_Ticket) {
795
+			$datetime = $ticket->first_datetime();
796
+			if ($datetime instanceof EE_Datetime) {
797
+				$event = $datetime->event();
798
+			}
799
+		}
800
+		return $event;
801
+	}
802
+
803
+
804
+	/**
805
+	 * Gets the first datetime for this lien item, assuming it's for a ticket
806
+	 *
807
+	 * @param string $date_format
808
+	 * @param string $time_format
809
+	 * @return string
810
+	 * @throws EE_Error
811
+	 * @throws InvalidArgumentException
812
+	 * @throws InvalidDataTypeException
813
+	 * @throws InvalidInterfaceException
814
+	 * @throws ReflectionException
815
+	 */
816
+	public function ticket_datetime_start($date_format = '', $time_format = '')
817
+	{
818
+		$first_datetime_string = esc_html__('Unknown', 'event_espresso');
819
+		$datetime = $this->get_ticket_datetime();
820
+		if ($datetime) {
821
+			$first_datetime_string = $datetime->start_date_and_time($date_format, $time_format);
822
+		}
823
+		return $first_datetime_string;
824
+	}
825
+
826
+
827
+	/**
828
+	 * Adds the line item as a child to this line item. If there is another child line
829
+	 * item with the same LIN_code, it is overwritten by this new one
830
+	 *
831
+	 * @param EEI_Line_Item $line_item
832
+	 * @param bool          $set_order
833
+	 * @return bool success
834
+	 * @throws EE_Error
835
+	 * @throws InvalidArgumentException
836
+	 * @throws InvalidDataTypeException
837
+	 * @throws InvalidInterfaceException
838
+	 * @throws ReflectionException
839
+	 */
840
+	public function add_child_line_item(EEI_Line_Item $line_item, $set_order = true)
841
+	{
842
+		// should we calculate the LIN_order for this line item ?
843
+		if ($set_order || $line_item->order() === null) {
844
+			$line_item->set_order(count($this->children()));
845
+		}
846
+		if ($this->ID()) {
847
+			// check for any duplicate line items (with the same code), if so, this replaces it
848
+			$line_item_with_same_code = $this->get_child_line_item($line_item->code());
849
+			if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) {
850
+				$this->delete_child_line_item($line_item_with_same_code->code());
851
+			}
852
+			$line_item->set_parent_ID($this->ID());
853
+			if ($this->TXN_ID()) {
854
+				$line_item->set_TXN_ID($this->TXN_ID());
855
+			}
856
+			return $line_item->save();
857
+		}
858
+		$this->_children[ $line_item->code() ] = $line_item;
859
+		if ($line_item->parent() !== $this) {
860
+			$line_item->set_parent($this);
861
+		}
862
+		return true;
863
+	}
864
+
865
+
866
+	/**
867
+	 * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation.
868
+	 * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save()
869
+	 * However, if this line item is NOT saved to the DB, this just caches the parent on
870
+	 * the EE_Line_Item::_parent property.
871
+	 *
872
+	 * @param EE_Line_Item $line_item
873
+	 * @throws EE_Error
874
+	 * @throws InvalidArgumentException
875
+	 * @throws InvalidDataTypeException
876
+	 * @throws InvalidInterfaceException
877
+	 * @throws ReflectionException
878
+	 */
879
+	public function set_parent($line_item)
880
+	{
881
+		if ($this->ID()) {
882
+			if (! $line_item->ID()) {
883
+				$line_item->save();
884
+			}
885
+			$this->set_parent_ID($line_item->ID());
886
+			$this->save();
887
+		} else {
888
+			$this->_parent = $line_item;
889
+			$this->set_parent_ID($line_item->ID());
890
+		}
891
+	}
892
+
893
+
894
+	/**
895
+	 * Gets the child line item as specified by its code. Because this returns an object (by reference)
896
+	 * you can modify this child line item and the parent (this object) can know about them
897
+	 * because it also has a reference to that line item
898
+	 *
899
+	 * @param string $code
900
+	 * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
901
+	 * @throws EE_Error
902
+	 * @throws InvalidArgumentException
903
+	 * @throws InvalidDataTypeException
904
+	 * @throws InvalidInterfaceException
905
+	 * @throws ReflectionException
906
+	 */
907
+	public function get_child_line_item($code)
908
+	{
909
+		if ($this->ID()) {
910
+			return $this->get_model()->get_one(
911
+				array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code))
912
+			);
913
+		}
914
+		return isset($this->_children[ $code ])
915
+			? $this->_children[ $code ]
916
+			: null;
917
+	}
918
+
919
+
920
+	/**
921
+	 * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD
922
+	 * cached on it)
923
+	 *
924
+	 * @return int
925
+	 * @throws EE_Error
926
+	 * @throws InvalidArgumentException
927
+	 * @throws InvalidDataTypeException
928
+	 * @throws InvalidInterfaceException
929
+	 * @throws ReflectionException
930
+	 */
931
+	public function delete_children_line_items()
932
+	{
933
+		if ($this->ID()) {
934
+			return $this->get_model()->delete(array(array('LIN_parent' => $this->ID())));
935
+		}
936
+		$count = count($this->_children);
937
+		$this->_children = array();
938
+		return $count;
939
+	}
940
+
941
+
942
+	/**
943
+	 * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line
944
+	 * HAS NOT been saved to the DB, removes the child line item with index $code.
945
+	 * Also searches through the child's children for a matching line item. However, once a line item has been found
946
+	 * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be
947
+	 * deleted)
948
+	 *
949
+	 * @param string $code
950
+	 * @param bool   $stop_search_once_found
951
+	 * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to
952
+	 *             the DB yet)
953
+	 * @throws EE_Error
954
+	 * @throws InvalidArgumentException
955
+	 * @throws InvalidDataTypeException
956
+	 * @throws InvalidInterfaceException
957
+	 * @throws ReflectionException
958
+	 */
959
+	public function delete_child_line_item($code, $stop_search_once_found = true)
960
+	{
961
+		if ($this->ID()) {
962
+			$items_deleted = 0;
963
+			if ($this->code() === $code) {
964
+				$items_deleted += EEH_Line_Item::delete_all_child_items($this);
965
+				$items_deleted += (int) $this->delete();
966
+				if ($stop_search_once_found) {
967
+					return $items_deleted;
968
+				}
969
+			}
970
+			foreach ($this->children() as $child_line_item) {
971
+				$items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found);
972
+			}
973
+			return $items_deleted;
974
+		}
975
+		if (isset($this->_children[ $code ])) {
976
+			unset($this->_children[ $code ]);
977
+			return 1;
978
+		}
979
+		return 0;
980
+	}
981
+
982
+
983
+	/**
984
+	 * If this line item is in the database, is of the type subtotal, and
985
+	 * has no children, why do we have it? It should be deleted so this function
986
+	 * does that
987
+	 *
988
+	 * @return boolean
989
+	 * @throws EE_Error
990
+	 * @throws InvalidArgumentException
991
+	 * @throws InvalidDataTypeException
992
+	 * @throws InvalidInterfaceException
993
+	 * @throws ReflectionException
994
+	 */
995
+	public function delete_if_childless_subtotal()
996
+	{
997
+		if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) {
998
+			return $this->delete();
999
+		}
1000
+		return false;
1001
+	}
1002
+
1003
+
1004
+	/**
1005
+	 * Creates a code and returns a string. doesn't assign the code to this model object
1006
+	 *
1007
+	 * @return string
1008
+	 * @throws EE_Error
1009
+	 * @throws InvalidArgumentException
1010
+	 * @throws InvalidDataTypeException
1011
+	 * @throws InvalidInterfaceException
1012
+	 * @throws ReflectionException
1013
+	 */
1014
+	public function generate_code()
1015
+	{
1016
+		// each line item in the cart requires a unique identifier
1017
+		return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime());
1018
+	}
1019
+
1020
+
1021
+	/**
1022
+	 * @return bool
1023
+	 * @throws EE_Error
1024
+	 * @throws InvalidArgumentException
1025
+	 * @throws InvalidDataTypeException
1026
+	 * @throws InvalidInterfaceException
1027
+	 * @throws ReflectionException
1028
+	 */
1029
+	public function is_tax()
1030
+	{
1031
+		return $this->type() === EEM_Line_Item::type_tax;
1032
+	}
1033
+
1034
+
1035
+	/**
1036
+	 * @return bool
1037
+	 * @throws EE_Error
1038
+	 * @throws InvalidArgumentException
1039
+	 * @throws InvalidDataTypeException
1040
+	 * @throws InvalidInterfaceException
1041
+	 * @throws ReflectionException
1042
+	 */
1043
+	public function is_tax_sub_total()
1044
+	{
1045
+		return $this->type() === EEM_Line_Item::type_tax_sub_total;
1046
+	}
1047
+
1048
+
1049
+	/**
1050
+	 * @return bool
1051
+	 * @throws EE_Error
1052
+	 * @throws InvalidArgumentException
1053
+	 * @throws InvalidDataTypeException
1054
+	 * @throws InvalidInterfaceException
1055
+	 * @throws ReflectionException
1056
+	 */
1057
+	public function is_line_item()
1058
+	{
1059
+		return $this->type() === EEM_Line_Item::type_line_item;
1060
+	}
1061
+
1062
+
1063
+	/**
1064
+	 * @return bool
1065
+	 * @throws EE_Error
1066
+	 * @throws InvalidArgumentException
1067
+	 * @throws InvalidDataTypeException
1068
+	 * @throws InvalidInterfaceException
1069
+	 * @throws ReflectionException
1070
+	 */
1071
+	public function is_sub_line_item()
1072
+	{
1073
+		return $this->type() === EEM_Line_Item::type_sub_line_item;
1074
+	}
1075
+
1076
+
1077
+	/**
1078
+	 * @return bool
1079
+	 * @throws EE_Error
1080
+	 * @throws InvalidArgumentException
1081
+	 * @throws InvalidDataTypeException
1082
+	 * @throws InvalidInterfaceException
1083
+	 * @throws ReflectionException
1084
+	 */
1085
+	public function is_sub_total()
1086
+	{
1087
+		return $this->type() === EEM_Line_Item::type_sub_total;
1088
+	}
1089
+
1090
+
1091
+	/**
1092
+	 * Whether or not this line item is a cancellation line item
1093
+	 *
1094
+	 * @return boolean
1095
+	 * @throws EE_Error
1096
+	 * @throws InvalidArgumentException
1097
+	 * @throws InvalidDataTypeException
1098
+	 * @throws InvalidInterfaceException
1099
+	 * @throws ReflectionException
1100
+	 */
1101
+	public function is_cancellation()
1102
+	{
1103
+		return EEM_Line_Item::type_cancellation === $this->type();
1104
+	}
1105
+
1106
+
1107
+	/**
1108
+	 * @return bool
1109
+	 * @throws EE_Error
1110
+	 * @throws InvalidArgumentException
1111
+	 * @throws InvalidDataTypeException
1112
+	 * @throws InvalidInterfaceException
1113
+	 * @throws ReflectionException
1114
+	 */
1115
+	public function is_total()
1116
+	{
1117
+		return $this->type() === EEM_Line_Item::type_total;
1118
+	}
1119
+
1120
+
1121
+	/**
1122
+	 * @return bool
1123
+	 * @throws EE_Error
1124
+	 * @throws InvalidArgumentException
1125
+	 * @throws InvalidDataTypeException
1126
+	 * @throws InvalidInterfaceException
1127
+	 * @throws ReflectionException
1128
+	 */
1129
+	public function is_cancelled()
1130
+	{
1131
+		return $this->type() === EEM_Line_Item::type_cancellation;
1132
+	}
1133
+
1134
+
1135
+	/**
1136
+	 * @return string like '2, 004.00', formatted according to the localized currency
1137
+	 * @throws EE_Error
1138
+	 * @throws InvalidArgumentException
1139
+	 * @throws InvalidDataTypeException
1140
+	 * @throws InvalidInterfaceException
1141
+	 * @throws ReflectionException
1142
+	 */
1143
+	public function unit_price_no_code()
1144
+	{
1145
+		return $this->get_pretty('LIN_unit_price', 'no_currency_code');
1146
+	}
1147
+
1148
+
1149
+	/**
1150
+	 * @return string like '2, 004.00', formatted according to the localized currency
1151
+	 * @throws EE_Error
1152
+	 * @throws InvalidArgumentException
1153
+	 * @throws InvalidDataTypeException
1154
+	 * @throws InvalidInterfaceException
1155
+	 * @throws ReflectionException
1156
+	 */
1157
+	public function total_no_code()
1158
+	{
1159
+		return $this->get_pretty('LIN_total', 'no_currency_code');
1160
+	}
1161
+
1162
+
1163
+	/**
1164
+	 * Gets the final total on this item, taking taxes into account.
1165
+	 * Has the side-effect of setting the sub-total as it was just calculated.
1166
+	 * If this is used on a grand-total line item, also updates the transaction's
1167
+	 * TXN_total (provided this line item is allowed to persist, otherwise we don't
1168
+	 * want to change a persistable transaction with info from a non-persistent line item)
1169
+	 *
1170
+	 * @param bool $update_txn_status
1171
+	 * @return float
1172
+	 * @throws EE_Error
1173
+	 * @throws InvalidArgumentException
1174
+	 * @throws InvalidDataTypeException
1175
+	 * @throws InvalidInterfaceException
1176
+	 * @throws ReflectionException
1177
+	 * @throws RuntimeException
1178
+	 */
1179
+	public function recalculate_total_including_taxes($update_txn_status = false)
1180
+	{
1181
+		$pre_tax_total = $this->recalculate_pre_tax_total();
1182
+		$tax_total = $this->recalculate_taxes_and_tax_total();
1183
+		$total = $pre_tax_total + $tax_total;
1184
+		// no negative totals plz
1185
+		$total = max($total, 0);
1186
+		$this->set_total($total);
1187
+		// only update the related transaction's total
1188
+		// if we intend to save this line item and its a grand total
1189
+		if (
1190
+			$this->allow_persist() && $this->type() === EEM_Line_Item::type_total
1191
+			&& $this->transaction()
1192
+			   instanceof
1193
+			   EE_Transaction
1194
+		) {
1195
+			$this->transaction()->set_total($total);
1196
+			if ($update_txn_status) {
1197
+				// don't save the TXN because that will be done below
1198
+				// and the following method only saves if the status changes
1199
+				$this->transaction()->update_status_based_on_total_paid(false);
1200
+			}
1201
+			if ($this->transaction()->ID()) {
1202
+				$this->transaction()->save();
1203
+			}
1204
+		}
1205
+		$this->maybe_save();
1206
+		return $total;
1207
+	}
1208
+
1209
+
1210
+	/**
1211
+	 * Recursively goes through all the children and recalculates sub-totals EXCEPT for
1212
+	 * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its
1213
+	 * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
1214
+	 * when this is called on the grand total
1215
+	 *
1216
+	 * @return float
1217
+	 * @throws EE_Error
1218
+	 * @throws InvalidArgumentException
1219
+	 * @throws InvalidDataTypeException
1220
+	 * @throws InvalidInterfaceException
1221
+	 * @throws ReflectionException
1222
+	 */
1223
+	public function recalculate_pre_tax_total()
1224
+	{
1225
+		$total = 0;
1226
+		$my_children = $this->children();
1227
+		$has_children = ! empty($my_children);
1228
+		if ($has_children && $this->is_line_item()) {
1229
+			$total = $this->_recalculate_pretax_total_for_line_item($total, $my_children);
1230
+		} elseif (! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) {
1231
+			$total = $this->unit_price() * $this->quantity();
1232
+		} elseif ($this->is_sub_total() || $this->is_total()) {
1233
+			$total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children);
1234
+		} elseif ($this->is_tax_sub_total() || $this->is_tax() || $this->is_cancelled()) {
1235
+			// completely ignore tax totals, tax sub-totals, and cancelled line items, when calculating the pre-tax-total
1236
+			return 0;
1237
+		}
1238
+		// ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events)
1239
+		if (
1240
+			! $this->is_line_item() && ! $this->is_sub_line_item() && ! $this->is_cancellation()
1241
+		) {
1242
+			if ($this->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_EVENT) {
1243
+				$this->set_quantity(1);
1244
+			}
1245
+			if (! $this->is_percent()) {
1246
+				$this->set_unit_price($total);
1247
+			}
1248
+		}
1249
+		// we don't want to bother saving grand totals, because that needs to factor in taxes anyways
1250
+		// so it ought to be
1251
+		if (! $this->is_total()) {
1252
+			$this->set_total($total);
1253
+			// if not a percent line item, make sure we keep the unit price in sync
1254
+			if (
1255
+				$has_children
1256
+				&& $this->is_line_item()
1257
+				&& ! $this->is_percent()
1258
+			) {
1259
+				if ($this->quantity() === 0) {
1260
+					$new_unit_price = 0;
1261
+				} else {
1262
+					$new_unit_price = $this->total() / $this->quantity();
1263
+				}
1264
+				$this->set_unit_price($new_unit_price);
1265
+			}
1266
+			$this->maybe_save();
1267
+		}
1268
+		return $total;
1269
+	}
1270
+
1271
+
1272
+	/**
1273
+	 * Calculates the pretax total when this line item is a subtotal or total line item.
1274
+	 * Basically does a sum-then-round approach (ie, any percent line item that are children
1275
+	 * will calculate their total based on the un-rounded total we're working with so far, and
1276
+	 * THEN round the result; instead of rounding as we go like with sub-line-items)
1277
+	 *
1278
+	 * @param float          $calculated_total_so_far
1279
+	 * @param EE_Line_Item[] $my_children
1280
+	 * @return float
1281
+	 * @throws EE_Error
1282
+	 * @throws InvalidArgumentException
1283
+	 * @throws InvalidDataTypeException
1284
+	 * @throws InvalidInterfaceException
1285
+	 * @throws ReflectionException
1286
+	 */
1287
+	protected function _recalculate_pretax_total_for_subtotal($calculated_total_so_far, $my_children = null)
1288
+	{
1289
+		if ($my_children === null) {
1290
+			$my_children = $this->children();
1291
+		}
1292
+		$subtotal_quantity = 0;
1293
+		// get the total of all its children
1294
+		foreach ($my_children as $child_line_item) {
1295
+			if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) {
1296
+				// percentage line items are based on total so far
1297
+				if ($child_line_item->is_percent()) {
1298
+					// round as we go so that the line items add up ok
1299
+					$percent_total = round(
1300
+						$calculated_total_so_far * $child_line_item->percent() / 100,
1301
+						EE_Registry::instance()->CFG->currency->dec_plc
1302
+					);
1303
+					$child_line_item->set_total($percent_total);
1304
+					// so far all percent line items should have a quantity of 1
1305
+					// (ie, no double percent discounts. Although that might be requested someday)
1306
+					$child_line_item->set_quantity(1);
1307
+					$child_line_item->maybe_save();
1308
+					$calculated_total_so_far += $percent_total;
1309
+				} else {
1310
+					// verify flat sub-line-item quantities match their parent
1311
+					if ($child_line_item->is_sub_line_item()) {
1312
+						$child_line_item->set_quantity($this->quantity());
1313
+					}
1314
+					$calculated_total_so_far += $child_line_item->recalculate_pre_tax_total();
1315
+					$subtotal_quantity += $child_line_item->quantity();
1316
+				}
1317
+			}
1318
+		}
1319
+		if ($this->is_sub_total()) {
1320
+			// no negative totals plz
1321
+			$calculated_total_so_far = max($calculated_total_so_far, 0);
1322
+			$subtotal_quantity = $subtotal_quantity > 0 ? 1 : 0;
1323
+			$this->set_quantity($subtotal_quantity);
1324
+			$this->maybe_save();
1325
+		}
1326
+		return $calculated_total_so_far;
1327
+	}
1328
+
1329
+
1330
+	/**
1331
+	 * Calculates the pretax total for a normal line item, in a round-then-sum approach
1332
+	 * (where each sub-line-item is applied to the base price for the line item
1333
+	 * and the result is immediately rounded, rather than summing all the sub-line-items
1334
+	 * then rounding, like we do when recalculating pretax totals on totals and subtotals).
1335
+	 *
1336
+	 * @param float          $calculated_total_so_far
1337
+	 * @param EE_Line_Item[] $my_children
1338
+	 * @return float
1339
+	 * @throws EE_Error
1340
+	 * @throws InvalidArgumentException
1341
+	 * @throws InvalidDataTypeException
1342
+	 * @throws InvalidInterfaceException
1343
+	 * @throws ReflectionException
1344
+	 */
1345
+	protected function _recalculate_pretax_total_for_line_item($calculated_total_so_far, $my_children = null)
1346
+	{
1347
+		if ($my_children === null) {
1348
+			$my_children = $this->children();
1349
+		}
1350
+		// we need to keep track of the running total for a single item,
1351
+		// because we need to round as we go
1352
+		$unit_price_for_total = 0;
1353
+		$quantity_for_total = 1;
1354
+		// get the total of all its children
1355
+		foreach ($my_children as $child_line_item) {
1356
+			if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) {
1357
+				if ($child_line_item->is_percent()) {
1358
+					// it should be the unit-price-so-far multiplied by teh percent multiplied by the quantity
1359
+					// not total multiplied by percent, because that ignores rounding along-the-way
1360
+					$percent_unit_price = round(
1361
+						$unit_price_for_total * $child_line_item->percent() / 100,
1362
+						EE_Registry::instance()->CFG->currency->dec_plc
1363
+					);
1364
+					$percent_total = $percent_unit_price * $quantity_for_total;
1365
+					$child_line_item->set_total($percent_total);
1366
+					// so far all percent line items should have a quantity of 1
1367
+					// (ie, no double percent discounts. Although that might be requested someday)
1368
+					$child_line_item->set_quantity(1);
1369
+					$child_line_item->maybe_save();
1370
+					$calculated_total_so_far += $percent_total;
1371
+					$unit_price_for_total += $percent_unit_price;
1372
+				} else {
1373
+					// verify flat sub-line-item quantities match their parent
1374
+					if ($child_line_item->is_sub_line_item()) {
1375
+						$child_line_item->set_quantity($this->quantity());
1376
+					}
1377
+					$quantity_for_total = $child_line_item->quantity();
1378
+					$calculated_total_so_far += $child_line_item->recalculate_pre_tax_total();
1379
+					$unit_price_for_total += $child_line_item->unit_price();
1380
+				}
1381
+			}
1382
+		}
1383
+		return $calculated_total_so_far;
1384
+	}
1385
+
1386
+
1387
+	/**
1388
+	 * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
1389
+	 * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
1390
+	 * and tax sub-total if already in the DB
1391
+	 *
1392
+	 * @return float
1393
+	 * @throws EE_Error
1394
+	 * @throws InvalidArgumentException
1395
+	 * @throws InvalidDataTypeException
1396
+	 * @throws InvalidInterfaceException
1397
+	 * @throws ReflectionException
1398
+	 */
1399
+	public function recalculate_taxes_and_tax_total()
1400
+	{
1401
+		// get all taxes
1402
+		$taxes = $this->tax_descendants();
1403
+		// calculate the pretax total
1404
+		$taxable_total = $this->taxable_total();
1405
+		$tax_total = 0;
1406
+		foreach ($taxes as $tax) {
1407
+			$total_on_this_tax = $taxable_total * $tax->percent() / 100;
1408
+			// remember the total on this line item
1409
+			$tax->set_total($total_on_this_tax);
1410
+			$tax->maybe_save();
1411
+			$tax_total += $tax->total();
1412
+		}
1413
+		$this->_recalculate_tax_sub_total();
1414
+		return $tax_total;
1415
+	}
1416
+
1417
+
1418
+	/**
1419
+	 * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated
1420
+	 *
1421
+	 * @return void
1422
+	 * @throws EE_Error
1423
+	 * @throws InvalidArgumentException
1424
+	 * @throws InvalidDataTypeException
1425
+	 * @throws InvalidInterfaceException
1426
+	 * @throws ReflectionException
1427
+	 */
1428
+	private function _recalculate_tax_sub_total()
1429
+	{
1430
+		if ($this->is_tax_sub_total()) {
1431
+			$total = 0;
1432
+			$total_percent = 0;
1433
+			// simply loop through all its children (which should be taxes) and sum their total
1434
+			foreach ($this->children() as $child_tax) {
1435
+				if ($child_tax instanceof EE_Line_Item) {
1436
+					$total += $child_tax->total();
1437
+					$total_percent += $child_tax->percent();
1438
+				}
1439
+			}
1440
+			$this->set_total($total);
1441
+			$this->set_percent($total_percent);
1442
+			$this->maybe_save();
1443
+		} elseif ($this->is_total()) {
1444
+			foreach ($this->children() as $maybe_tax_subtotal) {
1445
+				if ($maybe_tax_subtotal instanceof EE_Line_Item) {
1446
+					$maybe_tax_subtotal->_recalculate_tax_sub_total();
1447
+				}
1448
+			}
1449
+		}
1450
+	}
1451
+
1452
+
1453
+	/**
1454
+	 * Gets the total tax on this line item. Assumes taxes have already been calculated using
1455
+	 * recalculate_taxes_and_total
1456
+	 *
1457
+	 * @return float
1458
+	 * @throws EE_Error
1459
+	 * @throws InvalidArgumentException
1460
+	 * @throws InvalidDataTypeException
1461
+	 * @throws InvalidInterfaceException
1462
+	 * @throws ReflectionException
1463
+	 */
1464
+	public function get_total_tax()
1465
+	{
1466
+		$this->_recalculate_tax_sub_total();
1467
+		$total = 0;
1468
+		foreach ($this->tax_descendants() as $tax_line_item) {
1469
+			if ($tax_line_item instanceof EE_Line_Item) {
1470
+				$total += $tax_line_item->total();
1471
+			}
1472
+		}
1473
+		return $total;
1474
+	}
1475
+
1476
+
1477
+	/**
1478
+	 * Gets the total for all the items purchased only
1479
+	 *
1480
+	 * @return float
1481
+	 * @throws EE_Error
1482
+	 * @throws InvalidArgumentException
1483
+	 * @throws InvalidDataTypeException
1484
+	 * @throws InvalidInterfaceException
1485
+	 * @throws ReflectionException
1486
+	 */
1487
+	public function get_items_total()
1488
+	{
1489
+		// by default, let's make sure we're consistent with the existing line item
1490
+		if ($this->is_total()) {
1491
+			$pretax_subtotal_li = EEH_Line_Item::get_pre_tax_subtotal($this);
1492
+			if ($pretax_subtotal_li instanceof EE_Line_Item) {
1493
+				return $pretax_subtotal_li->total();
1494
+			}
1495
+		}
1496
+		$total = 0;
1497
+		foreach ($this->get_items() as $item) {
1498
+			if ($item instanceof EE_Line_Item) {
1499
+				$total += $item->total();
1500
+			}
1501
+		}
1502
+		return $total;
1503
+	}
1504
+
1505
+
1506
+	/**
1507
+	 * Gets all the descendants (ie, children or children of children etc) that
1508
+	 * are of the type 'tax'
1509
+	 *
1510
+	 * @return EE_Line_Item[]
1511
+	 * @throws EE_Error
1512
+	 */
1513
+	public function tax_descendants()
1514
+	{
1515
+		return EEH_Line_Item::get_tax_descendants($this);
1516
+	}
1517
+
1518
+
1519
+	/**
1520
+	 * Gets all the real items purchased which are children of this item
1521
+	 *
1522
+	 * @return EE_Line_Item[]
1523
+	 * @throws EE_Error
1524
+	 */
1525
+	public function get_items()
1526
+	{
1527
+		return EEH_Line_Item::get_line_item_descendants($this);
1528
+	}
1529
+
1530
+
1531
+	/**
1532
+	 * Returns the amount taxable among this line item's children (or if it has no children,
1533
+	 * how much of it is taxable). Does not recalculate totals or subtotals.
1534
+	 * If the taxable total is negative, (eg, if none of the tickets were taxable,
1535
+	 * but there is a "Taxable" discount), returns 0.
1536
+	 *
1537
+	 * @return float
1538
+	 * @throws EE_Error
1539
+	 * @throws InvalidArgumentException
1540
+	 * @throws InvalidDataTypeException
1541
+	 * @throws InvalidInterfaceException
1542
+	 * @throws ReflectionException
1543
+	 */
1544
+	public function taxable_total()
1545
+	{
1546
+		$total = 0;
1547
+		if ($this->children()) {
1548
+			foreach ($this->children() as $child_line_item) {
1549
+				if ($child_line_item->type() === EEM_Line_Item::type_line_item && $child_line_item->is_taxable()) {
1550
+					// if it's a percent item, only take into account the percent
1551
+					// that's taxable too (the taxable total so far)
1552
+					if ($child_line_item->is_percent()) {
1553
+						$total += ($total * $child_line_item->percent() / 100);
1554
+					} else {
1555
+						$total += $child_line_item->total();
1556
+					}
1557
+				} elseif ($child_line_item->type() === EEM_Line_Item::type_sub_total) {
1558
+					$total += $child_line_item->taxable_total();
1559
+				}
1560
+			}
1561
+		}
1562
+		return max($total, 0);
1563
+	}
1564
+
1565
+
1566
+	/**
1567
+	 * Gets the transaction for this line item
1568
+	 *
1569
+	 * @return EE_Base_Class|EE_Transaction
1570
+	 * @throws EE_Error
1571
+	 * @throws InvalidArgumentException
1572
+	 * @throws InvalidDataTypeException
1573
+	 * @throws InvalidInterfaceException
1574
+	 * @throws ReflectionException
1575
+	 */
1576
+	public function transaction()
1577
+	{
1578
+		return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TRANSACTION);
1579
+	}
1580
+
1581
+
1582
+	/**
1583
+	 * Saves this line item to the DB, and recursively saves its descendants.
1584
+	 * Because there currently is no proper parent-child relation on the model,
1585
+	 * save_this_and_cached() will NOT save the descendants.
1586
+	 * Also sets the transaction on this line item and all its descendants before saving
1587
+	 *
1588
+	 * @param int $txn_id if none is provided, assumes $this->TXN_ID()
1589
+	 * @return int count of items saved
1590
+	 * @throws EE_Error
1591
+	 * @throws InvalidArgumentException
1592
+	 * @throws InvalidDataTypeException
1593
+	 * @throws InvalidInterfaceException
1594
+	 * @throws ReflectionException
1595
+	 */
1596
+	public function save_this_and_descendants_to_txn($txn_id = null)
1597
+	{
1598
+		$count = 0;
1599
+		if (! $txn_id) {
1600
+			$txn_id = $this->TXN_ID();
1601
+		}
1602
+		$this->set_TXN_ID($txn_id);
1603
+		$children = $this->children();
1604
+		$count += $this->save()
1605
+			? 1
1606
+			: 0;
1607
+		foreach ($children as $child_line_item) {
1608
+			if ($child_line_item instanceof EE_Line_Item) {
1609
+				$child_line_item->set_parent_ID($this->ID());
1610
+				$count += $child_line_item->save_this_and_descendants_to_txn($txn_id);
1611
+			}
1612
+		}
1613
+		return $count;
1614
+	}
1615
+
1616
+
1617
+	/**
1618
+	 * Saves this line item to the DB, and recursively saves its descendants.
1619
+	 *
1620
+	 * @return int count of items saved
1621
+	 * @throws EE_Error
1622
+	 * @throws InvalidArgumentException
1623
+	 * @throws InvalidDataTypeException
1624
+	 * @throws InvalidInterfaceException
1625
+	 * @throws ReflectionException
1626
+	 */
1627
+	public function save_this_and_descendants()
1628
+	{
1629
+		$count = 0;
1630
+		$children = $this->children();
1631
+		$count += $this->save()
1632
+			? 1
1633
+			: 0;
1634
+		foreach ($children as $child_line_item) {
1635
+			if ($child_line_item instanceof EE_Line_Item) {
1636
+				$child_line_item->set_parent_ID($this->ID());
1637
+				$count += $child_line_item->save_this_and_descendants();
1638
+			}
1639
+		}
1640
+		return $count;
1641
+	}
1642
+
1643
+
1644
+	/**
1645
+	 * returns the cancellation line item if this item was cancelled
1646
+	 *
1647
+	 * @return EE_Line_Item[]
1648
+	 * @throws InvalidArgumentException
1649
+	 * @throws InvalidInterfaceException
1650
+	 * @throws InvalidDataTypeException
1651
+	 * @throws ReflectionException
1652
+	 * @throws EE_Error
1653
+	 */
1654
+	public function get_cancellations()
1655
+	{
1656
+		EE_Registry::instance()->load_helper('Line_Item');
1657
+		return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation);
1658
+	}
1659
+
1660
+
1661
+	/**
1662
+	 * If this item has an ID, then this saves it again to update the db
1663
+	 *
1664
+	 * @return int count of items saved
1665
+	 * @throws EE_Error
1666
+	 * @throws InvalidArgumentException
1667
+	 * @throws InvalidDataTypeException
1668
+	 * @throws InvalidInterfaceException
1669
+	 * @throws ReflectionException
1670
+	 */
1671
+	public function maybe_save()
1672
+	{
1673
+		if ($this->ID()) {
1674
+			return $this->save();
1675
+		}
1676
+		return false;
1677
+	}
1678
+
1679
+
1680
+	/**
1681
+	 * clears the cached children and parent from the line item
1682
+	 *
1683
+	 * @return void
1684
+	 */
1685
+	public function clear_related_line_item_cache()
1686
+	{
1687
+		$this->_children = array();
1688
+		$this->_parent = null;
1689
+	}
1690
+
1691
+
1692
+	/**
1693
+	 * @param bool $raw
1694
+	 * @return int
1695
+	 * @throws EE_Error
1696
+	 * @throws InvalidArgumentException
1697
+	 * @throws InvalidDataTypeException
1698
+	 * @throws InvalidInterfaceException
1699
+	 * @throws ReflectionException
1700
+	 */
1701
+	public function timestamp($raw = false)
1702
+	{
1703
+		return $raw
1704
+			? $this->get_raw('LIN_timestamp')
1705
+			: $this->get('LIN_timestamp');
1706
+	}
1707
+
1708
+
1709
+
1710
+
1711
+	/************************* DEPRECATED *************************/
1712
+	/**
1713
+	 * @deprecated 4.6.0
1714
+	 * @param string $type one of the constants on EEM_Line_Item
1715
+	 * @return EE_Line_Item[]
1716
+	 * @throws EE_Error
1717
+	 */
1718
+	protected function _get_descendants_of_type($type)
1719
+	{
1720
+		EE_Error::doing_it_wrong(
1721
+			'EE_Line_Item::_get_descendants_of_type()',
1722
+			sprintf(
1723
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
1724
+				'EEH_Line_Item::get_descendants_of_type()'
1725
+			),
1726
+			'4.6.0'
1727
+		);
1728
+		return EEH_Line_Item::get_descendants_of_type($this, $type);
1729
+	}
1730
+
1731
+
1732
+	/**
1733
+	 * @deprecated 4.6.0
1734
+	 * @param string $type like one of the EEM_Line_Item::type_*
1735
+	 * @return EE_Line_Item
1736
+	 * @throws EE_Error
1737
+	 * @throws InvalidArgumentException
1738
+	 * @throws InvalidDataTypeException
1739
+	 * @throws InvalidInterfaceException
1740
+	 * @throws ReflectionException
1741
+	 */
1742
+	public function get_nearest_descendant_of_type($type)
1743
+	{
1744
+		EE_Error::doing_it_wrong(
1745
+			'EE_Line_Item::get_nearest_descendant_of_type()',
1746
+			sprintf(
1747
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
1748
+				'EEH_Line_Item::get_nearest_descendant_of_type()'
1749
+			),
1750
+			'4.6.0'
1751
+		);
1752
+		return EEH_Line_Item::get_nearest_descendant_of_type($this, $type);
1753
+	}
1754 1754
 }
Please login to merge, or discard this patch.
core/domain/entities/editor/blocks/EventAttendees.php 2 patches
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -154,19 +154,19 @@
 block discarded – undo
154 154
         $sanitized_attributes = array();
155 155
         foreach ($attributes as $attribute => $value) {
156 156
             $convert = $this->getAttributesMap();
157
-            if (isset($convert[ $attribute ])) {
158
-                $sanitize = $convert[ $attribute ];
157
+            if (isset($convert[$attribute])) {
158
+                $sanitize = $convert[$attribute];
159 159
                 if ($sanitize === 'bool') {
160
-                    $sanitized_attributes[ $attribute ] = filter_var(
160
+                    $sanitized_attributes[$attribute] = filter_var(
161 161
                         $value,
162 162
                         FILTER_VALIDATE_BOOLEAN
163 163
                     );
164 164
                 } else {
165
-                    $sanitized_attributes[ $attribute ] = $sanitize($value);
165
+                    $sanitized_attributes[$attribute] = $sanitize($value);
166 166
                 }
167 167
                 // don't pass along attributes with a 0 value
168
-                if ($sanitized_attributes[ $attribute ] === 0) {
169
-                    unset($sanitized_attributes[ $attribute ]);
168
+                if ($sanitized_attributes[$attribute] === 0) {
169
+                    unset($sanitized_attributes[$attribute]);
170 170
                 }
171 171
             }
172 172
         }
Please login to merge, or discard this patch.
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -20,172 +20,172 @@
 block discarded – undo
20 20
  */
21 21
 class EventAttendees extends Block
22 22
 {
23
-    const BLOCK_TYPE = 'event-attendees';
23
+	const BLOCK_TYPE = 'event-attendees';
24 24
 
25
-    /**
26
-     * @var EventAttendeesBlockRenderer $renderer
27
-     */
28
-    protected $renderer;
25
+	/**
26
+	 * @var EventAttendeesBlockRenderer $renderer
27
+	 */
28
+	protected $renderer;
29 29
 
30 30
 
31
-    /**
32
-     * EventAttendees constructor.
33
-     *
34
-     * @param CoreBlocksAssetManager      $block_asset_manager
35
-     * @param RequestInterface            $request
36
-     * @param EventAttendeesBlockRenderer $renderer
37
-     */
38
-    public function __construct(
39
-        CoreBlocksAssetManager $block_asset_manager,
40
-        RequestInterface $request,
41
-        EventAttendeesBlockRenderer $renderer
42
-    ) {
43
-        parent::__construct($block_asset_manager, $request);
44
-        $this->renderer = $renderer;
45
-    }
31
+	/**
32
+	 * EventAttendees constructor.
33
+	 *
34
+	 * @param CoreBlocksAssetManager      $block_asset_manager
35
+	 * @param RequestInterface            $request
36
+	 * @param EventAttendeesBlockRenderer $renderer
37
+	 */
38
+	public function __construct(
39
+		CoreBlocksAssetManager $block_asset_manager,
40
+		RequestInterface $request,
41
+		EventAttendeesBlockRenderer $renderer
42
+	) {
43
+		parent::__construct($block_asset_manager, $request);
44
+		$this->renderer = $renderer;
45
+	}
46 46
 
47 47
 
48
-    /**
49
-     * Perform any early setup required by the block
50
-     * including setting the block type and supported post types
51
-     *
52
-     * @return void
53
-     */
54
-    public function initialize()
55
-    {
56
-        $this->setBlockType(self::BLOCK_TYPE);
57
-        $this->setSupportedRoutes(
58
-            array(
59
-                'EventEspresso\core\domain\entities\route_match\specifications\admin\EspressoStandardPostTypeEditor',
60
-                'EventEspresso\core\domain\entities\route_match\specifications\admin\WordPressPostTypeEditor',
61
-                'EventEspresso\core\domain\entities\route_match\specifications\frontend\EspressoBlockRenderer',
62
-                'EventEspresso\core\domain\entities\route_match\specifications\frontend\AnyFrontendRequest'
63
-            )
64
-        );
65
-        $EVT_ID = $this->request->getRequestParam('page') === 'espresso_events'
66
-            ? $this->request->getRequestParam('post', 0, 'int')
67
-            : 0;
68
-        $this->setAttributes(
69
-            array(
70
-                'eventId'           => array(
71
-                    'type'    => 'number',
72
-                    'default' => $EVT_ID,
73
-                ),
74
-                'datetimeId'        => array(
75
-                    'type'    => 'number',
76
-                    'default' => 0,
77
-                ),
78
-                'ticketId'          => array(
79
-                    'type'    => 'number',
80
-                    'default' => 0,
81
-                ),
82
-                'status'            => array(
83
-                    'type'    => 'string',
84
-                    'default' => EEM_Registration::status_id_approved,
85
-                ),
86
-                'limit'             => array(
87
-                    'type'    => 'number',
88
-                    'default' => 100,
89
-                ),
90
-                'order' => array(
91
-                    'type' => 'string',
92
-                    'default' => 'ASC'
93
-                ),
94
-                'orderBy' => array(
95
-                    'type' => 'string',
96
-                    'default' => 'lastThenFirstName',
97
-                ),
98
-                'showGravatar'      => array(
99
-                    'type'    => 'boolean',
100
-                    'default' => false,
101
-                ),
102
-                'avatarClass' => array(
103
-                    'type' => 'string',
104
-                    'default' => 'contact',
105
-                ),
106
-                'avatarSize' => array(
107
-                    'type' => 'number',
108
-                    'default' => 24,
109
-                ),
110
-                'displayOnArchives' => array(
111
-                    'type'    => 'boolean',
112
-                    'default' => false,
113
-                ),
114
-            )
115
-        );
116
-        $this->setDynamic();
117
-    }
48
+	/**
49
+	 * Perform any early setup required by the block
50
+	 * including setting the block type and supported post types
51
+	 *
52
+	 * @return void
53
+	 */
54
+	public function initialize()
55
+	{
56
+		$this->setBlockType(self::BLOCK_TYPE);
57
+		$this->setSupportedRoutes(
58
+			array(
59
+				'EventEspresso\core\domain\entities\route_match\specifications\admin\EspressoStandardPostTypeEditor',
60
+				'EventEspresso\core\domain\entities\route_match\specifications\admin\WordPressPostTypeEditor',
61
+				'EventEspresso\core\domain\entities\route_match\specifications\frontend\EspressoBlockRenderer',
62
+				'EventEspresso\core\domain\entities\route_match\specifications\frontend\AnyFrontendRequest'
63
+			)
64
+		);
65
+		$EVT_ID = $this->request->getRequestParam('page') === 'espresso_events'
66
+			? $this->request->getRequestParam('post', 0, 'int')
67
+			: 0;
68
+		$this->setAttributes(
69
+			array(
70
+				'eventId'           => array(
71
+					'type'    => 'number',
72
+					'default' => $EVT_ID,
73
+				),
74
+				'datetimeId'        => array(
75
+					'type'    => 'number',
76
+					'default' => 0,
77
+				),
78
+				'ticketId'          => array(
79
+					'type'    => 'number',
80
+					'default' => 0,
81
+				),
82
+				'status'            => array(
83
+					'type'    => 'string',
84
+					'default' => EEM_Registration::status_id_approved,
85
+				),
86
+				'limit'             => array(
87
+					'type'    => 'number',
88
+					'default' => 100,
89
+				),
90
+				'order' => array(
91
+					'type' => 'string',
92
+					'default' => 'ASC'
93
+				),
94
+				'orderBy' => array(
95
+					'type' => 'string',
96
+					'default' => 'lastThenFirstName',
97
+				),
98
+				'showGravatar'      => array(
99
+					'type'    => 'boolean',
100
+					'default' => false,
101
+				),
102
+				'avatarClass' => array(
103
+					'type' => 'string',
104
+					'default' => 'contact',
105
+				),
106
+				'avatarSize' => array(
107
+					'type' => 'number',
108
+					'default' => 24,
109
+				),
110
+				'displayOnArchives' => array(
111
+					'type'    => 'boolean',
112
+					'default' => false,
113
+				),
114
+			)
115
+		);
116
+		$this->setDynamic();
117
+	}
118 118
 
119 119
 
120
-    /**
121
-     * Returns an array where the key corresponds to the incoming attribute name from the WP block
122
-     * and the value corresponds to the attribute name for the existing EspressoEventAttendees shortcode
123
-     *
124
-     * @since 4.9.71.p
125
-     * @return array
126
-     */
127
-    private function getAttributesMap()
128
-    {
129
-        return array(
130
-            'eventId'           => 'absint',
131
-            'datetimeId'        => 'absint',
132
-            'ticketId'          => 'absint',
133
-            'status'            => 'sanitize_text_field',
134
-            'limit'             => 'intval',
135
-            'showGravatar'      => 'bool',
136
-            'avatarClass'       => 'sanitize_text_field',
137
-            'avatarSize'        => 'absint',
138
-            'displayOnArchives' => 'bool',
139
-            'order' => 'sanitize_text_field',
140
-            'orderBy' => 'sanitize_text_field',
141
-        );
142
-    }
120
+	/**
121
+	 * Returns an array where the key corresponds to the incoming attribute name from the WP block
122
+	 * and the value corresponds to the attribute name for the existing EspressoEventAttendees shortcode
123
+	 *
124
+	 * @since 4.9.71.p
125
+	 * @return array
126
+	 */
127
+	private function getAttributesMap()
128
+	{
129
+		return array(
130
+			'eventId'           => 'absint',
131
+			'datetimeId'        => 'absint',
132
+			'ticketId'          => 'absint',
133
+			'status'            => 'sanitize_text_field',
134
+			'limit'             => 'intval',
135
+			'showGravatar'      => 'bool',
136
+			'avatarClass'       => 'sanitize_text_field',
137
+			'avatarSize'        => 'absint',
138
+			'displayOnArchives' => 'bool',
139
+			'order' => 'sanitize_text_field',
140
+			'orderBy' => 'sanitize_text_field',
141
+		);
142
+	}
143 143
 
144 144
 
145
-    /**
146
-     * Sanitizes attributes.
147
-     *
148
-     * @param array $attributes
149
-     * @return array
150
-     */
151
-    private function sanitizeAttributes(array $attributes)
152
-    {
153
-        $sanitized_attributes = array();
154
-        foreach ($attributes as $attribute => $value) {
155
-            $convert = $this->getAttributesMap();
156
-            if (isset($convert[ $attribute ])) {
157
-                $sanitize = $convert[ $attribute ];
158
-                if ($sanitize === 'bool') {
159
-                    $sanitized_attributes[ $attribute ] = filter_var(
160
-                        $value,
161
-                        FILTER_VALIDATE_BOOLEAN
162
-                    );
163
-                } else {
164
-                    $sanitized_attributes[ $attribute ] = $sanitize($value);
165
-                }
166
-                // don't pass along attributes with a 0 value
167
-                if ($sanitized_attributes[ $attribute ] === 0) {
168
-                    unset($sanitized_attributes[ $attribute ]);
169
-                }
170
-            }
171
-        }
172
-        return $attributes;
173
-    }
145
+	/**
146
+	 * Sanitizes attributes.
147
+	 *
148
+	 * @param array $attributes
149
+	 * @return array
150
+	 */
151
+	private function sanitizeAttributes(array $attributes)
152
+	{
153
+		$sanitized_attributes = array();
154
+		foreach ($attributes as $attribute => $value) {
155
+			$convert = $this->getAttributesMap();
156
+			if (isset($convert[ $attribute ])) {
157
+				$sanitize = $convert[ $attribute ];
158
+				if ($sanitize === 'bool') {
159
+					$sanitized_attributes[ $attribute ] = filter_var(
160
+						$value,
161
+						FILTER_VALIDATE_BOOLEAN
162
+					);
163
+				} else {
164
+					$sanitized_attributes[ $attribute ] = $sanitize($value);
165
+				}
166
+				// don't pass along attributes with a 0 value
167
+				if ($sanitized_attributes[ $attribute ] === 0) {
168
+					unset($sanitized_attributes[ $attribute ]);
169
+				}
170
+			}
171
+		}
172
+		return $attributes;
173
+	}
174 174
 
175 175
 
176
-    /**
177
-     * Returns the rendered HTML for the block
178
-     *
179
-     * @param array $attributes
180
-     * @return string
181
-     * @throws DomainException
182
-     * @throws EE_Error
183
-     */
184
-    public function renderBlock(array $attributes = array())
185
-    {
186
-        $attributes = $this->sanitizeAttributes($attributes);
187
-        return (is_archive() || is_front_page() || is_home()) && ! $attributes['displayOnArchives']
188
-            ? ''
189
-            : $this->renderer->render($attributes);
190
-    }
176
+	/**
177
+	 * Returns the rendered HTML for the block
178
+	 *
179
+	 * @param array $attributes
180
+	 * @return string
181
+	 * @throws DomainException
182
+	 * @throws EE_Error
183
+	 */
184
+	public function renderBlock(array $attributes = array())
185
+	{
186
+		$attributes = $this->sanitizeAttributes($attributes);
187
+		return (is_archive() || is_front_page() || is_home()) && ! $attributes['displayOnArchives']
188
+			? ''
189
+			: $this->renderer->render($attributes);
190
+	}
191 191
 }
Please login to merge, or discard this patch.
strategies/EE_Restriction_Generator_Default_Protected.strategy.php 2 patches
Indentation   +75 added lines, -75 removed lines patch added patch discarded remove patch
@@ -17,85 +17,85 @@
 block discarded – undo
17 17
  */
18 18
 class EE_Restriction_Generator_Default_Protected extends EE_Restriction_Generator_Base
19 19
 {
20
-    /**
21
-     * Name of the field on this model (or a related model, including the model chain to it)
22
-     * that is a boolean indicating whether or not a model object is considered "Default" or not
23
-     * @var string
24
-     */
25
-    protected $_default_field_name;
20
+	/**
21
+	 * Name of the field on this model (or a related model, including the model chain to it)
22
+	 * that is a boolean indicating whether or not a model object is considered "Default" or not
23
+	 * @var string
24
+	 */
25
+	protected $_default_field_name;
26 26
 
27
-    /**
28
-     * The model chain to follow to get to the event model, including the event model itself.
29
-     * Eg 'Ticket.Datetime.Event'
30
-     * @var string
31
-     */
32
-    protected $_path_to_event_model;
33
-    /**
34
-     *
35
-     * @param string $default_field_name the name of the field Name of the field on this model (or a related model, including the model chain to it)
36
-     * that is a boolean indicating whether or not a model object is considered "Default" or not
37
-     * @param string $path_to_event_model The model chain to follow to get to the event model, including the event model itself.
38
-     * Eg 'Ticket.Datetime.Event'
39
-     */
40
-    public function __construct($default_field_name, $path_to_event_model)
41
-    {
42
-        $this->_default_field_name = $default_field_name;
43
-        if (substr($path_to_event_model, -1, 1) != '.') {
44
-            $path_to_event_model .= '.';
45
-        }
46
-        $this->_path_to_event_model = $path_to_event_model;
47
-    }
27
+	/**
28
+	 * The model chain to follow to get to the event model, including the event model itself.
29
+	 * Eg 'Ticket.Datetime.Event'
30
+	 * @var string
31
+	 */
32
+	protected $_path_to_event_model;
33
+	/**
34
+	 *
35
+	 * @param string $default_field_name the name of the field Name of the field on this model (or a related model, including the model chain to it)
36
+	 * that is a boolean indicating whether or not a model object is considered "Default" or not
37
+	 * @param string $path_to_event_model The model chain to follow to get to the event model, including the event model itself.
38
+	 * Eg 'Ticket.Datetime.Event'
39
+	 */
40
+	public function __construct($default_field_name, $path_to_event_model)
41
+	{
42
+		$this->_default_field_name = $default_field_name;
43
+		if (substr($path_to_event_model, -1, 1) != '.') {
44
+			$path_to_event_model .= '.';
45
+		}
46
+		$this->_path_to_event_model = $path_to_event_model;
47
+	}
48 48
 
49 49
 
50 50
 
51
-    /**
52
-     *
53
-     * @return \EE_Default_Where_Conditions
54
-     */
55
-    protected function _generate_restrictions()
56
-    {
57
-        // if there are no standard caps for this model, then for now all we know is
58
-        // if they need the default cap to access this
59
-        if (! $this->model()->cap_slug()) {
60
-            return array(
61
-                self::get_default_restrictions_cap() => new EE_Return_None_Where_Conditions()
62
-            );
63
-        }
51
+	/**
52
+	 *
53
+	 * @return \EE_Default_Where_Conditions
54
+	 */
55
+	protected function _generate_restrictions()
56
+	{
57
+		// if there are no standard caps for this model, then for now all we know is
58
+		// if they need the default cap to access this
59
+		if (! $this->model()->cap_slug()) {
60
+			return array(
61
+				self::get_default_restrictions_cap() => new EE_Return_None_Where_Conditions()
62
+			);
63
+		}
64 64
 
65
-        $event_model = EEM_Event::instance();
65
+		$event_model = EEM_Event::instance();
66 66
 
67
-        $restrictions =  array(
68
-            // first: basically access to non-defaults is essentially controlled by which events are accessible
69
-            // if they don't have the basic event cap, they can't access ANY non-default items
70
-            EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action()) => new EE_Default_Where_Conditions(array( $this->_default_field_name => true )),
71
-            // if they don't have the others event cap, they can't access others' non-default items
72
-            EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => new EE_Default_Where_Conditions(array(
73
-                'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => array(
74
-                    $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder ),
75
-                    $this->_default_field_name => true )),
76
-            // if they have basic and others, but not private, they can't access others' private non-default items
77
-            EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => new EE_Default_Where_Conditions(array(
78
-                'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => array(
79
-                $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder,
80
-                $this->_path_to_event_model . 'status' => array( '!=', 'private' ),
81
-                $this->_default_field_name => true ) )),
82
-            // second: access to defaults is controlled by the defaulty capabilities
83
-            // if they don't have the default capability, restrict access to only non-default items
84
-            EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_default') => new EE_Default_Where_Conditions(array( $this->_default_field_name => false )),
85
-            // if they don't have the "others" default capability, restrict access to only their default ones, and non-default ones
86
-             );
87
-        if (EE_Restriction_Generator_Base::is_cap($this->model(), $this->action() . '_others_default')) {
88
-            $restrictions[ EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') ] = new EE_Default_Where_Conditions(array(
89
-                    // if they don't have the others default cap, they can't access others default items (but they can access
90
-                    // their own default items, and non-default items)
91
-                    'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') => array(
92
-                        'AND' => array(
93
-                            $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder,
94
-                            $this->_default_field_name => true
95
-                            ),
96
-                        $this->_default_field_name => false
97
-                    ) ));
98
-        }
99
-        return $restrictions;
100
-    }
67
+		$restrictions =  array(
68
+			// first: basically access to non-defaults is essentially controlled by which events are accessible
69
+			// if they don't have the basic event cap, they can't access ANY non-default items
70
+			EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action()) => new EE_Default_Where_Conditions(array( $this->_default_field_name => true )),
71
+			// if they don't have the others event cap, they can't access others' non-default items
72
+			EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => new EE_Default_Where_Conditions(array(
73
+				'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => array(
74
+					$this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder ),
75
+					$this->_default_field_name => true )),
76
+			// if they have basic and others, but not private, they can't access others' private non-default items
77
+			EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => new EE_Default_Where_Conditions(array(
78
+				'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => array(
79
+				$this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder,
80
+				$this->_path_to_event_model . 'status' => array( '!=', 'private' ),
81
+				$this->_default_field_name => true ) )),
82
+			// second: access to defaults is controlled by the defaulty capabilities
83
+			// if they don't have the default capability, restrict access to only non-default items
84
+			EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_default') => new EE_Default_Where_Conditions(array( $this->_default_field_name => false )),
85
+			// if they don't have the "others" default capability, restrict access to only their default ones, and non-default ones
86
+			 );
87
+		if (EE_Restriction_Generator_Base::is_cap($this->model(), $this->action() . '_others_default')) {
88
+			$restrictions[ EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') ] = new EE_Default_Where_Conditions(array(
89
+					// if they don't have the others default cap, they can't access others default items (but they can access
90
+					// their own default items, and non-default items)
91
+					'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') => array(
92
+						'AND' => array(
93
+							$this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder,
94
+							$this->_default_field_name => true
95
+							),
96
+						$this->_default_field_name => false
97
+					) ));
98
+		}
99
+		return $restrictions;
100
+	}
101 101
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -56,7 +56,7 @@  discard block
 block discarded – undo
56 56
     {
57 57
         // if there are no standard caps for this model, then for now all we know is
58 58
         // if they need the default cap to access this
59
-        if (! $this->model()->cap_slug()) {
59
+        if ( ! $this->model()->cap_slug()) {
60 60
             return array(
61 61
                 self::get_default_restrictions_cap() => new EE_Return_None_Where_Conditions()
62 62
             );
@@ -64,33 +64,33 @@  discard block
 block discarded – undo
64 64
 
65 65
         $event_model = EEM_Event::instance();
66 66
 
67
-        $restrictions =  array(
67
+        $restrictions = array(
68 68
             // first: basically access to non-defaults is essentially controlled by which events are accessible
69 69
             // if they don't have the basic event cap, they can't access ANY non-default items
70
-            EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action()) => new EE_Default_Where_Conditions(array( $this->_default_field_name => true )),
70
+            EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action()) => new EE_Default_Where_Conditions(array($this->_default_field_name => true)),
71 71
             // if they don't have the others event cap, they can't access others' non-default items
72
-            EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => new EE_Default_Where_Conditions(array(
73
-                'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => array(
74
-                    $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder ),
72
+            EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action().'_others') => new EE_Default_Where_Conditions(array(
73
+                'OR*no_'.EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action().'_others') => array(
74
+                    $this->_path_to_event_model.'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder ),
75 75
                     $this->_default_field_name => true )),
76 76
             // if they have basic and others, but not private, they can't access others' private non-default items
77
-            EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => new EE_Default_Where_Conditions(array(
78
-                'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => array(
79
-                $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder,
80
-                $this->_path_to_event_model . 'status' => array( '!=', 'private' ),
77
+            EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action().'_private') => new EE_Default_Where_Conditions(array(
78
+                'OR*no_'.EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action().'_private') => array(
79
+                $this->_path_to_event_model.'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder,
80
+                $this->_path_to_event_model.'status' => array('!=', 'private'),
81 81
                 $this->_default_field_name => true ) )),
82 82
             // second: access to defaults is controlled by the defaulty capabilities
83 83
             // if they don't have the default capability, restrict access to only non-default items
84
-            EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_default') => new EE_Default_Where_Conditions(array( $this->_default_field_name => false )),
84
+            EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action().'_default') => new EE_Default_Where_Conditions(array($this->_default_field_name => false)),
85 85
             // if they don't have the "others" default capability, restrict access to only their default ones, and non-default ones
86 86
              );
87
-        if (EE_Restriction_Generator_Base::is_cap($this->model(), $this->action() . '_others_default')) {
88
-            $restrictions[ EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') ] = new EE_Default_Where_Conditions(array(
87
+        if (EE_Restriction_Generator_Base::is_cap($this->model(), $this->action().'_others_default')) {
88
+            $restrictions[EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action().'_others_default')] = new EE_Default_Where_Conditions(array(
89 89
                     // if they don't have the others default cap, they can't access others default items (but they can access
90 90
                     // their own default items, and non-default items)
91
-                    'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') => array(
91
+                    'OR*no_'.EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action().'_others_default') => array(
92 92
                         'AND' => array(
93
-                            $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder,
93
+                            $this->_path_to_event_model.'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder,
94 94
                             $this->_default_field_name => true
95 95
                             ),
96 96
                         $this->_default_field_name => false
Please login to merge, or discard this patch.
core/helpers/EEH_Event_Query.helper.php 2 patches
Spacing   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
     {
217 217
         if (EEH_Event_Query::apply_query_filters($wp_query)) {
218 218
             global $wpdb;
219
-            $clauses['groupby'] = $wpdb->posts . '.ID ';
219
+            $clauses['groupby'] = $wpdb->posts.'.ID ';
220 220
         }
221 221
         return $clauses;
222 222
     }
@@ -251,23 +251,23 @@  discard block
 block discarded – undo
251 251
      */
252 252
     public static function posts_fields_sql_for_orderby(array $orderby_params = [])
253 253
     {
254
-        $SQL = ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date ';
254
+        $SQL = ', MIN( '.EEM_Datetime::instance()->table().'.DTT_EVT_start ) as event_start_date ';
255 255
         foreach ($orderby_params as $orderby) {
256 256
             switch ($orderby) {
257 257
                 case 'ticket_start':
258
-                    $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_start_date';
258
+                    $SQL .= ', '.EEM_Ticket::instance()->table().'.TKT_start_date';
259 259
                     break;
260 260
                 case 'ticket_end':
261
-                    $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_end_date';
261
+                    $SQL .= ', '.EEM_Ticket::instance()->table().'.TKT_end_date';
262 262
                     break;
263 263
                 case 'venue_title':
264 264
                     $SQL .= ', Venue.post_title AS venue_title';
265 265
                     break;
266 266
                 case 'city':
267
-                    $SQL .= ', ' . EEM_Venue::instance()->second_table() . '.VNU_city';
267
+                    $SQL .= ', '.EEM_Venue::instance()->second_table().'.VNU_city';
268 268
                     break;
269 269
                 case 'state':
270
-                    $SQL .= ', ' . EEM_State::instance()->table() . '.STA_name';
270
+                    $SQL .= ', '.EEM_State::instance()->table().'.STA_name';
271 271
                     break;
272 272
             }
273 273
         }
@@ -307,12 +307,12 @@  discard block
 block discarded – undo
307 307
      */
308 308
     public static function posts_join_sql_for_show_expired($SQL = '', $show_expired = false)
309 309
     {
310
-        if (! $show_expired) {
311
-            $join = EEM_Event::instance()->table() . '.ID = ';
312
-            $join .= EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name();
310
+        if ( ! $show_expired) {
311
+            $join = EEM_Event::instance()->table().'.ID = ';
312
+            $join .= EEM_Datetime::instance()->table().'.'.EEM_Event::instance()->primary_key_name();
313 313
             // don't add if this is already in the SQL
314 314
             if (strpos($SQL, $join) === false) {
315
-                $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' ) ';
315
+                $SQL .= ' INNER JOIN '.EEM_Datetime::instance()->table().' ON ( '.$join.' ) ';
316 316
             }
317 317
         }
318 318
         return $SQL;
@@ -327,7 +327,7 @@  discard block
 block discarded – undo
327 327
      */
328 328
     public static function posts_join_sql_for_terms($SQL = '', $join_terms = '')
329 329
     {
330
-        if (! empty($join_terms)) {
330
+        if ( ! empty($join_terms)) {
331 331
             global $wpdb;
332 332
             $SQL .= " LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)";
333 333
             $SQL .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)";
@@ -356,13 +356,13 @@  discard block
 block discarded – undo
356 356
                 case 'ticket_end':
357 357
                     $SQL .= EEH_Event_Query::_posts_join_for_datetime(
358 358
                         $SQL,
359
-                        EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Datetime::instance()->primary_key_name()
359
+                        EEM_Datetime_Ticket::instance()->table().'.'.EEM_Datetime::instance()->primary_key_name()
360 360
                     );
361
-                    $SQL .= ' LEFT JOIN ' . EEM_Ticket::instance()->table();
361
+                    $SQL .= ' LEFT JOIN '.EEM_Ticket::instance()->table();
362 362
                     $SQL .= ' ON (';
363
-                    $SQL .= EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name();
363
+                    $SQL .= EEM_Datetime_Ticket::instance()->table().'.'.EEM_Ticket::instance()->primary_key_name();
364 364
                     $SQL .= ' = ';
365
-                    $SQL .= EEM_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name();
365
+                    $SQL .= EEM_Ticket::instance()->table().'.'.EEM_Ticket::instance()->primary_key_name();
366 366
                     $SQL .= ' )';
367 367
                     break;
368 368
                 case 'venue_title':
@@ -375,7 +375,7 @@  discard block
 block discarded – undo
375 375
                     break;
376 376
                 case 'start_date':
377 377
                 default:
378
-                    $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table() . '.ID');
378
+                    $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table().'.ID');
379 379
                     break;
380 380
             }
381 381
         }
@@ -394,10 +394,10 @@  discard block
 block discarded – undo
394 394
      */
395 395
     protected static function _posts_join_for_datetime($SQL = '', $join = '')
396 396
     {
397
-        if (! empty($join)) {
398
-            $join .= ' = ' . EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name();
397
+        if ( ! empty($join)) {
398
+            $join .= ' = '.EEM_Datetime::instance()->table().'.'.EEM_Event::instance()->primary_key_name();
399 399
             if (strpos($SQL, $join) === false) {
400
-                return ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' )';
400
+                return ' INNER JOIN '.EEM_Datetime::instance()->table().' ON ( '.$join.' )';
401 401
             }
402 402
         }
403 403
         return '';
@@ -417,8 +417,8 @@  discard block
 block discarded – undo
417 417
         // Event Venue table name
418 418
         $event_venue_table = EEM_Event_Venue::instance()->table();
419 419
         // generate conditions for:  Event <=> Event Venue  JOIN clause
420
-        $event_to_event_venue_join = EEM_Event::instance()->table() . '.ID = ';
421
-        $event_to_event_venue_join .= $event_venue_table . '.' . EEM_Event::instance()->primary_key_name();
420
+        $event_to_event_venue_join = EEM_Event::instance()->table().'.ID = ';
421
+        $event_to_event_venue_join .= $event_venue_table.'.'.EEM_Event::instance()->primary_key_name();
422 422
         // don't add joins if they have already been added
423 423
         if (strpos($SQL, $event_to_event_venue_join) === false) {
424 424
             // Venue table name
@@ -506,7 +506,7 @@  discard block
 block discarded – undo
506 506
     public static function posts_where_sql_for_show_expired($show_expired = false)
507 507
     {
508 508
         return ! $show_expired
509
-            ? ' AND ' . EEM_Datetime::instance()->table() . '.DTT_EVT_end > \'' . current_time('mysql', true) . '\' '
509
+            ? ' AND '.EEM_Datetime::instance()->table().'.DTT_EVT_end > \''.current_time('mysql', true).'\' '
510 510
             : '';
511 511
     }
512 512
 
@@ -518,7 +518,7 @@  discard block
 block discarded – undo
518 518
     public static function posts_where_sql_for_event_category_slug($event_category_slug = null)
519 519
     {
520 520
         global $wpdb;
521
-        if (! empty($event_category_slug)) {
521
+        if ( ! empty($event_category_slug)) {
522 522
             $event_category_slugs_array   = array_map('trim', explode(',', $event_category_slug));
523 523
             $event_category_slugs_prepare = implode(', ', array_fill(0, count($event_category_slugs_array), '%s'));
524 524
             return $wpdb->prepare(
@@ -541,14 +541,14 @@  discard block
 block discarded – undo
541 541
     public static function posts_where_sql_for_event_list_month($month = null)
542 542
     {
543 543
         $SQL = '';
544
-        if (! empty($month)) {
544
+        if ( ! empty($month)) {
545 545
             $datetime_table = EEM_Datetime::instance()->table();
546 546
             // event start date is LESS than the end of the month ( so nothing that doesn't start until next month )
547 547
             $SQL = " AND {$datetime_table}.DTT_EVT_start <= '";
548
-            $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month)) . "'";
548
+            $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month))."'";
549 549
             // event end date is GREATER than the start of the month ( so nothing that ended before this month )
550 550
             $SQL .= " AND {$datetime_table}.DTT_EVT_end >= '";
551
-            $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month)) . "' ";
551
+            $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month))."' ";
552 552
         }
553 553
         return $SQL;
554 554
     }
@@ -609,15 +609,15 @@  discard block
 block discarded – undo
609 609
             ? strtoupper($sort)
610 610
             : 'ASC';
611 611
         // make sure 'orderby' is set in query params
612
-        if (! isset(self::$_query_params['orderby'])) {
612
+        if ( ! isset(self::$_query_params['orderby'])) {
613 613
             self::$_query_params['orderby'] = [];
614 614
         }
615 615
         // loop thru $orderby_params (type cast as array)
616 616
         foreach ($orderby_params as $orderby) {
617 617
             // check if we have already added this param
618
-            if (isset(self::$_query_params['orderby'][ $orderby ])) {
618
+            if (isset(self::$_query_params['orderby'][$orderby])) {
619 619
                 // if so then remove from the $orderby_params so that the count() method below is accurate
620
-                unset($orderby_params[ $orderby ]);
620
+                unset($orderby_params[$orderby]);
621 621
                 // then bump ahead to the next param
622 622
                 continue;
623 623
             }
@@ -627,39 +627,39 @@  discard block
 block discarded – undo
627 627
             switch ($orderby) {
628 628
                 case 'id':
629 629
                 case 'ID':
630
-                    $SQL .= $glue . $wpdb->posts . '.ID ' . $sort;
630
+                    $SQL .= $glue.$wpdb->posts.'.ID '.$sort;
631 631
                     break;
632 632
                 case 'end_date':
633
-                    $SQL .= $glue . EEM_Datetime::instance()->table() . '.DTT_EVT_end ' . $sort;
633
+                    $SQL .= $glue.EEM_Datetime::instance()->table().'.DTT_EVT_end '.$sort;
634 634
                     break;
635 635
                 case 'event_name':
636
-                    $SQL .= $glue . $wpdb->posts . '.post_title ' . $sort;
636
+                    $SQL .= $glue.$wpdb->posts.'.post_title '.$sort;
637 637
                     break;
638 638
                 case 'category_slug':
639
-                    $SQL .= $glue . $wpdb->terms . '.slug ' . $sort;
639
+                    $SQL .= $glue.$wpdb->terms.'.slug '.$sort;
640 640
                     break;
641 641
                 case 'ticket_start':
642
-                    $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_start_date ' . $sort;
642
+                    $SQL .= $glue.EEM_Ticket::instance()->table().'.TKT_start_date '.$sort;
643 643
                     break;
644 644
                 case 'ticket_end':
645
-                    $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_end_date ' . $sort;
645
+                    $SQL .= $glue.EEM_Ticket::instance()->table().'.TKT_end_date '.$sort;
646 646
                     break;
647 647
                 case 'venue_title':
648
-                    $SQL .= $glue . 'venue_title ' . $sort;
648
+                    $SQL .= $glue.'venue_title '.$sort;
649 649
                     break;
650 650
                 case 'city':
651
-                    $SQL .= $glue . EEM_Venue::instance()->second_table() . '.VNU_city ' . $sort;
651
+                    $SQL .= $glue.EEM_Venue::instance()->second_table().'.VNU_city '.$sort;
652 652
                     break;
653 653
                 case 'state':
654
-                    $SQL .= $glue . EEM_State::instance()->table() . '.STA_name ' . $sort;
654
+                    $SQL .= $glue.EEM_State::instance()->table().'.STA_name '.$sort;
655 655
                     break;
656 656
                 case 'start_date':
657 657
                 default:
658
-                    $SQL .= $glue . ' event_start_date ' . $sort;
658
+                    $SQL .= $glue.' event_start_date '.$sort;
659 659
                     break;
660 660
             }
661 661
             // add to array of orderby params that have been added
662
-            self::$_query_params['orderby'][ $orderby ] = true;
662
+            self::$_query_params['orderby'][$orderby] = true;
663 663
             $counter++;
664 664
         }
665 665
         return $SQL;
Please login to merge, or discard this patch.
Indentation   +662 added lines, -662 removed lines patch added patch discarded remove patch
@@ -17,666 +17,666 @@
 block discarded – undo
17 17
  */
18 18
 class EEH_Event_Query
19 19
 {
20
-    /**
21
-     * Start Date
22
-     *
23
-     * @var $_event_query_month
24
-     */
25
-    protected static $_event_query_month;
26
-
27
-    /**
28
-     * Category
29
-     *
30
-     * @var $_event_query_category
31
-     */
32
-    protected static $_event_query_category;
33
-
34
-    /**
35
-     * whether to display expired events in the event list
36
-     *
37
-     * @var bool $_show_expired
38
-     */
39
-    protected static $_event_query_show_expired = false;
40
-
41
-    /**
42
-     * list of params for controlling how the query results are ordered
43
-     *
44
-     * @var array $_event_query_orderby
45
-     */
46
-    protected static $_event_query_orderby = [];
47
-
48
-    /**
49
-     * direction list is sorted
50
-     *
51
-     * @var string $_event_query_sort
52
-     */
53
-    protected static $_event_query_sort;
54
-
55
-    /**
56
-     * list of params used to build the query's various clauses
57
-     *
58
-     * @var $_query_params
59
-     */
60
-    protected static $_query_params = [];
61
-
62
-
63
-    /**
64
-     * @return void
65
-     */
66
-    public static function add_query_filters()
67
-    {
68
-        // add query filters
69
-        add_action('pre_get_posts', ['EEH_Event_Query', 'filter_query_parts'], 10, 1);
70
-    }
71
-
72
-
73
-    /**
74
-     * @param WP_Query $WP_Query
75
-     * @return bool
76
-     */
77
-    public static function apply_query_filters(WP_Query $WP_Query)
78
-    {
79
-        return (
80
-                   isset($WP_Query->query['post_type'])
81
-                   && $WP_Query->query['post_type'] === 'espresso_events'
82
-               )
83
-               || apply_filters('FHEE__EEH_Event_Query__apply_query_filters', false);
84
-    }
85
-
86
-
87
-    /**
88
-     * @param WP_Query $WP_Query
89
-     */
90
-    public static function filter_query_parts(WP_Query $WP_Query)
91
-    {
92
-        // ONLY add our filters if this isn't the main wp_query,
93
-        // because if this is the main wp_query we already have
94
-        // our cpt strategies take care of adding things in.
95
-        if ($WP_Query instanceof WP_Query && ! $WP_Query->is_main_query()) {
96
-            // build event list query
97
-            add_filter('posts_fields', ['EEH_Event_Query', 'posts_fields'], 10, 2);
98
-            add_filter('posts_join', ['EEH_Event_Query', 'posts_join'], 10, 2);
99
-            add_filter('posts_where', ['EEH_Event_Query', 'posts_where'], 10, 2);
100
-            add_filter('posts_orderby', ['EEH_Event_Query', 'posts_orderby'], 10, 2);
101
-            add_filter('posts_clauses_request', ['EEH_Event_Query', 'posts_clauses'], 10, 2);
102
-        }
103
-    }
104
-
105
-
106
-    /**
107
-     * @param string $month
108
-     * @param string $category
109
-     * @param bool   $show_expired
110
-     * @param array|string $orderby
111
-     * @param string $sort
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     */
116
-    public static function set_query_params(
117
-        $month = '',
118
-        $category = '',
119
-        $show_expired = false,
120
-        $orderby = 'start_date',
121
-        $sort = 'ASC'
122
-    ) {
123
-        self::$_query_params                        = [];
124
-        EEH_Event_Query::$_event_query_month        = EEH_Event_Query::_display_month($month);
125
-        EEH_Event_Query::$_event_query_category     = EEH_Event_Query::_event_category_slug($category);
126
-        EEH_Event_Query::$_event_query_show_expired = EEH_Event_Query::_show_expired($show_expired);
127
-        EEH_Event_Query::$_event_query_orderby      = EEH_Event_Query::_orderby($orderby);
128
-        EEH_Event_Query::$_event_query_sort         = EEH_Event_Query::_sort($sort);
129
-    }
130
-
131
-
132
-    /**
133
-     * what month should the event list display events for?
134
-     *
135
-     * @param string $month
136
-     * @return string
137
-     * @throws InvalidArgumentException
138
-     * @throws InvalidDataTypeException
139
-     * @throws InvalidInterfaceException
140
-     */
141
-    private static function _display_month($month = '')
142
-    {
143
-        return self::getRequest()->getRequestParam('event_query_month', $month);
144
-    }
145
-
146
-
147
-    /**
148
-     * @param string $category
149
-     * @return string
150
-     * @throws InvalidArgumentException
151
-     * @throws InvalidDataTypeException
152
-     * @throws InvalidInterfaceException
153
-     */
154
-    private static function _event_category_slug($category = '')
155
-    {
156
-        return self::getRequest()->getRequestParam('event_query_category', $category);
157
-    }
158
-
159
-
160
-    /**
161
-     * @param bool $show_expired
162
-     * @return bool
163
-     * @throws InvalidArgumentException
164
-     * @throws InvalidDataTypeException
165
-     * @throws InvalidInterfaceException
166
-     */
167
-    private static function _show_expired($show_expired = false)
168
-    {
169
-        // override default expired option if set via filter
170
-        return self::getRequest()->getRequestParam('event_query_show_expired', $show_expired, 'bool');
171
-    }
172
-
173
-
174
-    /**
175
-     * @param array|string $orderby
176
-     * @return array
177
-     * @throws InvalidArgumentException
178
-     * @throws InvalidDataTypeException
179
-     * @throws InvalidInterfaceException
180
-     */
181
-    private static function _orderby($orderby = 'start_date')
182
-    {
183
-        $event_query_orderby = self::getRequest()->getRequestParam(
184
-            'event_query_orderby',
185
-            (array) $orderby,
186
-            DataType::STRING,
187
-            true
188
-        );
189
-        $event_query_orderby = is_array($event_query_orderby)
190
-            ? $event_query_orderby
191
-            : explode(',', $event_query_orderby);
192
-        $event_query_orderby = array_map('trim', $event_query_orderby);
193
-        return array_map('sanitize_text_field', $event_query_orderby);
194
-    }
195
-
196
-
197
-    /**
198
-     * @param string $sort
199
-     * @return string
200
-     * @throws InvalidArgumentException
201
-     * @throws InvalidDataTypeException
202
-     * @throws InvalidInterfaceException
203
-     */
204
-    private static function _sort($sort = 'ASC')
205
-    {
206
-        $sort = self::getRequest()->getRequestParam('event_query_sort', $sort);
207
-        return in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true)
208
-            ? strtoupper($sort)
209
-            : 'ASC';
210
-    }
211
-
212
-
213
-    /**
214
-     * Filters the clauses for the WP_Query object
215
-     *
216
-     * @param array    $clauses array of clauses
217
-     * @param WP_Query $wp_query
218
-     * @return array   array of clauses
219
-     */
220
-    public static function posts_clauses($clauses, WP_Query $wp_query)
221
-    {
222
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
223
-            global $wpdb;
224
-            $clauses['groupby'] = $wpdb->posts . '.ID ';
225
-        }
226
-        return $clauses;
227
-    }
228
-
229
-
230
-    /**
231
-     * @param string   $SQL
232
-     * @param WP_Query $wp_query
233
-     * @return string
234
-     * @throws EE_Error
235
-     * @throws InvalidArgumentException
236
-     * @throws InvalidDataTypeException
237
-     * @throws InvalidInterfaceException
238
-     */
239
-    public static function posts_fields($SQL, WP_Query $wp_query)
240
-    {
241
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
242
-            // adds something like ", wp_esp_datetime.* " to WP Query SELECT statement
243
-            $SQL .= EEH_Event_Query::posts_fields_sql_for_orderby(EEH_Event_Query::$_event_query_orderby);
244
-        }
245
-        return $SQL;
246
-    }
247
-
248
-
249
-    /**
250
-     * @param array $orderby_params
251
-     * @return string
252
-     * @throws EE_Error
253
-     * @throws InvalidArgumentException
254
-     * @throws InvalidDataTypeException
255
-     * @throws InvalidInterfaceException
256
-     */
257
-    public static function posts_fields_sql_for_orderby(array $orderby_params = [])
258
-    {
259
-        $SQL = ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date ';
260
-        foreach ($orderby_params as $orderby) {
261
-            switch ($orderby) {
262
-                case 'ticket_start':
263
-                    $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_start_date';
264
-                    break;
265
-                case 'ticket_end':
266
-                    $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_end_date';
267
-                    break;
268
-                case 'venue_title':
269
-                    $SQL .= ', Venue.post_title AS venue_title';
270
-                    break;
271
-                case 'city':
272
-                    $SQL .= ', ' . EEM_Venue::instance()->second_table() . '.VNU_city';
273
-                    break;
274
-                case 'state':
275
-                    $SQL .= ', ' . EEM_State::instance()->table() . '.STA_name';
276
-                    break;
277
-            }
278
-        }
279
-        return $SQL;
280
-    }
281
-
282
-
283
-    /**
284
-     * @param string   $SQL
285
-     * @param WP_Query $wp_query
286
-     * @return string
287
-     * @throws EE_Error
288
-     * @throws InvalidArgumentException
289
-     * @throws InvalidDataTypeException
290
-     * @throws InvalidInterfaceException
291
-     */
292
-    public static function posts_join($SQL, WP_Query $wp_query)
293
-    {
294
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
295
-            // Category
296
-            $SQL = EEH_Event_Query::posts_join_sql_for_show_expired($SQL, EEH_Event_Query::$_event_query_show_expired);
297
-            $SQL = EEH_Event_Query::posts_join_sql_for_terms($SQL, EEH_Event_Query::$_event_query_category);
298
-            $SQL = EEH_Event_Query::posts_join_for_orderby($SQL, EEH_Event_Query::$_event_query_orderby);
299
-        }
300
-        return $SQL;
301
-    }
302
-
303
-
304
-    /**
305
-     * @param string  $SQL
306
-     * @param boolean $show_expired if TRUE, then displayed past events
307
-     * @return string
308
-     * @throws EE_Error
309
-     * @throws InvalidArgumentException
310
-     * @throws InvalidDataTypeException
311
-     * @throws InvalidInterfaceException
312
-     */
313
-    public static function posts_join_sql_for_show_expired($SQL = '', $show_expired = false)
314
-    {
315
-        if (! $show_expired) {
316
-            $join = EEM_Event::instance()->table() . '.ID = ';
317
-            $join .= EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name();
318
-            // don't add if this is already in the SQL
319
-            if (strpos($SQL, $join) === false) {
320
-                $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' ) ';
321
-            }
322
-        }
323
-        return $SQL;
324
-    }
325
-
326
-
327
-    /**
328
-     * @param string $SQL
329
-     * @param string $join_terms    pass TRUE or term string, doesn't really matter since this value doesn't really get
330
-     *                              used for anything yet
331
-     * @return string
332
-     */
333
-    public static function posts_join_sql_for_terms($SQL = '', $join_terms = '')
334
-    {
335
-        if (! empty($join_terms)) {
336
-            global $wpdb;
337
-            $SQL .= " LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)";
338
-            $SQL .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)";
339
-            $SQL .= " LEFT JOIN $wpdb->terms ON ($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id) ";
340
-        }
341
-        return $SQL;
342
-    }
343
-
344
-
345
-    /**
346
-     * usage:  $SQL .= EEH_Event_Query::posts_join_for_orderby( $orderby_params );
347
-     *
348
-     * @param string $SQL
349
-     * @param array  $orderby_params
350
-     * @return string
351
-     * @throws EE_Error
352
-     * @throws InvalidArgumentException
353
-     * @throws InvalidDataTypeException
354
-     * @throws InvalidInterfaceException
355
-     */
356
-    public static function posts_join_for_orderby($SQL = '', array $orderby_params = [])
357
-    {
358
-        foreach ($orderby_params as $orderby) {
359
-            switch ($orderby) {
360
-                case 'ticket_start':
361
-                case 'ticket_end':
362
-                    $SQL .= EEH_Event_Query::_posts_join_for_datetime(
363
-                        $SQL,
364
-                        EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Datetime::instance()->primary_key_name()
365
-                    );
366
-                    $SQL .= ' LEFT JOIN ' . EEM_Ticket::instance()->table();
367
-                    $SQL .= ' ON (';
368
-                    $SQL .= EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name();
369
-                    $SQL .= ' = ';
370
-                    $SQL .= EEM_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name();
371
-                    $SQL .= ' )';
372
-                    break;
373
-                case 'venue_title':
374
-                case 'city':
375
-                    $SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL);
376
-                    break;
377
-                case 'state':
378
-                    $SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL);
379
-                    $SQL .= EEH_Event_Query::_posts_join_for_venue_state($SQL);
380
-                    break;
381
-                case 'start_date':
382
-                default:
383
-                    $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table() . '.ID');
384
-                    break;
385
-            }
386
-        }
387
-        return $SQL;
388
-    }
389
-
390
-
391
-    /**
392
-     * @param string $SQL
393
-     * @param string $join
394
-     * @return string
395
-     * @throws EE_Error
396
-     * @throws InvalidArgumentException
397
-     * @throws InvalidDataTypeException
398
-     * @throws InvalidInterfaceException
399
-     */
400
-    protected static function _posts_join_for_datetime($SQL = '', $join = '')
401
-    {
402
-        if (! empty($join)) {
403
-            $join .= ' = ' . EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name();
404
-            if (strpos($SQL, $join) === false) {
405
-                return ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' )';
406
-            }
407
-        }
408
-        return '';
409
-    }
410
-
411
-
412
-    /**
413
-     * @param string $SQL
414
-     * @return string
415
-     * @throws EE_Error
416
-     * @throws InvalidArgumentException
417
-     * @throws InvalidDataTypeException
418
-     * @throws InvalidInterfaceException
419
-     */
420
-    protected static function _posts_join_for_event_venue($SQL = '')
421
-    {
422
-        // Event Venue table name
423
-        $event_venue_table = EEM_Event_Venue::instance()->table();
424
-        // generate conditions for:  Event <=> Event Venue  JOIN clause
425
-        $event_to_event_venue_join = EEM_Event::instance()->table() . '.ID = ';
426
-        $event_to_event_venue_join .= $event_venue_table . '.' . EEM_Event::instance()->primary_key_name();
427
-        // don't add joins if they have already been added
428
-        if (strpos($SQL, $event_to_event_venue_join) === false) {
429
-            // Venue table name
430
-            $venue_table = EEM_Venue::instance()->table();
431
-            // Venue table pk
432
-            $venue_table_pk = EEM_Venue::instance()->primary_key_name();
433
-            // Venue Meta table name
434
-            $venue_meta_table = EEM_Venue::instance()->second_table();
435
-            // generate JOIN clause for: Event <=> Event Venue
436
-            $venue_SQL = " LEFT JOIN $event_venue_table ON ( $event_to_event_venue_join )";
437
-            // generate JOIN clause for: Event Venue <=> Venue
438
-            $venue_SQL .= " LEFT JOIN $venue_table as Venue ON ( $event_venue_table.$venue_table_pk = Venue.ID )";
439
-            // generate JOIN clause for: Venue <=> Venue Meta
440
-            $venue_SQL .= " LEFT JOIN $venue_meta_table ON ( Venue.ID = $venue_meta_table.$venue_table_pk )";
441
-            unset($event_venue_table, $event_to_event_venue_join, $venue_table, $venue_table_pk, $venue_meta_table);
442
-            return $venue_SQL;
443
-        }
444
-        unset($event_venue_table, $event_to_event_venue_join);
445
-        return '';
446
-    }
447
-
448
-
449
-    /**
450
-     * @param string $SQL
451
-     * @return string
452
-     * @throws EE_Error
453
-     * @throws InvalidArgumentException
454
-     * @throws InvalidDataTypeException
455
-     * @throws InvalidInterfaceException
456
-     */
457
-    protected static function _posts_join_for_venue_state($SQL = '')
458
-    {
459
-        // Venue Meta table name
460
-        $venue_meta_table = EEM_Venue::instance()->second_table();
461
-        // State table name
462
-        $state_table = EEM_State::instance()->table();
463
-        // State table pk
464
-        $state_table_pk = EEM_State::instance()->primary_key_name();
465
-        // verify vars
466
-        if ($venue_meta_table && $state_table && $state_table_pk) {
467
-            // like: wp_esp_venue_meta.STA_ID = wp_esp_state.STA_ID
468
-            $join = "$venue_meta_table.$state_table_pk = $state_table.$state_table_pk";
469
-            // don't add join if it has already been added
470
-            if (strpos($SQL, $join) === false) {
471
-                unset($state_table_pk, $venue_meta_table, $venue_table_pk);
472
-                return " LEFT JOIN $state_table ON ( $join )";
473
-            }
474
-        }
475
-        unset($join, $state_table, $state_table_pk, $venue_meta_table, $venue_table_pk);
476
-        return '';
477
-    }
478
-
479
-
480
-    /**
481
-     * @param string   $SQL
482
-     * @param WP_Query $wp_query
483
-     * @return string
484
-     * @throws EE_Error
485
-     * @throws InvalidArgumentException
486
-     * @throws InvalidDataTypeException
487
-     * @throws InvalidInterfaceException
488
-     */
489
-    public static function posts_where($SQL, WP_Query $wp_query)
490
-    {
491
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
492
-            // Show Expired ?
493
-            $SQL .= EEH_Event_Query::posts_where_sql_for_show_expired(EEH_Event_Query::$_event_query_show_expired);
494
-            // Category
495
-            $SQL .= EEH_Event_Query::posts_where_sql_for_event_category_slug(EEH_Event_Query::$_event_query_category);
496
-            // Start Date
497
-            $SQL .= EEH_Event_Query::posts_where_sql_for_event_list_month(EEH_Event_Query::$_event_query_month);
498
-        }
499
-        return $SQL;
500
-    }
501
-
502
-
503
-    /**
504
-     * @param boolean $show_expired if TRUE, then displayed past events
505
-     * @return string
506
-     * @throws EE_Error
507
-     * @throws InvalidArgumentException
508
-     * @throws InvalidDataTypeException
509
-     * @throws InvalidInterfaceException
510
-     */
511
-    public static function posts_where_sql_for_show_expired($show_expired = false)
512
-    {
513
-        return ! $show_expired
514
-            ? ' AND ' . EEM_Datetime::instance()->table() . '.DTT_EVT_end > \'' . current_time('mysql', true) . '\' '
515
-            : '';
516
-    }
517
-
518
-
519
-    /**
520
-     * @param boolean $event_category_slug
521
-     * @return string
522
-     */
523
-    public static function posts_where_sql_for_event_category_slug($event_category_slug = null)
524
-    {
525
-        global $wpdb;
526
-        if (! empty($event_category_slug)) {
527
-            $event_category_slugs_array   = array_map('trim', explode(',', $event_category_slug));
528
-            $event_category_slugs_prepare = implode(', ', array_fill(0, count($event_category_slugs_array), '%s'));
529
-            return $wpdb->prepare(
530
-                " AND {$wpdb->terms}.slug IN ({$event_category_slugs_prepare}) ",
531
-                $event_category_slugs_array
532
-            );
533
-        }
534
-        return '';
535
-    }
536
-
537
-
538
-    /**
539
-     * @param boolean $month
540
-     * @return string
541
-     * @throws EE_Error
542
-     * @throws InvalidArgumentException
543
-     * @throws InvalidDataTypeException
544
-     * @throws InvalidInterfaceException
545
-     */
546
-    public static function posts_where_sql_for_event_list_month($month = null)
547
-    {
548
-        $SQL = '';
549
-        if (! empty($month)) {
550
-            $datetime_table = EEM_Datetime::instance()->table();
551
-            // event start date is LESS than the end of the month ( so nothing that doesn't start until next month )
552
-            $SQL = " AND {$datetime_table}.DTT_EVT_start <= '";
553
-            $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month)) . "'";
554
-            // event end date is GREATER than the start of the month ( so nothing that ended before this month )
555
-            $SQL .= " AND {$datetime_table}.DTT_EVT_end >= '";
556
-            $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month)) . "' ";
557
-        }
558
-        return $SQL;
559
-    }
560
-
561
-
562
-    /**
563
-     * @param string   $SQL
564
-     * @param WP_Query $wp_query
565
-     * @return string
566
-     * @throws EE_Error
567
-     * @throws InvalidArgumentException
568
-     * @throws InvalidDataTypeException
569
-     * @throws InvalidInterfaceException
570
-     */
571
-    public static function posts_orderby($SQL, WP_Query $wp_query)
572
-    {
573
-        if (EEH_Event_Query::apply_query_filters($wp_query)) {
574
-            $SQL = EEH_Event_Query::posts_orderby_sql(
575
-                EEH_Event_Query::$_event_query_orderby,
576
-                EEH_Event_Query::$_event_query_sort
577
-            );
578
-        }
579
-        return $SQL;
580
-    }
581
-
582
-
583
-    /**
584
-     *    posts_orderby_sql
585
-     *    possible parameters:
586
-     *    ID
587
-     *    start_date
588
-     *    end_date
589
-     *    event_name
590
-     *    category_slug
591
-     *    ticket_start
592
-     *    ticket_end
593
-     *    venue_title
594
-     *    city
595
-     *    state
596
-     *    **IMPORTANT**
597
-     *    make sure to also send the $orderby_params array to the posts_join_for_orderby() method
598
-     *    or else some of the table references below will result in MySQL errors
599
-     *
600
-     * @param array  $orderby_params
601
-     * @param string $sort
602
-     * @return string
603
-     * @throws EE_Error
604
-     * @throws InvalidArgumentException
605
-     * @throws InvalidDataTypeException
606
-     * @throws InvalidInterfaceException
607
-     */
608
-    public static function posts_orderby_sql(array $orderby_params = [], $sort = 'ASC')
609
-    {
610
-        global $wpdb;
611
-        $SQL     = '';
612
-        $counter = 0;
613
-        $sort    = in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true)
614
-            ? strtoupper($sort)
615
-            : 'ASC';
616
-        // make sure 'orderby' is set in query params
617
-        if (! isset(self::$_query_params['orderby'])) {
618
-            self::$_query_params['orderby'] = [];
619
-        }
620
-        // loop thru $orderby_params (type cast as array)
621
-        foreach ($orderby_params as $orderby) {
622
-            // check if we have already added this param
623
-            if (isset(self::$_query_params['orderby'][ $orderby ])) {
624
-                // if so then remove from the $orderby_params so that the count() method below is accurate
625
-                unset($orderby_params[ $orderby ]);
626
-                // then bump ahead to the next param
627
-                continue;
628
-            }
629
-            // this will ad a comma depending on whether this is the first or last param
630
-            $glue = $counter === 0 || $counter === count($orderby_params) ? ' ' : ', ';
631
-            // ok what's we dealing with?
632
-            switch ($orderby) {
633
-                case 'id':
634
-                case 'ID':
635
-                    $SQL .= $glue . $wpdb->posts . '.ID ' . $sort;
636
-                    break;
637
-                case 'end_date':
638
-                    $SQL .= $glue . EEM_Datetime::instance()->table() . '.DTT_EVT_end ' . $sort;
639
-                    break;
640
-                case 'event_name':
641
-                    $SQL .= $glue . $wpdb->posts . '.post_title ' . $sort;
642
-                    break;
643
-                case 'category_slug':
644
-                    $SQL .= $glue . $wpdb->terms . '.slug ' . $sort;
645
-                    break;
646
-                case 'ticket_start':
647
-                    $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_start_date ' . $sort;
648
-                    break;
649
-                case 'ticket_end':
650
-                    $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_end_date ' . $sort;
651
-                    break;
652
-                case 'venue_title':
653
-                    $SQL .= $glue . 'venue_title ' . $sort;
654
-                    break;
655
-                case 'city':
656
-                    $SQL .= $glue . EEM_Venue::instance()->second_table() . '.VNU_city ' . $sort;
657
-                    break;
658
-                case 'state':
659
-                    $SQL .= $glue . EEM_State::instance()->table() . '.STA_name ' . $sort;
660
-                    break;
661
-                case 'start_date':
662
-                default:
663
-                    $SQL .= $glue . ' event_start_date ' . $sort;
664
-                    break;
665
-            }
666
-            // add to array of orderby params that have been added
667
-            self::$_query_params['orderby'][ $orderby ] = true;
668
-            $counter++;
669
-        }
670
-        return $SQL;
671
-    }
672
-
673
-
674
-    /**
675
-     * @return RequestInterface
676
-     * @since   4.10.14.p
677
-     */
678
-    private static function getRequest()
679
-    {
680
-        return LoaderFactory::getLoader()->getShared(RequestInterface::class);
681
-    }
20
+	/**
21
+	 * Start Date
22
+	 *
23
+	 * @var $_event_query_month
24
+	 */
25
+	protected static $_event_query_month;
26
+
27
+	/**
28
+	 * Category
29
+	 *
30
+	 * @var $_event_query_category
31
+	 */
32
+	protected static $_event_query_category;
33
+
34
+	/**
35
+	 * whether to display expired events in the event list
36
+	 *
37
+	 * @var bool $_show_expired
38
+	 */
39
+	protected static $_event_query_show_expired = false;
40
+
41
+	/**
42
+	 * list of params for controlling how the query results are ordered
43
+	 *
44
+	 * @var array $_event_query_orderby
45
+	 */
46
+	protected static $_event_query_orderby = [];
47
+
48
+	/**
49
+	 * direction list is sorted
50
+	 *
51
+	 * @var string $_event_query_sort
52
+	 */
53
+	protected static $_event_query_sort;
54
+
55
+	/**
56
+	 * list of params used to build the query's various clauses
57
+	 *
58
+	 * @var $_query_params
59
+	 */
60
+	protected static $_query_params = [];
61
+
62
+
63
+	/**
64
+	 * @return void
65
+	 */
66
+	public static function add_query_filters()
67
+	{
68
+		// add query filters
69
+		add_action('pre_get_posts', ['EEH_Event_Query', 'filter_query_parts'], 10, 1);
70
+	}
71
+
72
+
73
+	/**
74
+	 * @param WP_Query $WP_Query
75
+	 * @return bool
76
+	 */
77
+	public static function apply_query_filters(WP_Query $WP_Query)
78
+	{
79
+		return (
80
+				   isset($WP_Query->query['post_type'])
81
+				   && $WP_Query->query['post_type'] === 'espresso_events'
82
+			   )
83
+			   || apply_filters('FHEE__EEH_Event_Query__apply_query_filters', false);
84
+	}
85
+
86
+
87
+	/**
88
+	 * @param WP_Query $WP_Query
89
+	 */
90
+	public static function filter_query_parts(WP_Query $WP_Query)
91
+	{
92
+		// ONLY add our filters if this isn't the main wp_query,
93
+		// because if this is the main wp_query we already have
94
+		// our cpt strategies take care of adding things in.
95
+		if ($WP_Query instanceof WP_Query && ! $WP_Query->is_main_query()) {
96
+			// build event list query
97
+			add_filter('posts_fields', ['EEH_Event_Query', 'posts_fields'], 10, 2);
98
+			add_filter('posts_join', ['EEH_Event_Query', 'posts_join'], 10, 2);
99
+			add_filter('posts_where', ['EEH_Event_Query', 'posts_where'], 10, 2);
100
+			add_filter('posts_orderby', ['EEH_Event_Query', 'posts_orderby'], 10, 2);
101
+			add_filter('posts_clauses_request', ['EEH_Event_Query', 'posts_clauses'], 10, 2);
102
+		}
103
+	}
104
+
105
+
106
+	/**
107
+	 * @param string $month
108
+	 * @param string $category
109
+	 * @param bool   $show_expired
110
+	 * @param array|string $orderby
111
+	 * @param string $sort
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 */
116
+	public static function set_query_params(
117
+		$month = '',
118
+		$category = '',
119
+		$show_expired = false,
120
+		$orderby = 'start_date',
121
+		$sort = 'ASC'
122
+	) {
123
+		self::$_query_params                        = [];
124
+		EEH_Event_Query::$_event_query_month        = EEH_Event_Query::_display_month($month);
125
+		EEH_Event_Query::$_event_query_category     = EEH_Event_Query::_event_category_slug($category);
126
+		EEH_Event_Query::$_event_query_show_expired = EEH_Event_Query::_show_expired($show_expired);
127
+		EEH_Event_Query::$_event_query_orderby      = EEH_Event_Query::_orderby($orderby);
128
+		EEH_Event_Query::$_event_query_sort         = EEH_Event_Query::_sort($sort);
129
+	}
130
+
131
+
132
+	/**
133
+	 * what month should the event list display events for?
134
+	 *
135
+	 * @param string $month
136
+	 * @return string
137
+	 * @throws InvalidArgumentException
138
+	 * @throws InvalidDataTypeException
139
+	 * @throws InvalidInterfaceException
140
+	 */
141
+	private static function _display_month($month = '')
142
+	{
143
+		return self::getRequest()->getRequestParam('event_query_month', $month);
144
+	}
145
+
146
+
147
+	/**
148
+	 * @param string $category
149
+	 * @return string
150
+	 * @throws InvalidArgumentException
151
+	 * @throws InvalidDataTypeException
152
+	 * @throws InvalidInterfaceException
153
+	 */
154
+	private static function _event_category_slug($category = '')
155
+	{
156
+		return self::getRequest()->getRequestParam('event_query_category', $category);
157
+	}
158
+
159
+
160
+	/**
161
+	 * @param bool $show_expired
162
+	 * @return bool
163
+	 * @throws InvalidArgumentException
164
+	 * @throws InvalidDataTypeException
165
+	 * @throws InvalidInterfaceException
166
+	 */
167
+	private static function _show_expired($show_expired = false)
168
+	{
169
+		// override default expired option if set via filter
170
+		return self::getRequest()->getRequestParam('event_query_show_expired', $show_expired, 'bool');
171
+	}
172
+
173
+
174
+	/**
175
+	 * @param array|string $orderby
176
+	 * @return array
177
+	 * @throws InvalidArgumentException
178
+	 * @throws InvalidDataTypeException
179
+	 * @throws InvalidInterfaceException
180
+	 */
181
+	private static function _orderby($orderby = 'start_date')
182
+	{
183
+		$event_query_orderby = self::getRequest()->getRequestParam(
184
+			'event_query_orderby',
185
+			(array) $orderby,
186
+			DataType::STRING,
187
+			true
188
+		);
189
+		$event_query_orderby = is_array($event_query_orderby)
190
+			? $event_query_orderby
191
+			: explode(',', $event_query_orderby);
192
+		$event_query_orderby = array_map('trim', $event_query_orderby);
193
+		return array_map('sanitize_text_field', $event_query_orderby);
194
+	}
195
+
196
+
197
+	/**
198
+	 * @param string $sort
199
+	 * @return string
200
+	 * @throws InvalidArgumentException
201
+	 * @throws InvalidDataTypeException
202
+	 * @throws InvalidInterfaceException
203
+	 */
204
+	private static function _sort($sort = 'ASC')
205
+	{
206
+		$sort = self::getRequest()->getRequestParam('event_query_sort', $sort);
207
+		return in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true)
208
+			? strtoupper($sort)
209
+			: 'ASC';
210
+	}
211
+
212
+
213
+	/**
214
+	 * Filters the clauses for the WP_Query object
215
+	 *
216
+	 * @param array    $clauses array of clauses
217
+	 * @param WP_Query $wp_query
218
+	 * @return array   array of clauses
219
+	 */
220
+	public static function posts_clauses($clauses, WP_Query $wp_query)
221
+	{
222
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
223
+			global $wpdb;
224
+			$clauses['groupby'] = $wpdb->posts . '.ID ';
225
+		}
226
+		return $clauses;
227
+	}
228
+
229
+
230
+	/**
231
+	 * @param string   $SQL
232
+	 * @param WP_Query $wp_query
233
+	 * @return string
234
+	 * @throws EE_Error
235
+	 * @throws InvalidArgumentException
236
+	 * @throws InvalidDataTypeException
237
+	 * @throws InvalidInterfaceException
238
+	 */
239
+	public static function posts_fields($SQL, WP_Query $wp_query)
240
+	{
241
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
242
+			// adds something like ", wp_esp_datetime.* " to WP Query SELECT statement
243
+			$SQL .= EEH_Event_Query::posts_fields_sql_for_orderby(EEH_Event_Query::$_event_query_orderby);
244
+		}
245
+		return $SQL;
246
+	}
247
+
248
+
249
+	/**
250
+	 * @param array $orderby_params
251
+	 * @return string
252
+	 * @throws EE_Error
253
+	 * @throws InvalidArgumentException
254
+	 * @throws InvalidDataTypeException
255
+	 * @throws InvalidInterfaceException
256
+	 */
257
+	public static function posts_fields_sql_for_orderby(array $orderby_params = [])
258
+	{
259
+		$SQL = ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date ';
260
+		foreach ($orderby_params as $orderby) {
261
+			switch ($orderby) {
262
+				case 'ticket_start':
263
+					$SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_start_date';
264
+					break;
265
+				case 'ticket_end':
266
+					$SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_end_date';
267
+					break;
268
+				case 'venue_title':
269
+					$SQL .= ', Venue.post_title AS venue_title';
270
+					break;
271
+				case 'city':
272
+					$SQL .= ', ' . EEM_Venue::instance()->second_table() . '.VNU_city';
273
+					break;
274
+				case 'state':
275
+					$SQL .= ', ' . EEM_State::instance()->table() . '.STA_name';
276
+					break;
277
+			}
278
+		}
279
+		return $SQL;
280
+	}
281
+
282
+
283
+	/**
284
+	 * @param string   $SQL
285
+	 * @param WP_Query $wp_query
286
+	 * @return string
287
+	 * @throws EE_Error
288
+	 * @throws InvalidArgumentException
289
+	 * @throws InvalidDataTypeException
290
+	 * @throws InvalidInterfaceException
291
+	 */
292
+	public static function posts_join($SQL, WP_Query $wp_query)
293
+	{
294
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
295
+			// Category
296
+			$SQL = EEH_Event_Query::posts_join_sql_for_show_expired($SQL, EEH_Event_Query::$_event_query_show_expired);
297
+			$SQL = EEH_Event_Query::posts_join_sql_for_terms($SQL, EEH_Event_Query::$_event_query_category);
298
+			$SQL = EEH_Event_Query::posts_join_for_orderby($SQL, EEH_Event_Query::$_event_query_orderby);
299
+		}
300
+		return $SQL;
301
+	}
302
+
303
+
304
+	/**
305
+	 * @param string  $SQL
306
+	 * @param boolean $show_expired if TRUE, then displayed past events
307
+	 * @return string
308
+	 * @throws EE_Error
309
+	 * @throws InvalidArgumentException
310
+	 * @throws InvalidDataTypeException
311
+	 * @throws InvalidInterfaceException
312
+	 */
313
+	public static function posts_join_sql_for_show_expired($SQL = '', $show_expired = false)
314
+	{
315
+		if (! $show_expired) {
316
+			$join = EEM_Event::instance()->table() . '.ID = ';
317
+			$join .= EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name();
318
+			// don't add if this is already in the SQL
319
+			if (strpos($SQL, $join) === false) {
320
+				$SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' ) ';
321
+			}
322
+		}
323
+		return $SQL;
324
+	}
325
+
326
+
327
+	/**
328
+	 * @param string $SQL
329
+	 * @param string $join_terms    pass TRUE or term string, doesn't really matter since this value doesn't really get
330
+	 *                              used for anything yet
331
+	 * @return string
332
+	 */
333
+	public static function posts_join_sql_for_terms($SQL = '', $join_terms = '')
334
+	{
335
+		if (! empty($join_terms)) {
336
+			global $wpdb;
337
+			$SQL .= " LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)";
338
+			$SQL .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)";
339
+			$SQL .= " LEFT JOIN $wpdb->terms ON ($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id) ";
340
+		}
341
+		return $SQL;
342
+	}
343
+
344
+
345
+	/**
346
+	 * usage:  $SQL .= EEH_Event_Query::posts_join_for_orderby( $orderby_params );
347
+	 *
348
+	 * @param string $SQL
349
+	 * @param array  $orderby_params
350
+	 * @return string
351
+	 * @throws EE_Error
352
+	 * @throws InvalidArgumentException
353
+	 * @throws InvalidDataTypeException
354
+	 * @throws InvalidInterfaceException
355
+	 */
356
+	public static function posts_join_for_orderby($SQL = '', array $orderby_params = [])
357
+	{
358
+		foreach ($orderby_params as $orderby) {
359
+			switch ($orderby) {
360
+				case 'ticket_start':
361
+				case 'ticket_end':
362
+					$SQL .= EEH_Event_Query::_posts_join_for_datetime(
363
+						$SQL,
364
+						EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Datetime::instance()->primary_key_name()
365
+					);
366
+					$SQL .= ' LEFT JOIN ' . EEM_Ticket::instance()->table();
367
+					$SQL .= ' ON (';
368
+					$SQL .= EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name();
369
+					$SQL .= ' = ';
370
+					$SQL .= EEM_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name();
371
+					$SQL .= ' )';
372
+					break;
373
+				case 'venue_title':
374
+				case 'city':
375
+					$SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL);
376
+					break;
377
+				case 'state':
378
+					$SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL);
379
+					$SQL .= EEH_Event_Query::_posts_join_for_venue_state($SQL);
380
+					break;
381
+				case 'start_date':
382
+				default:
383
+					$SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table() . '.ID');
384
+					break;
385
+			}
386
+		}
387
+		return $SQL;
388
+	}
389
+
390
+
391
+	/**
392
+	 * @param string $SQL
393
+	 * @param string $join
394
+	 * @return string
395
+	 * @throws EE_Error
396
+	 * @throws InvalidArgumentException
397
+	 * @throws InvalidDataTypeException
398
+	 * @throws InvalidInterfaceException
399
+	 */
400
+	protected static function _posts_join_for_datetime($SQL = '', $join = '')
401
+	{
402
+		if (! empty($join)) {
403
+			$join .= ' = ' . EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name();
404
+			if (strpos($SQL, $join) === false) {
405
+				return ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' )';
406
+			}
407
+		}
408
+		return '';
409
+	}
410
+
411
+
412
+	/**
413
+	 * @param string $SQL
414
+	 * @return string
415
+	 * @throws EE_Error
416
+	 * @throws InvalidArgumentException
417
+	 * @throws InvalidDataTypeException
418
+	 * @throws InvalidInterfaceException
419
+	 */
420
+	protected static function _posts_join_for_event_venue($SQL = '')
421
+	{
422
+		// Event Venue table name
423
+		$event_venue_table = EEM_Event_Venue::instance()->table();
424
+		// generate conditions for:  Event <=> Event Venue  JOIN clause
425
+		$event_to_event_venue_join = EEM_Event::instance()->table() . '.ID = ';
426
+		$event_to_event_venue_join .= $event_venue_table . '.' . EEM_Event::instance()->primary_key_name();
427
+		// don't add joins if they have already been added
428
+		if (strpos($SQL, $event_to_event_venue_join) === false) {
429
+			// Venue table name
430
+			$venue_table = EEM_Venue::instance()->table();
431
+			// Venue table pk
432
+			$venue_table_pk = EEM_Venue::instance()->primary_key_name();
433
+			// Venue Meta table name
434
+			$venue_meta_table = EEM_Venue::instance()->second_table();
435
+			// generate JOIN clause for: Event <=> Event Venue
436
+			$venue_SQL = " LEFT JOIN $event_venue_table ON ( $event_to_event_venue_join )";
437
+			// generate JOIN clause for: Event Venue <=> Venue
438
+			$venue_SQL .= " LEFT JOIN $venue_table as Venue ON ( $event_venue_table.$venue_table_pk = Venue.ID )";
439
+			// generate JOIN clause for: Venue <=> Venue Meta
440
+			$venue_SQL .= " LEFT JOIN $venue_meta_table ON ( Venue.ID = $venue_meta_table.$venue_table_pk )";
441
+			unset($event_venue_table, $event_to_event_venue_join, $venue_table, $venue_table_pk, $venue_meta_table);
442
+			return $venue_SQL;
443
+		}
444
+		unset($event_venue_table, $event_to_event_venue_join);
445
+		return '';
446
+	}
447
+
448
+
449
+	/**
450
+	 * @param string $SQL
451
+	 * @return string
452
+	 * @throws EE_Error
453
+	 * @throws InvalidArgumentException
454
+	 * @throws InvalidDataTypeException
455
+	 * @throws InvalidInterfaceException
456
+	 */
457
+	protected static function _posts_join_for_venue_state($SQL = '')
458
+	{
459
+		// Venue Meta table name
460
+		$venue_meta_table = EEM_Venue::instance()->second_table();
461
+		// State table name
462
+		$state_table = EEM_State::instance()->table();
463
+		// State table pk
464
+		$state_table_pk = EEM_State::instance()->primary_key_name();
465
+		// verify vars
466
+		if ($venue_meta_table && $state_table && $state_table_pk) {
467
+			// like: wp_esp_venue_meta.STA_ID = wp_esp_state.STA_ID
468
+			$join = "$venue_meta_table.$state_table_pk = $state_table.$state_table_pk";
469
+			// don't add join if it has already been added
470
+			if (strpos($SQL, $join) === false) {
471
+				unset($state_table_pk, $venue_meta_table, $venue_table_pk);
472
+				return " LEFT JOIN $state_table ON ( $join )";
473
+			}
474
+		}
475
+		unset($join, $state_table, $state_table_pk, $venue_meta_table, $venue_table_pk);
476
+		return '';
477
+	}
478
+
479
+
480
+	/**
481
+	 * @param string   $SQL
482
+	 * @param WP_Query $wp_query
483
+	 * @return string
484
+	 * @throws EE_Error
485
+	 * @throws InvalidArgumentException
486
+	 * @throws InvalidDataTypeException
487
+	 * @throws InvalidInterfaceException
488
+	 */
489
+	public static function posts_where($SQL, WP_Query $wp_query)
490
+	{
491
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
492
+			// Show Expired ?
493
+			$SQL .= EEH_Event_Query::posts_where_sql_for_show_expired(EEH_Event_Query::$_event_query_show_expired);
494
+			// Category
495
+			$SQL .= EEH_Event_Query::posts_where_sql_for_event_category_slug(EEH_Event_Query::$_event_query_category);
496
+			// Start Date
497
+			$SQL .= EEH_Event_Query::posts_where_sql_for_event_list_month(EEH_Event_Query::$_event_query_month);
498
+		}
499
+		return $SQL;
500
+	}
501
+
502
+
503
+	/**
504
+	 * @param boolean $show_expired if TRUE, then displayed past events
505
+	 * @return string
506
+	 * @throws EE_Error
507
+	 * @throws InvalidArgumentException
508
+	 * @throws InvalidDataTypeException
509
+	 * @throws InvalidInterfaceException
510
+	 */
511
+	public static function posts_where_sql_for_show_expired($show_expired = false)
512
+	{
513
+		return ! $show_expired
514
+			? ' AND ' . EEM_Datetime::instance()->table() . '.DTT_EVT_end > \'' . current_time('mysql', true) . '\' '
515
+			: '';
516
+	}
517
+
518
+
519
+	/**
520
+	 * @param boolean $event_category_slug
521
+	 * @return string
522
+	 */
523
+	public static function posts_where_sql_for_event_category_slug($event_category_slug = null)
524
+	{
525
+		global $wpdb;
526
+		if (! empty($event_category_slug)) {
527
+			$event_category_slugs_array   = array_map('trim', explode(',', $event_category_slug));
528
+			$event_category_slugs_prepare = implode(', ', array_fill(0, count($event_category_slugs_array), '%s'));
529
+			return $wpdb->prepare(
530
+				" AND {$wpdb->terms}.slug IN ({$event_category_slugs_prepare}) ",
531
+				$event_category_slugs_array
532
+			);
533
+		}
534
+		return '';
535
+	}
536
+
537
+
538
+	/**
539
+	 * @param boolean $month
540
+	 * @return string
541
+	 * @throws EE_Error
542
+	 * @throws InvalidArgumentException
543
+	 * @throws InvalidDataTypeException
544
+	 * @throws InvalidInterfaceException
545
+	 */
546
+	public static function posts_where_sql_for_event_list_month($month = null)
547
+	{
548
+		$SQL = '';
549
+		if (! empty($month)) {
550
+			$datetime_table = EEM_Datetime::instance()->table();
551
+			// event start date is LESS than the end of the month ( so nothing that doesn't start until next month )
552
+			$SQL = " AND {$datetime_table}.DTT_EVT_start <= '";
553
+			$SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month)) . "'";
554
+			// event end date is GREATER than the start of the month ( so nothing that ended before this month )
555
+			$SQL .= " AND {$datetime_table}.DTT_EVT_end >= '";
556
+			$SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month)) . "' ";
557
+		}
558
+		return $SQL;
559
+	}
560
+
561
+
562
+	/**
563
+	 * @param string   $SQL
564
+	 * @param WP_Query $wp_query
565
+	 * @return string
566
+	 * @throws EE_Error
567
+	 * @throws InvalidArgumentException
568
+	 * @throws InvalidDataTypeException
569
+	 * @throws InvalidInterfaceException
570
+	 */
571
+	public static function posts_orderby($SQL, WP_Query $wp_query)
572
+	{
573
+		if (EEH_Event_Query::apply_query_filters($wp_query)) {
574
+			$SQL = EEH_Event_Query::posts_orderby_sql(
575
+				EEH_Event_Query::$_event_query_orderby,
576
+				EEH_Event_Query::$_event_query_sort
577
+			);
578
+		}
579
+		return $SQL;
580
+	}
581
+
582
+
583
+	/**
584
+	 *    posts_orderby_sql
585
+	 *    possible parameters:
586
+	 *    ID
587
+	 *    start_date
588
+	 *    end_date
589
+	 *    event_name
590
+	 *    category_slug
591
+	 *    ticket_start
592
+	 *    ticket_end
593
+	 *    venue_title
594
+	 *    city
595
+	 *    state
596
+	 *    **IMPORTANT**
597
+	 *    make sure to also send the $orderby_params array to the posts_join_for_orderby() method
598
+	 *    or else some of the table references below will result in MySQL errors
599
+	 *
600
+	 * @param array  $orderby_params
601
+	 * @param string $sort
602
+	 * @return string
603
+	 * @throws EE_Error
604
+	 * @throws InvalidArgumentException
605
+	 * @throws InvalidDataTypeException
606
+	 * @throws InvalidInterfaceException
607
+	 */
608
+	public static function posts_orderby_sql(array $orderby_params = [], $sort = 'ASC')
609
+	{
610
+		global $wpdb;
611
+		$SQL     = '';
612
+		$counter = 0;
613
+		$sort    = in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true)
614
+			? strtoupper($sort)
615
+			: 'ASC';
616
+		// make sure 'orderby' is set in query params
617
+		if (! isset(self::$_query_params['orderby'])) {
618
+			self::$_query_params['orderby'] = [];
619
+		}
620
+		// loop thru $orderby_params (type cast as array)
621
+		foreach ($orderby_params as $orderby) {
622
+			// check if we have already added this param
623
+			if (isset(self::$_query_params['orderby'][ $orderby ])) {
624
+				// if so then remove from the $orderby_params so that the count() method below is accurate
625
+				unset($orderby_params[ $orderby ]);
626
+				// then bump ahead to the next param
627
+				continue;
628
+			}
629
+			// this will ad a comma depending on whether this is the first or last param
630
+			$glue = $counter === 0 || $counter === count($orderby_params) ? ' ' : ', ';
631
+			// ok what's we dealing with?
632
+			switch ($orderby) {
633
+				case 'id':
634
+				case 'ID':
635
+					$SQL .= $glue . $wpdb->posts . '.ID ' . $sort;
636
+					break;
637
+				case 'end_date':
638
+					$SQL .= $glue . EEM_Datetime::instance()->table() . '.DTT_EVT_end ' . $sort;
639
+					break;
640
+				case 'event_name':
641
+					$SQL .= $glue . $wpdb->posts . '.post_title ' . $sort;
642
+					break;
643
+				case 'category_slug':
644
+					$SQL .= $glue . $wpdb->terms . '.slug ' . $sort;
645
+					break;
646
+				case 'ticket_start':
647
+					$SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_start_date ' . $sort;
648
+					break;
649
+				case 'ticket_end':
650
+					$SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_end_date ' . $sort;
651
+					break;
652
+				case 'venue_title':
653
+					$SQL .= $glue . 'venue_title ' . $sort;
654
+					break;
655
+				case 'city':
656
+					$SQL .= $glue . EEM_Venue::instance()->second_table() . '.VNU_city ' . $sort;
657
+					break;
658
+				case 'state':
659
+					$SQL .= $glue . EEM_State::instance()->table() . '.STA_name ' . $sort;
660
+					break;
661
+				case 'start_date':
662
+				default:
663
+					$SQL .= $glue . ' event_start_date ' . $sort;
664
+					break;
665
+			}
666
+			// add to array of orderby params that have been added
667
+			self::$_query_params['orderby'][ $orderby ] = true;
668
+			$counter++;
669
+		}
670
+		return $SQL;
671
+	}
672
+
673
+
674
+	/**
675
+	 * @return RequestInterface
676
+	 * @since   4.10.14.p
677
+	 */
678
+	private static function getRequest()
679
+	{
680
+		return LoaderFactory::getLoader()->getShared(RequestInterface::class);
681
+	}
682 682
 }
Please login to merge, or discard this patch.
core/EE_Session.core.php 2 patches
Spacing   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -246,22 +246,22 @@  discard block
 block discarded – undo
246 246
         // but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
247 247
         // (which currently fires on the init hook at priority 9),
248 248
         // can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
249
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
249
+        if ( ! apply_filters('FHEE_load_EE_Session', true)) {
250 250
             return;
251 251
         }
252 252
         $this->session_start_handler = $session_start_handler;
253 253
         $this->session_lifespan = $lifespan;
254 254
         $this->request = $request;
255
-        if (! defined('ESPRESSO_SESSION')) {
255
+        if ( ! defined('ESPRESSO_SESSION')) {
256 256
             define('ESPRESSO_SESSION', true);
257 257
         }
258 258
         // retrieve session options from db
259 259
         $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
260
-        if (! empty($session_settings)) {
260
+        if ( ! empty($session_settings)) {
261 261
             // cycle though existing session options
262 262
             foreach ($session_settings as $var_name => $session_setting) {
263 263
                 // set values for class properties
264
-                $var_name = '_' . $var_name;
264
+                $var_name = '_'.$var_name;
265 265
                 $this->{$var_name} = $session_setting;
266 266
             }
267 267
         }
@@ -322,7 +322,7 @@  discard block
 block discarded – undo
322 322
     public function open_session()
323 323
     {
324 324
         // check for existing session and retrieve it from db
325
-        if (! $this->_espresso_session()) {
325
+        if ( ! $this->_espresso_session()) {
326 326
             // or just start a new one
327 327
             $this->_create_espresso_session();
328 328
         }
@@ -399,7 +399,7 @@  discard block
 block discarded – undo
399 399
             EE_Session::SAVE_STATE_CLEAN,
400 400
             EE_Session::SAVE_STATE_DIRTY,
401 401
         ];
402
-        if (! in_array($save_state, $valid_save_states, true)) {
402
+        if ( ! in_array($save_state, $valid_save_states, true)) {
403 403
             $save_state = EE_Session::SAVE_STATE_DIRTY;
404 404
         }
405 405
         $this->save_state = $save_state;
@@ -417,9 +417,9 @@  discard block
 block discarded – undo
417 417
         // set some defaults
418 418
         foreach ($this->_default_session_vars as $key => $default_var) {
419 419
             if (is_array($default_var)) {
420
-                $this->_session_data[ $key ] = array();
420
+                $this->_session_data[$key] = array();
421 421
             } else {
422
-                $this->_session_data[ $key ] = '';
422
+                $this->_session_data[$key] = '';
423 423
             }
424 424
         }
425 425
     }
@@ -555,8 +555,8 @@  discard block
 block discarded – undo
555 555
             $this->reset_checkout();
556 556
             $this->reset_transaction();
557 557
         }
558
-        if (! empty($key)) {
559
-            return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
558
+        if ( ! empty($key)) {
559
+            return isset($this->_session_data[$key]) ? $this->_session_data[$key] : null;
560 560
         }
561 561
         return $this->_session_data;
562 562
     }
@@ -584,7 +584,7 @@  discard block
 block discarded – undo
584 584
             return false;
585 585
         }
586 586
         foreach ($data as $key => $value) {
587
-            if (isset($this->_default_session_vars[ $key ])) {
587
+            if (isset($this->_default_session_vars[$key])) {
588 588
                 EE_Error::add_error(
589 589
                     sprintf(
590 590
                         esc_html__(
@@ -599,7 +599,7 @@  discard block
 block discarded – undo
599 599
                 );
600 600
                 return false;
601 601
             }
602
-            $this->_session_data[ $key ] = $value;
602
+            $this->_session_data[$key] = $value;
603 603
             $this->setSaveState();
604 604
         }
605 605
         return true;
@@ -630,7 +630,7 @@  discard block
 block discarded – undo
630 630
         $this->_user_agent = $this->request->userAgent();
631 631
         // now let's retrieve what's in the db
632 632
         $session_data = $this->_retrieve_session_data();
633
-        if (! empty($session_data)) {
633
+        if ( ! empty($session_data)) {
634 634
             // get the current time in UTC
635 635
             $this->_time = $this->_time !== null ? $this->_time : time();
636 636
             // and reset the session expiration
@@ -641,7 +641,7 @@  discard block
 block discarded – undo
641 641
             // set initial site access time and the session expiration
642 642
             $this->_set_init_access_and_expiration();
643 643
             // set referer
644
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = esc_attr(
644
+            $this->_session_data['pages_visited'][$this->_session_data['init_access']] = esc_attr(
645 645
                 $this->request->getServerParam('HTTP_REFERER')
646 646
             );
647 647
             // no previous session = go back and create one (on top of the data above)
@@ -679,7 +679,7 @@  discard block
 block discarded – undo
679 679
      */
680 680
     protected function _retrieve_session_data()
681 681
     {
682
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
682
+        $ssn_key = EE_Session::session_id_prefix.$this->_sid;
683 683
         try {
684 684
             // we're using WP's Transient API to store session data using the PHP session ID as the option name
685 685
             $session_data = $this->cache_storage->get($ssn_key, false);
@@ -688,7 +688,7 @@  discard block
 block discarded – undo
688 688
             }
689 689
             if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
690 690
                 $hash_check = $this->cache_storage->get(
691
-                    EE_Session::hash_check_prefix . $this->_sid,
691
+                    EE_Session::hash_check_prefix.$this->_sid,
692 692
                     false
693 693
                 );
694 694
                 if ($hash_check && $hash_check !== md5($session_data)) {
@@ -698,7 +698,7 @@  discard block
 block discarded – undo
698 698
                                 'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
699 699
                                 'event_espresso'
700 700
                             ),
701
-                            EE_Session::session_id_prefix . $this->_sid
701
+                            EE_Session::session_id_prefix.$this->_sid
702 702
                         ),
703 703
                         __FILE__,
704 704
                         __FUNCTION__,
@@ -712,17 +712,17 @@  discard block
 block discarded – undo
712 712
             $row = $wpdb->get_row(
713 713
                 $wpdb->prepare(
714 714
                     "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
715
-                    '_transient_' . $ssn_key
715
+                    '_transient_'.$ssn_key
716 716
                 )
717 717
             );
718 718
             $session_data = is_object($row) ? $row->option_value : null;
719 719
             if ($session_data) {
720 720
                 $session_data = preg_replace_callback(
721 721
                     '!s:(d+):"(.*?)";!',
722
-                    function ($match) {
722
+                    function($match) {
723 723
                         return $match[1] === strlen($match[2])
724 724
                             ? $match[0]
725
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
725
+                            : 's:'.strlen($match[2]).':"'.$match[2].'";';
726 726
                     },
727 727
                     $session_data
728 728
                 );
@@ -733,7 +733,7 @@  discard block
 block discarded – undo
733 733
         $session_data = $this->encryption instanceof EE_Encryption
734 734
             ? $this->encryption->base64_string_decode($session_data)
735 735
             : $session_data;
736
-        if (! is_array($session_data)) {
736
+        if ( ! is_array($session_data)) {
737 737
             try {
738 738
                 $session_data = maybe_unserialize($session_data);
739 739
             } catch (Exception $e) {
@@ -747,21 +747,21 @@  discard block
 block discarded – undo
747 747
                       . '</pre><br>'
748 748
                       . $this->find_serialize_error($session_data)
749 749
                     : '';
750
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
750
+                $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
751 751
                 throw new InvalidSessionDataException($msg, 0, $e);
752 752
             }
753 753
         }
754 754
         // just a check to make sure the session array is indeed an array
755
-        if (! is_array($session_data)) {
755
+        if ( ! is_array($session_data)) {
756 756
             // no?!?! then something is wrong
757 757
             $msg = esc_html__(
758 758
                 'The session data is missing, invalid, or corrupted.',
759 759
                 'event_espresso'
760 760
             );
761 761
             $msg .= WP_DEBUG
762
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
762
+                ? '<br><pre>'.print_r($session_data, true).'</pre><br>'.$this->find_serialize_error($session_data)
763 763
                 : '';
764
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
764
+            $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
765 765
             throw new InvalidSessionDataException($msg);
766 766
         }
767 767
         if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
@@ -787,7 +787,7 @@  discard block
 block discarded – undo
787 787
         // check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
788 788
         $session_id = $this->request->requestParamIsSet('EESID')
789 789
             ? $this->request->getRequestParam('EESID')
790
-            : md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
790
+            : md5(session_id().get_current_blog_id().$this->_get_sid_salt());
791 791
         return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
792 792
     }
793 793
 
@@ -889,19 +889,19 @@  discard block
 block discarded – undo
889 889
                     $page_visit = $this->_get_page_visit();
890 890
                     if ($page_visit) {
891 891
                         // set pages visited where the first will be the http referrer
892
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
892
+                        $this->_session_data['pages_visited'][$this->_time] = $page_visit;
893 893
                         // we'll only save the last 10 page visits.
894 894
                         $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
895 895
                     }
896 896
                     break;
897 897
                 default:
898 898
                     // carry any other data over
899
-                    $session_data[ $key ] = $this->_session_data[ $key ];
899
+                    $session_data[$key] = $this->_session_data[$key];
900 900
             }
901 901
         }
902 902
         $this->_session_data = $session_data;
903 903
         // creating a new session does not require saving to the db just yet
904
-        if (! $new_session) {
904
+        if ( ! $new_session) {
905 905
             // ready? let's save
906 906
             if ($this->_save_session_to_db()) {
907 907
                 return true;
@@ -979,7 +979,7 @@  discard block
 block discarded – undo
979 979
         }
980 980
         $transaction = $this->transaction();
981 981
         if ($transaction instanceof EE_Transaction) {
982
-            if (! $transaction->ID()) {
982
+            if ( ! $transaction->ID()) {
983 983
                 $transaction->save();
984 984
             }
985 985
             $this->_session_data['transaction'] = $transaction->ID();
@@ -993,14 +993,14 @@  discard block
 block discarded – undo
993 993
         // maybe save hash check
994 994
         if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
995 995
             $this->cache_storage->add(
996
-                EE_Session::hash_check_prefix . $this->_sid,
996
+                EE_Session::hash_check_prefix.$this->_sid,
997 997
                 md5($session_data),
998 998
                 $this->session_lifespan->inSeconds()
999 999
             );
1000 1000
         }
1001 1001
         // we're using the Transient API for storing session data,
1002 1002
         $saved = $this->cache_storage->add(
1003
-            EE_Session::session_id_prefix . $this->_sid,
1003
+            EE_Session::session_id_prefix.$this->_sid,
1004 1004
             $session_data,
1005 1005
             $this->session_lifespan->inSeconds()
1006 1006
         );
@@ -1015,7 +1015,7 @@  discard block
 block discarded – undo
1015 1015
      */
1016 1016
     public function _get_page_visit()
1017 1017
     {
1018
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
1018
+        $page_visit = home_url('/').'wp-admin/admin-ajax.php';
1019 1019
         // check for request url
1020 1020
         if ($this->request->serverParamIsSet('REQUEST_URI')) {
1021 1021
             $page_id = '?';
@@ -1027,14 +1027,14 @@  discard block
 block discarded – undo
1027 1027
             // check for page_id in SERVER REQUEST
1028 1028
             if ($this->request->requestParamIsSet('page_id')) {
1029 1029
                 // rebuild $e_reg without any of the extra parameters
1030
-                $page_id .= 'page_id=' . $this->request->getRequestParam('page_id', 0, 'int') . '&amp;';
1030
+                $page_id .= 'page_id='.$this->request->getRequestParam('page_id', 0, 'int').'&amp;';
1031 1031
             }
1032 1032
             // check for $e_reg in SERVER REQUEST
1033 1033
             if ($this->request->requestParamIsSet('ee')) {
1034 1034
                 // rebuild $e_reg without any of the extra parameters
1035
-                $e_reg = 'ee=' . $this->request->getRequestParam('ee');
1035
+                $e_reg = 'ee='.$this->request->getRequestParam('ee');
1036 1036
             }
1037
-            $page_visit = esc_url(rtrim($http_host . $request_uri . $page_id . $e_reg, '?'));
1037
+            $page_visit = esc_url(rtrim($http_host.$request_uri.$page_id.$e_reg, '?'));
1038 1038
         }
1039 1039
         return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
1040 1040
     }
@@ -1071,7 +1071,7 @@  discard block
 block discarded – undo
1071 1071
 // <span style="color:#2EA2CC">' . __CLASS__ . '</span>::<span style="color:#E76700">' . __FUNCTION__ . '( ' . $class . '::' . $function . '() )</span><br/>
1072 1072
 // <span style="font-size:9px;font-weight:normal;">' . __FILE__ . '</span>    <b style="font-size:10px;">  ' . __LINE__ . ' </b>
1073 1073
 // </h3>';
1074
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1074
+        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : '.$class.'::'.$function.'()');
1075 1075
         $this->reset_cart();
1076 1076
         $this->reset_checkout();
1077 1077
         $this->reset_transaction();
@@ -1094,7 +1094,7 @@  discard block
 block discarded – undo
1094 1094
     public function reset_data($data_to_reset = array(), $show_all_notices = false)
1095 1095
     {
1096 1096
         // if $data_to_reset is not in an array, then put it in one
1097
-        if (! is_array($data_to_reset)) {
1097
+        if ( ! is_array($data_to_reset)) {
1098 1098
             $data_to_reset = array($data_to_reset);
1099 1099
         }
1100 1100
         // nothing ??? go home!
@@ -1114,11 +1114,11 @@  discard block
 block discarded – undo
1114 1114
         // since $data_to_reset is an array, cycle through the values
1115 1115
         foreach ($data_to_reset as $reset) {
1116 1116
             // first check to make sure it is a valid session var
1117
-            if (isset($this->_session_data[ $reset ])) {
1117
+            if (isset($this->_session_data[$reset])) {
1118 1118
                 // then check to make sure it is not a default var
1119
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1119
+                if ( ! array_key_exists($reset, $this->_default_session_vars)) {
1120 1120
                     // remove session var
1121
-                    unset($this->_session_data[ $reset ]);
1121
+                    unset($this->_session_data[$reset]);
1122 1122
                     $this->setSaveState();
1123 1123
                     if ($show_all_notices) {
1124 1124
                         EE_Error::add_success(
@@ -1221,7 +1221,7 @@  discard block
 block discarded – undo
1221 1221
             // or use that for the new transient cleanup query limit
1222 1222
             add_filter(
1223 1223
                 'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1224
-                function () use ($expired_session_transient_delete_query_limit) {
1224
+                function() use ($expired_session_transient_delete_query_limit) {
1225 1225
                     return $expired_session_transient_delete_query_limit;
1226 1226
                 }
1227 1227
             );
@@ -1239,7 +1239,7 @@  discard block
 block discarded – undo
1239 1239
         $error = '<pre>';
1240 1240
         $data2 = preg_replace_callback(
1241 1241
             '!s:(\d+):"(.*?)";!',
1242
-            function ($match) {
1242
+            function($match) {
1243 1243
                 return ($match[1] === strlen($match[2]))
1244 1244
                     ? $match[0]
1245 1245
                     : 's:'
@@ -1251,13 +1251,13 @@  discard block
 block discarded – undo
1251 1251
             $data1
1252 1252
         );
1253 1253
         $max = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1254
-        $error .= $data1 . PHP_EOL;
1255
-        $error .= $data2 . PHP_EOL;
1254
+        $error .= $data1.PHP_EOL;
1255
+        $error .= $data2.PHP_EOL;
1256 1256
         for ($i = 0; $i < $max; $i++) {
1257
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1258
-                $error .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1259
-                $error .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1260
-                $error .= "\t-> Line Number = $i" . PHP_EOL;
1257
+            if (@$data1[$i] !== @$data2[$i]) {
1258
+                $error .= 'Difference '.@$data1[$i].' != '.@$data2[$i].PHP_EOL;
1259
+                $error .= "\t-> ORD number ".ord(@$data1[$i]).' != '.ord(@$data2[$i]).PHP_EOL;
1260
+                $error .= "\t-> Line Number = $i".PHP_EOL;
1261 1261
                 $start = ($i - 20);
1262 1262
                 $start = ($start < 0) ? 0 : $start;
1263 1263
                 $length = 40;
@@ -1272,7 +1272,7 @@  discard block
 block discarded – undo
1272 1272
                 $error .= "\t-> Section Data1  = ";
1273 1273
                 $error .= substr_replace(
1274 1274
                     substr($data1, $start, $length),
1275
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1275
+                    "<b style=\"color:green\">{$data1[$i]}</b>",
1276 1276
                     $rpoint,
1277 1277
                     $rlength
1278 1278
                 );
@@ -1280,7 +1280,7 @@  discard block
 block discarded – undo
1280 1280
                 $error .= "\t-> Section Data2  = ";
1281 1281
                 $error .= substr_replace(
1282 1282
                     substr($data2, $start, $length),
1283
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1283
+                    "<b style=\"color:red\">{$data2[$i]}</b>",
1284 1284
                     $rpoint,
1285 1285
                     $rlength
1286 1286
                 );
@@ -1311,7 +1311,7 @@  discard block
 block discarded – undo
1311 1311
     public function garbageCollection()
1312 1312
     {
1313 1313
         // only perform during regular requests if last garbage collection was over an hour ago
1314
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1314
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1315 1315
             $this->_last_gc = time();
1316 1316
             $this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1317 1317
             /** @type WPDB $wpdb */
@@ -1346,7 +1346,7 @@  discard block
 block discarded – undo
1346 1346
                 // AND option_value < 1508368198 LIMIT 50
1347 1347
                 $expired_sessions = $wpdb->get_col($SQL);
1348 1348
                 // valid results?
1349
-                if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1349
+                if ( ! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1350 1350
                     $this->cache_storage->deleteMany($expired_sessions, true);
1351 1351
                 }
1352 1352
             }
Please login to merge, or discard this patch.
Indentation   +1312 added lines, -1312 removed lines patch added patch discarded remove patch
@@ -23,1310 +23,1310 @@  discard block
 block discarded – undo
23 23
  */
24 24
 class EE_Session implements SessionIdentifierInterface
25 25
 {
26
-    const session_id_prefix = 'ee_ssn_';
27
-
28
-    const hash_check_prefix = 'ee_shc_';
29
-
30
-    const OPTION_NAME_SETTINGS = 'ee_session_settings';
31
-
32
-    const STATUS_CLOSED = 0;
33
-
34
-    const STATUS_OPEN = 1;
35
-
36
-    const SAVE_STATE_CLEAN = 'clean';
37
-    const SAVE_STATE_DIRTY = 'dirty';
38
-
39
-
40
-    /**
41
-     * instance of the EE_Session object
42
-     *
43
-     * @var EE_Session
44
-     */
45
-    private static $_instance;
46
-
47
-    /**
48
-     * @var CacheStorageInterface $cache_storage
49
-     */
50
-    protected $cache_storage;
51
-
52
-    /**
53
-     * @var EE_Encryption $encryption
54
-     */
55
-    protected $encryption;
56
-
57
-    /**
58
-     * @var SessionStartHandler $session_start_handler
59
-     */
60
-    protected $session_start_handler;
61
-
62
-    /**
63
-     * the session id
64
-     *
65
-     * @var string
66
-     */
67
-    private $_sid;
68
-
69
-    /**
70
-     * session id salt
71
-     *
72
-     * @var string
73
-     */
74
-    private $_sid_salt;
75
-
76
-    /**
77
-     * session data
78
-     *
79
-     * @var array
80
-     */
81
-    private $_session_data = array();
82
-
83
-    /**
84
-     * how long an EE session lasts
85
-     * default session lifespan of 1 hour (for not so instant IPNs)
86
-     *
87
-     * @var SessionLifespan $session_lifespan
88
-     */
89
-    private $session_lifespan;
90
-
91
-    /**
92
-     * session expiration time as Unix timestamp in GMT
93
-     *
94
-     * @var int
95
-     */
96
-    private $_expiration;
97
-
98
-    /**
99
-     * whether or not session has expired at some point
100
-     *
101
-     * @var boolean
102
-     */
103
-    private $_expired = false;
104
-
105
-    /**
106
-     * current time as Unix timestamp in GMT
107
-     *
108
-     * @var int
109
-     */
110
-    private $_time;
111
-
112
-    /**
113
-     * whether to encrypt session data
114
-     *
115
-     * @var bool
116
-     */
117
-    private $_use_encryption;
118
-
119
-    /**
120
-     * well... according to the server...
121
-     *
122
-     * @var null
123
-     */
124
-    private $_user_agent;
125
-
126
-    /**
127
-     * do you really trust the server ?
128
-     *
129
-     * @var null
130
-     */
131
-    private $_ip_address;
132
-
133
-    /**
134
-     * current WP user_id
135
-     *
136
-     * @var null
137
-     */
138
-    private $_wp_user_id;
139
-
140
-    /**
141
-     * array for defining default session vars
142
-     *
143
-     * @var array
144
-     */
145
-    private $_default_session_vars = array(
146
-        'id'            => null,
147
-        'user_id'       => null,
148
-        'ip_address'    => null,
149
-        'user_agent'    => null,
150
-        'init_access'   => null,
151
-        'last_access'   => null,
152
-        'expiration'    => null,
153
-        'pages_visited' => array(),
154
-    );
155
-
156
-    /**
157
-     * timestamp for when last garbage collection cycle was performed
158
-     *
159
-     * @var int $_last_gc
160
-     */
161
-    private $_last_gc;
162
-
163
-    /**
164
-     * @var RequestInterface $request
165
-     */
166
-    protected $request;
167
-
168
-    /**
169
-     * whether session is active or not
170
-     *
171
-     * @var int $status
172
-     */
173
-    private $status = EE_Session::STATUS_CLOSED;
174
-
175
-    /**
176
-     * whether session data has changed therefore requiring a session save
177
-     *
178
-     * @var string $save_state
179
-     */
180
-    private $save_state = EE_Session::SAVE_STATE_CLEAN;
181
-
182
-
183
-    /**
184
-     * @singleton method used to instantiate class object
185
-     * @param CacheStorageInterface $cache_storage
186
-     * @param SessionLifespan|null  $lifespan
187
-     * @param RequestInterface      $request
188
-     * @param SessionStartHandler   $session_start_handler
189
-     * @param EE_Encryption         $encryption
190
-     * @return EE_Session
191
-     * @throws InvalidArgumentException
192
-     * @throws InvalidDataTypeException
193
-     * @throws InvalidInterfaceException
194
-     */
195
-    public static function instance(
196
-        CacheStorageInterface $cache_storage = null,
197
-        SessionLifespan $lifespan = null,
198
-        RequestInterface $request = null,
199
-        SessionStartHandler $session_start_handler = null,
200
-        EE_Encryption $encryption = null
201
-    ) {
202
-        // check if class object is instantiated
203
-        // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
204
-        // add_filter( 'FHEE_load_EE_Session', '__return_false' );
205
-        if (
206
-            ! self::$_instance instanceof EE_Session
207
-            && $cache_storage instanceof CacheStorageInterface
208
-            && $lifespan instanceof SessionLifespan
209
-            && $request instanceof RequestInterface
210
-            && $session_start_handler instanceof SessionStartHandler
211
-            && apply_filters('FHEE_load_EE_Session', true)
212
-        ) {
213
-            self::$_instance = new self(
214
-                $cache_storage,
215
-                $lifespan,
216
-                $request,
217
-                $session_start_handler,
218
-                $encryption
219
-            );
220
-        }
221
-        return self::$_instance;
222
-    }
223
-
224
-
225
-    /**
226
-     * protected constructor to prevent direct creation
227
-     *
228
-     * @param CacheStorageInterface $cache_storage
229
-     * @param SessionLifespan       $lifespan
230
-     * @param RequestInterface      $request
231
-     * @param SessionStartHandler   $session_start_handler
232
-     * @param EE_Encryption         $encryption
233
-     * @throws InvalidArgumentException
234
-     * @throws InvalidDataTypeException
235
-     * @throws InvalidInterfaceException
236
-     */
237
-    protected function __construct(
238
-        CacheStorageInterface $cache_storage,
239
-        SessionLifespan $lifespan,
240
-        RequestInterface $request,
241
-        SessionStartHandler $session_start_handler,
242
-        EE_Encryption $encryption = null
243
-    ) {
244
-        // session loading is turned ON by default,
245
-        // but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
246
-        // (which currently fires on the init hook at priority 9),
247
-        // can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
248
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
249
-            return;
250
-        }
251
-        $this->session_start_handler = $session_start_handler;
252
-        $this->session_lifespan = $lifespan;
253
-        $this->request = $request;
254
-        if (! defined('ESPRESSO_SESSION')) {
255
-            define('ESPRESSO_SESSION', true);
256
-        }
257
-        // retrieve session options from db
258
-        $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
259
-        if (! empty($session_settings)) {
260
-            // cycle though existing session options
261
-            foreach ($session_settings as $var_name => $session_setting) {
262
-                // set values for class properties
263
-                $var_name = '_' . $var_name;
264
-                $this->{$var_name} = $session_setting;
265
-            }
266
-        }
267
-        $this->cache_storage = $cache_storage;
268
-        // are we using encryption?
269
-        $this->_use_encryption = $encryption instanceof EE_Encryption
270
-                                 && EE_Registry::instance()->CFG->admin->encode_session_data();
271
-        // encrypt data via: $this->encryption->encrypt();
272
-        $this->encryption = $encryption;
273
-        // filter hook allows outside functions/classes/plugins to change default empty cart
274
-        $extra_default_session_vars = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', array());
275
-        array_merge($this->_default_session_vars, $extra_default_session_vars);
276
-        // apply default session vars
277
-        $this->_set_defaults();
278
-        add_action('AHEE__EE_System__initialize', array($this, 'open_session'));
279
-        // check request for 'clear_session' param
280
-        add_action('AHEE__EE_Request_Handler__construct__complete', array($this, 'wp_loaded'));
281
-        // once everything is all said and done,
282
-        add_action('shutdown', array($this, 'update'), 100);
283
-        add_action('shutdown', array($this, 'garbageCollection'), 1000);
284
-        $this->configure_garbage_collection_filters();
285
-    }
286
-
287
-
288
-    /**
289
-     * @return bool
290
-     * @throws InvalidArgumentException
291
-     * @throws InvalidDataTypeException
292
-     * @throws InvalidInterfaceException
293
-     */
294
-    public static function isLoadedAndActive()
295
-    {
296
-        return did_action('AHEE__EE_System__core_loaded_and_ready')
297
-               && EE_Session::instance() instanceof EE_Session
298
-               && EE_Session::instance()->isActive();
299
-    }
300
-
301
-
302
-    /**
303
-     * @return bool
304
-     */
305
-    public function isActive()
306
-    {
307
-        return $this->status === EE_Session::STATUS_OPEN;
308
-    }
309
-
310
-
311
-    /**
312
-     * @return void
313
-     * @throws EE_Error
314
-     * @throws InvalidArgumentException
315
-     * @throws InvalidDataTypeException
316
-     * @throws InvalidInterfaceException
317
-     * @throws InvalidSessionDataException
318
-     * @throws RuntimeException
319
-     * @throws ReflectionException
320
-     */
321
-    public function open_session()
322
-    {
323
-        // check for existing session and retrieve it from db
324
-        if (! $this->_espresso_session()) {
325
-            // or just start a new one
326
-            $this->_create_espresso_session();
327
-        }
328
-    }
329
-
330
-
331
-    /**
332
-     * @return bool
333
-     */
334
-    public function expired()
335
-    {
336
-        return $this->_expired;
337
-    }
338
-
339
-
340
-    /**
341
-     * @return void
342
-     */
343
-    public function reset_expired()
344
-    {
345
-        $this->_expired = false;
346
-    }
347
-
348
-
349
-    /**
350
-     * @return int
351
-     */
352
-    public function expiration()
353
-    {
354
-        return $this->_expiration;
355
-    }
356
-
357
-
358
-    /**
359
-     * @return int
360
-     */
361
-    public function extension()
362
-    {
363
-        return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
364
-    }
365
-
366
-
367
-    /**
368
-     * @param int $time number of seconds to add to session expiration
369
-     */
370
-    public function extend_expiration($time = 0)
371
-    {
372
-        $time = $time ? $time : $this->extension();
373
-        $this->_expiration += absint($time);
374
-    }
375
-
376
-
377
-    /**
378
-     * @return int
379
-     */
380
-    public function lifespan()
381
-    {
382
-        return $this->session_lifespan->inSeconds();
383
-    }
384
-
385
-
386
-    /**
387
-     * Marks whether the session data has been updated or not.
388
-     * Valid options are:
389
-     *      EE_Session::SAVE_STATE_CLEAN - session data remains unchanged and updating is not necessary
390
-     *      EE_Session::SAVE_STATE_DIRTY - session data has changed since last save and needs to be updated
391
-     * default value is EE_Session::SAVE_STATE_DIRTY
392
-     *
393
-     * @param string $save_state
394
-     */
395
-    public function setSaveState($save_state = EE_Session::SAVE_STATE_DIRTY)
396
-    {
397
-        $valid_save_states = [
398
-            EE_Session::SAVE_STATE_CLEAN,
399
-            EE_Session::SAVE_STATE_DIRTY,
400
-        ];
401
-        if (! in_array($save_state, $valid_save_states, true)) {
402
-            $save_state = EE_Session::SAVE_STATE_DIRTY;
403
-        }
404
-        $this->save_state = $save_state;
405
-    }
406
-
407
-
408
-
409
-    /**
410
-     * This just sets some defaults for the _session data property
411
-     *
412
-     * @return void
413
-     */
414
-    private function _set_defaults()
415
-    {
416
-        // set some defaults
417
-        foreach ($this->_default_session_vars as $key => $default_var) {
418
-            if (is_array($default_var)) {
419
-                $this->_session_data[ $key ] = array();
420
-            } else {
421
-                $this->_session_data[ $key ] = '';
422
-            }
423
-        }
424
-    }
425
-
426
-
427
-    /**
428
-     * @retrieve  session data
429
-     * @return    string
430
-     */
431
-    public function id()
432
-    {
433
-        return $this->_sid;
434
-    }
435
-
436
-
437
-    /**
438
-     * @param \EE_Cart $cart
439
-     * @return bool
440
-     */
441
-    public function set_cart(EE_Cart $cart)
442
-    {
443
-        $this->_session_data['cart'] = $cart;
444
-        $this->setSaveState();
445
-        return true;
446
-    }
447
-
448
-
449
-    /**
450
-     * reset_cart
451
-     */
452
-    public function reset_cart()
453
-    {
454
-        do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
455
-        $this->_session_data['cart'] = null;
456
-        $this->setSaveState();
457
-    }
458
-
459
-
460
-    /**
461
-     * @return \EE_Cart
462
-     */
463
-    public function cart()
464
-    {
465
-        return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
466
-            ? $this->_session_data['cart']
467
-            : null;
468
-    }
469
-
470
-
471
-    /**
472
-     * @param \EE_Checkout $checkout
473
-     * @return bool
474
-     */
475
-    public function set_checkout(EE_Checkout $checkout)
476
-    {
477
-        $this->_session_data['checkout'] = $checkout;
478
-        $this->setSaveState();
479
-        return true;
480
-    }
481
-
482
-
483
-    /**
484
-     * reset_checkout
485
-     */
486
-    public function reset_checkout()
487
-    {
488
-        do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
489
-        $this->_session_data['checkout'] = null;
490
-        $this->setSaveState();
491
-    }
492
-
493
-
494
-    /**
495
-     * @return \EE_Checkout
496
-     */
497
-    public function checkout()
498
-    {
499
-        return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
500
-            ? $this->_session_data['checkout']
501
-            : null;
502
-    }
503
-
504
-
505
-    /**
506
-     * @param \EE_Transaction $transaction
507
-     * @return bool
508
-     * @throws EE_Error
509
-     */
510
-    public function set_transaction(EE_Transaction $transaction)
511
-    {
512
-        // first remove the session from the transaction before we save the transaction in the session
513
-        $transaction->set_txn_session_data(null);
514
-        $this->_session_data['transaction'] = $transaction;
515
-        $this->setSaveState();
516
-        return true;
517
-    }
518
-
519
-
520
-    /**
521
-     * reset_transaction
522
-     */
523
-    public function reset_transaction()
524
-    {
525
-        do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
526
-        $this->_session_data['transaction'] = null;
527
-        $this->setSaveState();
528
-    }
529
-
530
-
531
-    /**
532
-     * @return \EE_Transaction
533
-     */
534
-    public function transaction()
535
-    {
536
-        return isset($this->_session_data['transaction'])
537
-               && $this->_session_data['transaction'] instanceof EE_Transaction
538
-            ? $this->_session_data['transaction']
539
-            : null;
540
-    }
541
-
542
-
543
-    /**
544
-     * retrieve session data
545
-     *
546
-     * @param null $key
547
-     * @param bool $reset_cache
548
-     * @return array
549
-     */
550
-    public function get_session_data($key = null, $reset_cache = false)
551
-    {
552
-        if ($reset_cache) {
553
-            $this->reset_cart();
554
-            $this->reset_checkout();
555
-            $this->reset_transaction();
556
-        }
557
-        if (! empty($key)) {
558
-            return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
559
-        }
560
-        return $this->_session_data;
561
-    }
562
-
563
-
564
-    /**
565
-     * Returns TRUE on success, FALSE on fail
566
-     *
567
-     * @param array $data
568
-     * @return bool
569
-     */
570
-    public function set_session_data($data)
571
-    {
572
-        // nothing ??? bad data ??? go home!
573
-        if (empty($data) || ! is_array($data)) {
574
-            EE_Error::add_error(
575
-                esc_html__(
576
-                    'No session data or invalid session data was provided.',
577
-                    'event_espresso'
578
-                ),
579
-                __FILE__,
580
-                __FUNCTION__,
581
-                __LINE__
582
-            );
583
-            return false;
584
-        }
585
-        foreach ($data as $key => $value) {
586
-            if (isset($this->_default_session_vars[ $key ])) {
587
-                EE_Error::add_error(
588
-                    sprintf(
589
-                        esc_html__(
590
-                            'Sorry! %s is a default session datum and can not be reset.',
591
-                            'event_espresso'
592
-                        ),
593
-                        $key
594
-                    ),
595
-                    __FILE__,
596
-                    __FUNCTION__,
597
-                    __LINE__
598
-                );
599
-                return false;
600
-            }
601
-            $this->_session_data[ $key ] = $value;
602
-            $this->setSaveState();
603
-        }
604
-        return true;
605
-    }
606
-
607
-
608
-    /**
609
-     * @initiate session
610
-     * @return bool TRUE on success, FALSE on fail
611
-     * @throws EE_Error
612
-     * @throws InvalidArgumentException
613
-     * @throws InvalidDataTypeException
614
-     * @throws InvalidInterfaceException
615
-     * @throws InvalidSessionDataException
616
-     * @throws RuntimeException
617
-     * @throws ReflectionException
618
-     */
619
-    private function _espresso_session()
620
-    {
621
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
622
-        $this->session_start_handler->startSession();
623
-        $this->status = EE_Session::STATUS_OPEN;
624
-        // get our modified session ID
625
-        $this->_sid = $this->_generate_session_id();
626
-        // and the visitors IP
627
-        $this->_ip_address = $this->request->ipAddress();
628
-        // set the "user agent"
629
-        $this->_user_agent = $this->request->userAgent();
630
-        // now let's retrieve what's in the db
631
-        $session_data = $this->_retrieve_session_data();
632
-        if (! empty($session_data)) {
633
-            // get the current time in UTC
634
-            $this->_time = $this->_time !== null ? $this->_time : time();
635
-            // and reset the session expiration
636
-            $this->_expiration = isset($session_data['expiration'])
637
-                ? $session_data['expiration']
638
-                : $this->_time + $this->session_lifespan->inSeconds();
639
-        } else {
640
-            // set initial site access time and the session expiration
641
-            $this->_set_init_access_and_expiration();
642
-            // set referer
643
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = esc_attr(
644
-                $this->request->getServerParam('HTTP_REFERER')
645
-            );
646
-            // no previous session = go back and create one (on top of the data above)
647
-            return false;
648
-        }
649
-        // now the user agent
650
-        if ($session_data['user_agent'] !== $this->_user_agent) {
651
-            return false;
652
-        }
653
-        // wait a minute... how old are you?
654
-        if ($this->_time > $this->_expiration) {
655
-            // yer too old fer me!
656
-            $this->_expired = true;
657
-            // wipe out everything that isn't a default session datum
658
-            $this->clear_session(__CLASS__, __FUNCTION__);
659
-        }
660
-        // make event espresso session data available to plugin
661
-        $this->_session_data = array_merge($this->_session_data, $session_data);
662
-        return true;
663
-    }
664
-
665
-
666
-    /**
667
-     * _get_session_data
668
-     * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
669
-     * databases
670
-     *
671
-     * @return array
672
-     * @throws EE_Error
673
-     * @throws InvalidArgumentException
674
-     * @throws InvalidSessionDataException
675
-     * @throws InvalidDataTypeException
676
-     * @throws InvalidInterfaceException
677
-     * @throws RuntimeException
678
-     */
679
-    protected function _retrieve_session_data()
680
-    {
681
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
682
-        try {
683
-            // we're using WP's Transient API to store session data using the PHP session ID as the option name
684
-            $session_data = $this->cache_storage->get($ssn_key, false);
685
-            if (empty($session_data)) {
686
-                return array();
687
-            }
688
-            if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
689
-                $hash_check = $this->cache_storage->get(
690
-                    EE_Session::hash_check_prefix . $this->_sid,
691
-                    false
692
-                );
693
-                if ($hash_check && $hash_check !== md5($session_data)) {
694
-                    EE_Error::add_error(
695
-                        sprintf(
696
-                            esc_html__(
697
-                                'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
698
-                                'event_espresso'
699
-                            ),
700
-                            EE_Session::session_id_prefix . $this->_sid
701
-                        ),
702
-                        __FILE__,
703
-                        __FUNCTION__,
704
-                        __LINE__
705
-                    );
706
-                }
707
-            }
708
-        } catch (Exception $e) {
709
-            // let's just eat that error for now and attempt to correct any corrupted data
710
-            global $wpdb;
711
-            $row = $wpdb->get_row(
712
-                $wpdb->prepare(
713
-                    "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
714
-                    '_transient_' . $ssn_key
715
-                )
716
-            );
717
-            $session_data = is_object($row) ? $row->option_value : null;
718
-            if ($session_data) {
719
-                $session_data = preg_replace_callback(
720
-                    '!s:(d+):"(.*?)";!',
721
-                    function ($match) {
722
-                        return $match[1] === strlen($match[2])
723
-                            ? $match[0]
724
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
725
-                    },
726
-                    $session_data
727
-                );
728
-            }
729
-            $session_data = maybe_unserialize($session_data);
730
-        }
731
-        // in case the data is encoded... try to decode it
732
-        $session_data = $this->encryption instanceof EE_Encryption
733
-            ? $this->encryption->base64_string_decode($session_data)
734
-            : $session_data;
735
-        if (! is_array($session_data)) {
736
-            try {
737
-                $session_data = maybe_unserialize($session_data);
738
-            } catch (Exception $e) {
739
-                $msg = esc_html__(
740
-                    'An error occurred while attempting to unserialize the session data.',
741
-                    'event_espresso'
742
-                );
743
-                $msg .= WP_DEBUG
744
-                    ? '<br><pre>'
745
-                      . print_r($session_data, true)
746
-                      . '</pre><br>'
747
-                      . $this->find_serialize_error($session_data)
748
-                    : '';
749
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
750
-                throw new InvalidSessionDataException($msg, 0, $e);
751
-            }
752
-        }
753
-        // just a check to make sure the session array is indeed an array
754
-        if (! is_array($session_data)) {
755
-            // no?!?! then something is wrong
756
-            $msg = esc_html__(
757
-                'The session data is missing, invalid, or corrupted.',
758
-                'event_espresso'
759
-            );
760
-            $msg .= WP_DEBUG
761
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
762
-                : '';
763
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
764
-            throw new InvalidSessionDataException($msg);
765
-        }
766
-        if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
767
-            $session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
768
-                $session_data['transaction']
769
-            );
770
-        }
771
-        return $session_data;
772
-    }
773
-
774
-
775
-    /**
776
-     * _generate_session_id
777
-     * Retrieves the PHP session id either directly from the PHP session,
778
-     * or from the request array if it was passed in from an AJAX request.
779
-     * The session id is then salted and hashed (mmm sounds tasty)
780
-     * so that it can be safely used as a request param
781
-     *
782
-     * @return string
783
-     */
784
-    protected function _generate_session_id()
785
-    {
786
-        // check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
787
-        $session_id = $this->request->requestParamIsSet('EESID')
788
-            ? $this->request->getRequestParam('EESID')
789
-            : md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
790
-        return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
791
-    }
792
-
793
-
794
-    /**
795
-     * _get_sid_salt
796
-     *
797
-     * @return string
798
-     */
799
-    protected function _get_sid_salt()
800
-    {
801
-        // was session id salt already saved to db ?
802
-        if (empty($this->_sid_salt)) {
803
-            // no?  then maybe use WP defined constant
804
-            if (defined('AUTH_SALT')) {
805
-                $this->_sid_salt = AUTH_SALT;
806
-            }
807
-            // if salt doesn't exist or is too short
808
-            if (strlen($this->_sid_salt) < 32) {
809
-                // create a new one
810
-                $this->_sid_salt = wp_generate_password(64);
811
-            }
812
-            // and save it as a permanent session setting
813
-            $this->updateSessionSettings(array('sid_salt' => $this->_sid_salt));
814
-        }
815
-        return $this->_sid_salt;
816
-    }
817
-
818
-
819
-    /**
820
-     * _set_init_access_and_expiration
821
-     *
822
-     * @return void
823
-     */
824
-    protected function _set_init_access_and_expiration()
825
-    {
826
-        $this->_time = time();
827
-        $this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
828
-        // set initial site access time
829
-        $this->_session_data['init_access'] = $this->_time;
830
-        // and the session expiration
831
-        $this->_session_data['expiration'] = $this->_expiration;
832
-    }
833
-
834
-
835
-    /**
836
-     * @update session data  prior to saving to the db
837
-     * @param bool $new_session
838
-     * @return bool TRUE on success, FALSE on fail
839
-     * @throws EE_Error
840
-     * @throws InvalidArgumentException
841
-     * @throws InvalidDataTypeException
842
-     * @throws InvalidInterfaceException
843
-     * @throws ReflectionException
844
-     */
845
-    public function update($new_session = false)
846
-    {
847
-        $this->_session_data = is_array($this->_session_data) && isset($this->_session_data['id'])
848
-            ? $this->_session_data
849
-            : array();
850
-        if (empty($this->_session_data)) {
851
-            $this->_set_defaults();
852
-        }
853
-        $session_data = array();
854
-        foreach ($this->_session_data as $key => $value) {
855
-            switch ($key) {
856
-                case 'id':
857
-                    // session ID
858
-                    $session_data['id'] = $this->_sid;
859
-                    break;
860
-                case 'ip_address':
861
-                    // visitor ip address
862
-                    $session_data['ip_address'] = $this->request->ipAddress();
863
-                    break;
864
-                case 'user_agent':
865
-                    // visitor user_agent
866
-                    $session_data['user_agent'] = $this->_user_agent;
867
-                    break;
868
-                case 'init_access':
869
-                    $session_data['init_access'] = absint($value);
870
-                    break;
871
-                case 'last_access':
872
-                    // current access time
873
-                    $session_data['last_access'] = $this->_time;
874
-                    break;
875
-                case 'expiration':
876
-                    // when the session expires
877
-                    $session_data['expiration'] = ! empty($this->_expiration)
878
-                        ? $this->_expiration
879
-                        : $session_data['init_access'] + $this->session_lifespan->inSeconds();
880
-                    break;
881
-                case 'user_id':
882
-                    // current user if logged in
883
-                    $session_data['user_id'] = $this->_wp_user_id();
884
-                    break;
885
-                case 'pages_visited':
886
-                    $page_visit = $this->_get_page_visit();
887
-                    if ($page_visit) {
888
-                        // set pages visited where the first will be the http referrer
889
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
890
-                        // we'll only save the last 10 page visits.
891
-                        $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
892
-                    }
893
-                    break;
894
-                default:
895
-                    // carry any other data over
896
-                    $session_data[ $key ] = $this->_session_data[ $key ];
897
-            }
898
-        }
899
-        $this->_session_data = $session_data;
900
-        // creating a new session does not require saving to the db just yet
901
-        if (! $new_session) {
902
-            // ready? let's save
903
-            if ($this->_save_session_to_db()) {
904
-                return true;
905
-            }
906
-            return false;
907
-        }
908
-        // meh, why not?
909
-        return true;
910
-    }
911
-
912
-
913
-    /**
914
-     * @create session data array
915
-     * @throws EE_Error
916
-     * @throws InvalidArgumentException
917
-     * @throws InvalidDataTypeException
918
-     * @throws InvalidInterfaceException
919
-     * @throws ReflectionException
920
-     */
921
-    private function _create_espresso_session()
922
-    {
923
-        do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
924
-        // use the update function for now with $new_session arg set to TRUE
925
-        $this->update(true);
926
-    }
927
-
928
-    /**
929
-     * Detects if there is anything worth saving in the session (eg the cart is a good one, notices are pretty good
930
-     * too). This is used when determining if we want to save the session or not.
931
-     * @since 4.9.67.p
932
-     * @return bool
933
-     */
934
-    private function sessionHasStuffWorthSaving()
935
-    {
936
-        return $this->save_state === EE_Session::SAVE_STATE_DIRTY
937
-               // we may want to eventually remove the following
938
-               // on the assumption that the above check is enough
939
-               || $this->cart() instanceof EE_Cart
940
-               || (
941
-                   isset($this->_session_data['ee_notices'])
942
-                   && (
943
-                       ! empty($this->_session_data['ee_notices']['attention'])
944
-                       || ! empty($this->_session_data['ee_notices']['errors'])
945
-                       || ! empty($this->_session_data['ee_notices']['success'])
946
-                   )
947
-               );
948
-    }
949
-
950
-
951
-    /**
952
-     * _save_session_to_db
953
-     *
954
-     * @param bool $clear_session
955
-     * @return bool
956
-     * @throws EE_Error
957
-     * @throws InvalidArgumentException
958
-     * @throws InvalidDataTypeException
959
-     * @throws InvalidInterfaceException
960
-     * @throws ReflectionException
961
-     */
962
-    private function _save_session_to_db($clear_session = false)
963
-    {
964
-        // don't save sessions for crawlers
965
-        // and unless we're deleting the session data, don't save anything if there isn't a cart
966
-        if (
967
-            $this->request->isBot()
968
-            || (
969
-                ! $clear_session
970
-                && ! $this->sessionHasStuffWorthSaving()
971
-                && apply_filters('FHEE__EE_Session___save_session_to_db__abort_session_save', true)
972
-            )
973
-        ) {
974
-            return false;
975
-        }
976
-        $transaction = $this->transaction();
977
-        if ($transaction instanceof EE_Transaction) {
978
-            if (! $transaction->ID()) {
979
-                $transaction->save();
980
-            }
981
-            $this->_session_data['transaction'] = $transaction->ID();
982
-        }
983
-        // then serialize all of our session data
984
-        $session_data = serialize($this->_session_data);
985
-        // do we need to also encode it to avoid corrupted data when saved to the db?
986
-        $session_data = $this->_use_encryption
987
-            ? $this->encryption->base64_string_encode($session_data)
988
-            : $session_data;
989
-        // maybe save hash check
990
-        if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
991
-            $this->cache_storage->add(
992
-                EE_Session::hash_check_prefix . $this->_sid,
993
-                md5($session_data),
994
-                $this->session_lifespan->inSeconds()
995
-            );
996
-        }
997
-        // we're using the Transient API for storing session data,
998
-        $saved = $this->cache_storage->add(
999
-            EE_Session::session_id_prefix . $this->_sid,
1000
-            $session_data,
1001
-            $this->session_lifespan->inSeconds()
1002
-        );
1003
-        $this->setSaveState(EE_Session::SAVE_STATE_CLEAN);
1004
-        return $saved;
1005
-    }
1006
-
1007
-
1008
-    /**
1009
-     * @get    the full page request the visitor is accessing
1010
-     * @return string
1011
-     */
1012
-    public function _get_page_visit()
1013
-    {
1014
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
1015
-        // check for request url
1016
-        if ($this->request->serverParamIsSet('REQUEST_URI')) {
1017
-            $page_id = '?';
1018
-            $e_reg = '';
1019
-            $request_uri = $this->request->getServerParam('REQUEST_URI');
1020
-            $ru_bits = explode('?', $request_uri);
1021
-            $request_uri = $ru_bits[0];
1022
-            $http_host = $this->request->getServerParam('HTTP_HOST');
1023
-            // check for page_id in SERVER REQUEST
1024
-            if ($this->request->requestParamIsSet('page_id')) {
1025
-                // rebuild $e_reg without any of the extra parameters
1026
-                $page_id .= 'page_id=' . $this->request->getRequestParam('page_id', 0, 'int') . '&amp;';
1027
-            }
1028
-            // check for $e_reg in SERVER REQUEST
1029
-            if ($this->request->requestParamIsSet('ee')) {
1030
-                // rebuild $e_reg without any of the extra parameters
1031
-                $e_reg = 'ee=' . $this->request->getRequestParam('ee');
1032
-            }
1033
-            $page_visit = esc_url(rtrim($http_host . $request_uri . $page_id . $e_reg, '?'));
1034
-        }
1035
-        return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
1036
-    }
1037
-
1038
-
1039
-    /**
1040
-     * @the    current wp user id
1041
-     * @return int
1042
-     */
1043
-    public function _wp_user_id()
1044
-    {
1045
-        // if I need to explain the following lines of code, then you shouldn't be looking at this!
1046
-        $this->_wp_user_id = get_current_user_id();
1047
-        return $this->_wp_user_id;
1048
-    }
1049
-
1050
-
1051
-    /**
1052
-     * Clear EE_Session data
1053
-     *
1054
-     * @param string $class
1055
-     * @param string $function
1056
-     * @return void
1057
-     * @throws EE_Error
1058
-     * @throws InvalidArgumentException
1059
-     * @throws InvalidDataTypeException
1060
-     * @throws InvalidInterfaceException
1061
-     * @throws ReflectionException
1062
-     */
1063
-    public function clear_session($class = '', $function = '')
1064
-    {
26
+	const session_id_prefix = 'ee_ssn_';
27
+
28
+	const hash_check_prefix = 'ee_shc_';
29
+
30
+	const OPTION_NAME_SETTINGS = 'ee_session_settings';
31
+
32
+	const STATUS_CLOSED = 0;
33
+
34
+	const STATUS_OPEN = 1;
35
+
36
+	const SAVE_STATE_CLEAN = 'clean';
37
+	const SAVE_STATE_DIRTY = 'dirty';
38
+
39
+
40
+	/**
41
+	 * instance of the EE_Session object
42
+	 *
43
+	 * @var EE_Session
44
+	 */
45
+	private static $_instance;
46
+
47
+	/**
48
+	 * @var CacheStorageInterface $cache_storage
49
+	 */
50
+	protected $cache_storage;
51
+
52
+	/**
53
+	 * @var EE_Encryption $encryption
54
+	 */
55
+	protected $encryption;
56
+
57
+	/**
58
+	 * @var SessionStartHandler $session_start_handler
59
+	 */
60
+	protected $session_start_handler;
61
+
62
+	/**
63
+	 * the session id
64
+	 *
65
+	 * @var string
66
+	 */
67
+	private $_sid;
68
+
69
+	/**
70
+	 * session id salt
71
+	 *
72
+	 * @var string
73
+	 */
74
+	private $_sid_salt;
75
+
76
+	/**
77
+	 * session data
78
+	 *
79
+	 * @var array
80
+	 */
81
+	private $_session_data = array();
82
+
83
+	/**
84
+	 * how long an EE session lasts
85
+	 * default session lifespan of 1 hour (for not so instant IPNs)
86
+	 *
87
+	 * @var SessionLifespan $session_lifespan
88
+	 */
89
+	private $session_lifespan;
90
+
91
+	/**
92
+	 * session expiration time as Unix timestamp in GMT
93
+	 *
94
+	 * @var int
95
+	 */
96
+	private $_expiration;
97
+
98
+	/**
99
+	 * whether or not session has expired at some point
100
+	 *
101
+	 * @var boolean
102
+	 */
103
+	private $_expired = false;
104
+
105
+	/**
106
+	 * current time as Unix timestamp in GMT
107
+	 *
108
+	 * @var int
109
+	 */
110
+	private $_time;
111
+
112
+	/**
113
+	 * whether to encrypt session data
114
+	 *
115
+	 * @var bool
116
+	 */
117
+	private $_use_encryption;
118
+
119
+	/**
120
+	 * well... according to the server...
121
+	 *
122
+	 * @var null
123
+	 */
124
+	private $_user_agent;
125
+
126
+	/**
127
+	 * do you really trust the server ?
128
+	 *
129
+	 * @var null
130
+	 */
131
+	private $_ip_address;
132
+
133
+	/**
134
+	 * current WP user_id
135
+	 *
136
+	 * @var null
137
+	 */
138
+	private $_wp_user_id;
139
+
140
+	/**
141
+	 * array for defining default session vars
142
+	 *
143
+	 * @var array
144
+	 */
145
+	private $_default_session_vars = array(
146
+		'id'            => null,
147
+		'user_id'       => null,
148
+		'ip_address'    => null,
149
+		'user_agent'    => null,
150
+		'init_access'   => null,
151
+		'last_access'   => null,
152
+		'expiration'    => null,
153
+		'pages_visited' => array(),
154
+	);
155
+
156
+	/**
157
+	 * timestamp for when last garbage collection cycle was performed
158
+	 *
159
+	 * @var int $_last_gc
160
+	 */
161
+	private $_last_gc;
162
+
163
+	/**
164
+	 * @var RequestInterface $request
165
+	 */
166
+	protected $request;
167
+
168
+	/**
169
+	 * whether session is active or not
170
+	 *
171
+	 * @var int $status
172
+	 */
173
+	private $status = EE_Session::STATUS_CLOSED;
174
+
175
+	/**
176
+	 * whether session data has changed therefore requiring a session save
177
+	 *
178
+	 * @var string $save_state
179
+	 */
180
+	private $save_state = EE_Session::SAVE_STATE_CLEAN;
181
+
182
+
183
+	/**
184
+	 * @singleton method used to instantiate class object
185
+	 * @param CacheStorageInterface $cache_storage
186
+	 * @param SessionLifespan|null  $lifespan
187
+	 * @param RequestInterface      $request
188
+	 * @param SessionStartHandler   $session_start_handler
189
+	 * @param EE_Encryption         $encryption
190
+	 * @return EE_Session
191
+	 * @throws InvalidArgumentException
192
+	 * @throws InvalidDataTypeException
193
+	 * @throws InvalidInterfaceException
194
+	 */
195
+	public static function instance(
196
+		CacheStorageInterface $cache_storage = null,
197
+		SessionLifespan $lifespan = null,
198
+		RequestInterface $request = null,
199
+		SessionStartHandler $session_start_handler = null,
200
+		EE_Encryption $encryption = null
201
+	) {
202
+		// check if class object is instantiated
203
+		// session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
204
+		// add_filter( 'FHEE_load_EE_Session', '__return_false' );
205
+		if (
206
+			! self::$_instance instanceof EE_Session
207
+			&& $cache_storage instanceof CacheStorageInterface
208
+			&& $lifespan instanceof SessionLifespan
209
+			&& $request instanceof RequestInterface
210
+			&& $session_start_handler instanceof SessionStartHandler
211
+			&& apply_filters('FHEE_load_EE_Session', true)
212
+		) {
213
+			self::$_instance = new self(
214
+				$cache_storage,
215
+				$lifespan,
216
+				$request,
217
+				$session_start_handler,
218
+				$encryption
219
+			);
220
+		}
221
+		return self::$_instance;
222
+	}
223
+
224
+
225
+	/**
226
+	 * protected constructor to prevent direct creation
227
+	 *
228
+	 * @param CacheStorageInterface $cache_storage
229
+	 * @param SessionLifespan       $lifespan
230
+	 * @param RequestInterface      $request
231
+	 * @param SessionStartHandler   $session_start_handler
232
+	 * @param EE_Encryption         $encryption
233
+	 * @throws InvalidArgumentException
234
+	 * @throws InvalidDataTypeException
235
+	 * @throws InvalidInterfaceException
236
+	 */
237
+	protected function __construct(
238
+		CacheStorageInterface $cache_storage,
239
+		SessionLifespan $lifespan,
240
+		RequestInterface $request,
241
+		SessionStartHandler $session_start_handler,
242
+		EE_Encryption $encryption = null
243
+	) {
244
+		// session loading is turned ON by default,
245
+		// but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
246
+		// (which currently fires on the init hook at priority 9),
247
+		// can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
248
+		if (! apply_filters('FHEE_load_EE_Session', true)) {
249
+			return;
250
+		}
251
+		$this->session_start_handler = $session_start_handler;
252
+		$this->session_lifespan = $lifespan;
253
+		$this->request = $request;
254
+		if (! defined('ESPRESSO_SESSION')) {
255
+			define('ESPRESSO_SESSION', true);
256
+		}
257
+		// retrieve session options from db
258
+		$session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
259
+		if (! empty($session_settings)) {
260
+			// cycle though existing session options
261
+			foreach ($session_settings as $var_name => $session_setting) {
262
+				// set values for class properties
263
+				$var_name = '_' . $var_name;
264
+				$this->{$var_name} = $session_setting;
265
+			}
266
+		}
267
+		$this->cache_storage = $cache_storage;
268
+		// are we using encryption?
269
+		$this->_use_encryption = $encryption instanceof EE_Encryption
270
+								 && EE_Registry::instance()->CFG->admin->encode_session_data();
271
+		// encrypt data via: $this->encryption->encrypt();
272
+		$this->encryption = $encryption;
273
+		// filter hook allows outside functions/classes/plugins to change default empty cart
274
+		$extra_default_session_vars = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', array());
275
+		array_merge($this->_default_session_vars, $extra_default_session_vars);
276
+		// apply default session vars
277
+		$this->_set_defaults();
278
+		add_action('AHEE__EE_System__initialize', array($this, 'open_session'));
279
+		// check request for 'clear_session' param
280
+		add_action('AHEE__EE_Request_Handler__construct__complete', array($this, 'wp_loaded'));
281
+		// once everything is all said and done,
282
+		add_action('shutdown', array($this, 'update'), 100);
283
+		add_action('shutdown', array($this, 'garbageCollection'), 1000);
284
+		$this->configure_garbage_collection_filters();
285
+	}
286
+
287
+
288
+	/**
289
+	 * @return bool
290
+	 * @throws InvalidArgumentException
291
+	 * @throws InvalidDataTypeException
292
+	 * @throws InvalidInterfaceException
293
+	 */
294
+	public static function isLoadedAndActive()
295
+	{
296
+		return did_action('AHEE__EE_System__core_loaded_and_ready')
297
+			   && EE_Session::instance() instanceof EE_Session
298
+			   && EE_Session::instance()->isActive();
299
+	}
300
+
301
+
302
+	/**
303
+	 * @return bool
304
+	 */
305
+	public function isActive()
306
+	{
307
+		return $this->status === EE_Session::STATUS_OPEN;
308
+	}
309
+
310
+
311
+	/**
312
+	 * @return void
313
+	 * @throws EE_Error
314
+	 * @throws InvalidArgumentException
315
+	 * @throws InvalidDataTypeException
316
+	 * @throws InvalidInterfaceException
317
+	 * @throws InvalidSessionDataException
318
+	 * @throws RuntimeException
319
+	 * @throws ReflectionException
320
+	 */
321
+	public function open_session()
322
+	{
323
+		// check for existing session and retrieve it from db
324
+		if (! $this->_espresso_session()) {
325
+			// or just start a new one
326
+			$this->_create_espresso_session();
327
+		}
328
+	}
329
+
330
+
331
+	/**
332
+	 * @return bool
333
+	 */
334
+	public function expired()
335
+	{
336
+		return $this->_expired;
337
+	}
338
+
339
+
340
+	/**
341
+	 * @return void
342
+	 */
343
+	public function reset_expired()
344
+	{
345
+		$this->_expired = false;
346
+	}
347
+
348
+
349
+	/**
350
+	 * @return int
351
+	 */
352
+	public function expiration()
353
+	{
354
+		return $this->_expiration;
355
+	}
356
+
357
+
358
+	/**
359
+	 * @return int
360
+	 */
361
+	public function extension()
362
+	{
363
+		return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
364
+	}
365
+
366
+
367
+	/**
368
+	 * @param int $time number of seconds to add to session expiration
369
+	 */
370
+	public function extend_expiration($time = 0)
371
+	{
372
+		$time = $time ? $time : $this->extension();
373
+		$this->_expiration += absint($time);
374
+	}
375
+
376
+
377
+	/**
378
+	 * @return int
379
+	 */
380
+	public function lifespan()
381
+	{
382
+		return $this->session_lifespan->inSeconds();
383
+	}
384
+
385
+
386
+	/**
387
+	 * Marks whether the session data has been updated or not.
388
+	 * Valid options are:
389
+	 *      EE_Session::SAVE_STATE_CLEAN - session data remains unchanged and updating is not necessary
390
+	 *      EE_Session::SAVE_STATE_DIRTY - session data has changed since last save and needs to be updated
391
+	 * default value is EE_Session::SAVE_STATE_DIRTY
392
+	 *
393
+	 * @param string $save_state
394
+	 */
395
+	public function setSaveState($save_state = EE_Session::SAVE_STATE_DIRTY)
396
+	{
397
+		$valid_save_states = [
398
+			EE_Session::SAVE_STATE_CLEAN,
399
+			EE_Session::SAVE_STATE_DIRTY,
400
+		];
401
+		if (! in_array($save_state, $valid_save_states, true)) {
402
+			$save_state = EE_Session::SAVE_STATE_DIRTY;
403
+		}
404
+		$this->save_state = $save_state;
405
+	}
406
+
407
+
408
+
409
+	/**
410
+	 * This just sets some defaults for the _session data property
411
+	 *
412
+	 * @return void
413
+	 */
414
+	private function _set_defaults()
415
+	{
416
+		// set some defaults
417
+		foreach ($this->_default_session_vars as $key => $default_var) {
418
+			if (is_array($default_var)) {
419
+				$this->_session_data[ $key ] = array();
420
+			} else {
421
+				$this->_session_data[ $key ] = '';
422
+			}
423
+		}
424
+	}
425
+
426
+
427
+	/**
428
+	 * @retrieve  session data
429
+	 * @return    string
430
+	 */
431
+	public function id()
432
+	{
433
+		return $this->_sid;
434
+	}
435
+
436
+
437
+	/**
438
+	 * @param \EE_Cart $cart
439
+	 * @return bool
440
+	 */
441
+	public function set_cart(EE_Cart $cart)
442
+	{
443
+		$this->_session_data['cart'] = $cart;
444
+		$this->setSaveState();
445
+		return true;
446
+	}
447
+
448
+
449
+	/**
450
+	 * reset_cart
451
+	 */
452
+	public function reset_cart()
453
+	{
454
+		do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
455
+		$this->_session_data['cart'] = null;
456
+		$this->setSaveState();
457
+	}
458
+
459
+
460
+	/**
461
+	 * @return \EE_Cart
462
+	 */
463
+	public function cart()
464
+	{
465
+		return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
466
+			? $this->_session_data['cart']
467
+			: null;
468
+	}
469
+
470
+
471
+	/**
472
+	 * @param \EE_Checkout $checkout
473
+	 * @return bool
474
+	 */
475
+	public function set_checkout(EE_Checkout $checkout)
476
+	{
477
+		$this->_session_data['checkout'] = $checkout;
478
+		$this->setSaveState();
479
+		return true;
480
+	}
481
+
482
+
483
+	/**
484
+	 * reset_checkout
485
+	 */
486
+	public function reset_checkout()
487
+	{
488
+		do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
489
+		$this->_session_data['checkout'] = null;
490
+		$this->setSaveState();
491
+	}
492
+
493
+
494
+	/**
495
+	 * @return \EE_Checkout
496
+	 */
497
+	public function checkout()
498
+	{
499
+		return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
500
+			? $this->_session_data['checkout']
501
+			: null;
502
+	}
503
+
504
+
505
+	/**
506
+	 * @param \EE_Transaction $transaction
507
+	 * @return bool
508
+	 * @throws EE_Error
509
+	 */
510
+	public function set_transaction(EE_Transaction $transaction)
511
+	{
512
+		// first remove the session from the transaction before we save the transaction in the session
513
+		$transaction->set_txn_session_data(null);
514
+		$this->_session_data['transaction'] = $transaction;
515
+		$this->setSaveState();
516
+		return true;
517
+	}
518
+
519
+
520
+	/**
521
+	 * reset_transaction
522
+	 */
523
+	public function reset_transaction()
524
+	{
525
+		do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
526
+		$this->_session_data['transaction'] = null;
527
+		$this->setSaveState();
528
+	}
529
+
530
+
531
+	/**
532
+	 * @return \EE_Transaction
533
+	 */
534
+	public function transaction()
535
+	{
536
+		return isset($this->_session_data['transaction'])
537
+			   && $this->_session_data['transaction'] instanceof EE_Transaction
538
+			? $this->_session_data['transaction']
539
+			: null;
540
+	}
541
+
542
+
543
+	/**
544
+	 * retrieve session data
545
+	 *
546
+	 * @param null $key
547
+	 * @param bool $reset_cache
548
+	 * @return array
549
+	 */
550
+	public function get_session_data($key = null, $reset_cache = false)
551
+	{
552
+		if ($reset_cache) {
553
+			$this->reset_cart();
554
+			$this->reset_checkout();
555
+			$this->reset_transaction();
556
+		}
557
+		if (! empty($key)) {
558
+			return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
559
+		}
560
+		return $this->_session_data;
561
+	}
562
+
563
+
564
+	/**
565
+	 * Returns TRUE on success, FALSE on fail
566
+	 *
567
+	 * @param array $data
568
+	 * @return bool
569
+	 */
570
+	public function set_session_data($data)
571
+	{
572
+		// nothing ??? bad data ??? go home!
573
+		if (empty($data) || ! is_array($data)) {
574
+			EE_Error::add_error(
575
+				esc_html__(
576
+					'No session data or invalid session data was provided.',
577
+					'event_espresso'
578
+				),
579
+				__FILE__,
580
+				__FUNCTION__,
581
+				__LINE__
582
+			);
583
+			return false;
584
+		}
585
+		foreach ($data as $key => $value) {
586
+			if (isset($this->_default_session_vars[ $key ])) {
587
+				EE_Error::add_error(
588
+					sprintf(
589
+						esc_html__(
590
+							'Sorry! %s is a default session datum and can not be reset.',
591
+							'event_espresso'
592
+						),
593
+						$key
594
+					),
595
+					__FILE__,
596
+					__FUNCTION__,
597
+					__LINE__
598
+				);
599
+				return false;
600
+			}
601
+			$this->_session_data[ $key ] = $value;
602
+			$this->setSaveState();
603
+		}
604
+		return true;
605
+	}
606
+
607
+
608
+	/**
609
+	 * @initiate session
610
+	 * @return bool TRUE on success, FALSE on fail
611
+	 * @throws EE_Error
612
+	 * @throws InvalidArgumentException
613
+	 * @throws InvalidDataTypeException
614
+	 * @throws InvalidInterfaceException
615
+	 * @throws InvalidSessionDataException
616
+	 * @throws RuntimeException
617
+	 * @throws ReflectionException
618
+	 */
619
+	private function _espresso_session()
620
+	{
621
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
622
+		$this->session_start_handler->startSession();
623
+		$this->status = EE_Session::STATUS_OPEN;
624
+		// get our modified session ID
625
+		$this->_sid = $this->_generate_session_id();
626
+		// and the visitors IP
627
+		$this->_ip_address = $this->request->ipAddress();
628
+		// set the "user agent"
629
+		$this->_user_agent = $this->request->userAgent();
630
+		// now let's retrieve what's in the db
631
+		$session_data = $this->_retrieve_session_data();
632
+		if (! empty($session_data)) {
633
+			// get the current time in UTC
634
+			$this->_time = $this->_time !== null ? $this->_time : time();
635
+			// and reset the session expiration
636
+			$this->_expiration = isset($session_data['expiration'])
637
+				? $session_data['expiration']
638
+				: $this->_time + $this->session_lifespan->inSeconds();
639
+		} else {
640
+			// set initial site access time and the session expiration
641
+			$this->_set_init_access_and_expiration();
642
+			// set referer
643
+			$this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = esc_attr(
644
+				$this->request->getServerParam('HTTP_REFERER')
645
+			);
646
+			// no previous session = go back and create one (on top of the data above)
647
+			return false;
648
+		}
649
+		// now the user agent
650
+		if ($session_data['user_agent'] !== $this->_user_agent) {
651
+			return false;
652
+		}
653
+		// wait a minute... how old are you?
654
+		if ($this->_time > $this->_expiration) {
655
+			// yer too old fer me!
656
+			$this->_expired = true;
657
+			// wipe out everything that isn't a default session datum
658
+			$this->clear_session(__CLASS__, __FUNCTION__);
659
+		}
660
+		// make event espresso session data available to plugin
661
+		$this->_session_data = array_merge($this->_session_data, $session_data);
662
+		return true;
663
+	}
664
+
665
+
666
+	/**
667
+	 * _get_session_data
668
+	 * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
669
+	 * databases
670
+	 *
671
+	 * @return array
672
+	 * @throws EE_Error
673
+	 * @throws InvalidArgumentException
674
+	 * @throws InvalidSessionDataException
675
+	 * @throws InvalidDataTypeException
676
+	 * @throws InvalidInterfaceException
677
+	 * @throws RuntimeException
678
+	 */
679
+	protected function _retrieve_session_data()
680
+	{
681
+		$ssn_key = EE_Session::session_id_prefix . $this->_sid;
682
+		try {
683
+			// we're using WP's Transient API to store session data using the PHP session ID as the option name
684
+			$session_data = $this->cache_storage->get($ssn_key, false);
685
+			if (empty($session_data)) {
686
+				return array();
687
+			}
688
+			if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
689
+				$hash_check = $this->cache_storage->get(
690
+					EE_Session::hash_check_prefix . $this->_sid,
691
+					false
692
+				);
693
+				if ($hash_check && $hash_check !== md5($session_data)) {
694
+					EE_Error::add_error(
695
+						sprintf(
696
+							esc_html__(
697
+								'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
698
+								'event_espresso'
699
+							),
700
+							EE_Session::session_id_prefix . $this->_sid
701
+						),
702
+						__FILE__,
703
+						__FUNCTION__,
704
+						__LINE__
705
+					);
706
+				}
707
+			}
708
+		} catch (Exception $e) {
709
+			// let's just eat that error for now and attempt to correct any corrupted data
710
+			global $wpdb;
711
+			$row = $wpdb->get_row(
712
+				$wpdb->prepare(
713
+					"SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
714
+					'_transient_' . $ssn_key
715
+				)
716
+			);
717
+			$session_data = is_object($row) ? $row->option_value : null;
718
+			if ($session_data) {
719
+				$session_data = preg_replace_callback(
720
+					'!s:(d+):"(.*?)";!',
721
+					function ($match) {
722
+						return $match[1] === strlen($match[2])
723
+							? $match[0]
724
+							: 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
725
+					},
726
+					$session_data
727
+				);
728
+			}
729
+			$session_data = maybe_unserialize($session_data);
730
+		}
731
+		// in case the data is encoded... try to decode it
732
+		$session_data = $this->encryption instanceof EE_Encryption
733
+			? $this->encryption->base64_string_decode($session_data)
734
+			: $session_data;
735
+		if (! is_array($session_data)) {
736
+			try {
737
+				$session_data = maybe_unserialize($session_data);
738
+			} catch (Exception $e) {
739
+				$msg = esc_html__(
740
+					'An error occurred while attempting to unserialize the session data.',
741
+					'event_espresso'
742
+				);
743
+				$msg .= WP_DEBUG
744
+					? '<br><pre>'
745
+					  . print_r($session_data, true)
746
+					  . '</pre><br>'
747
+					  . $this->find_serialize_error($session_data)
748
+					: '';
749
+				$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
750
+				throw new InvalidSessionDataException($msg, 0, $e);
751
+			}
752
+		}
753
+		// just a check to make sure the session array is indeed an array
754
+		if (! is_array($session_data)) {
755
+			// no?!?! then something is wrong
756
+			$msg = esc_html__(
757
+				'The session data is missing, invalid, or corrupted.',
758
+				'event_espresso'
759
+			);
760
+			$msg .= WP_DEBUG
761
+				? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
762
+				: '';
763
+			$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
764
+			throw new InvalidSessionDataException($msg);
765
+		}
766
+		if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
767
+			$session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
768
+				$session_data['transaction']
769
+			);
770
+		}
771
+		return $session_data;
772
+	}
773
+
774
+
775
+	/**
776
+	 * _generate_session_id
777
+	 * Retrieves the PHP session id either directly from the PHP session,
778
+	 * or from the request array if it was passed in from an AJAX request.
779
+	 * The session id is then salted and hashed (mmm sounds tasty)
780
+	 * so that it can be safely used as a request param
781
+	 *
782
+	 * @return string
783
+	 */
784
+	protected function _generate_session_id()
785
+	{
786
+		// check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
787
+		$session_id = $this->request->requestParamIsSet('EESID')
788
+			? $this->request->getRequestParam('EESID')
789
+			: md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
790
+		return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
791
+	}
792
+
793
+
794
+	/**
795
+	 * _get_sid_salt
796
+	 *
797
+	 * @return string
798
+	 */
799
+	protected function _get_sid_salt()
800
+	{
801
+		// was session id salt already saved to db ?
802
+		if (empty($this->_sid_salt)) {
803
+			// no?  then maybe use WP defined constant
804
+			if (defined('AUTH_SALT')) {
805
+				$this->_sid_salt = AUTH_SALT;
806
+			}
807
+			// if salt doesn't exist or is too short
808
+			if (strlen($this->_sid_salt) < 32) {
809
+				// create a new one
810
+				$this->_sid_salt = wp_generate_password(64);
811
+			}
812
+			// and save it as a permanent session setting
813
+			$this->updateSessionSettings(array('sid_salt' => $this->_sid_salt));
814
+		}
815
+		return $this->_sid_salt;
816
+	}
817
+
818
+
819
+	/**
820
+	 * _set_init_access_and_expiration
821
+	 *
822
+	 * @return void
823
+	 */
824
+	protected function _set_init_access_and_expiration()
825
+	{
826
+		$this->_time = time();
827
+		$this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
828
+		// set initial site access time
829
+		$this->_session_data['init_access'] = $this->_time;
830
+		// and the session expiration
831
+		$this->_session_data['expiration'] = $this->_expiration;
832
+	}
833
+
834
+
835
+	/**
836
+	 * @update session data  prior to saving to the db
837
+	 * @param bool $new_session
838
+	 * @return bool TRUE on success, FALSE on fail
839
+	 * @throws EE_Error
840
+	 * @throws InvalidArgumentException
841
+	 * @throws InvalidDataTypeException
842
+	 * @throws InvalidInterfaceException
843
+	 * @throws ReflectionException
844
+	 */
845
+	public function update($new_session = false)
846
+	{
847
+		$this->_session_data = is_array($this->_session_data) && isset($this->_session_data['id'])
848
+			? $this->_session_data
849
+			: array();
850
+		if (empty($this->_session_data)) {
851
+			$this->_set_defaults();
852
+		}
853
+		$session_data = array();
854
+		foreach ($this->_session_data as $key => $value) {
855
+			switch ($key) {
856
+				case 'id':
857
+					// session ID
858
+					$session_data['id'] = $this->_sid;
859
+					break;
860
+				case 'ip_address':
861
+					// visitor ip address
862
+					$session_data['ip_address'] = $this->request->ipAddress();
863
+					break;
864
+				case 'user_agent':
865
+					// visitor user_agent
866
+					$session_data['user_agent'] = $this->_user_agent;
867
+					break;
868
+				case 'init_access':
869
+					$session_data['init_access'] = absint($value);
870
+					break;
871
+				case 'last_access':
872
+					// current access time
873
+					$session_data['last_access'] = $this->_time;
874
+					break;
875
+				case 'expiration':
876
+					// when the session expires
877
+					$session_data['expiration'] = ! empty($this->_expiration)
878
+						? $this->_expiration
879
+						: $session_data['init_access'] + $this->session_lifespan->inSeconds();
880
+					break;
881
+				case 'user_id':
882
+					// current user if logged in
883
+					$session_data['user_id'] = $this->_wp_user_id();
884
+					break;
885
+				case 'pages_visited':
886
+					$page_visit = $this->_get_page_visit();
887
+					if ($page_visit) {
888
+						// set pages visited where the first will be the http referrer
889
+						$this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
890
+						// we'll only save the last 10 page visits.
891
+						$session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
892
+					}
893
+					break;
894
+				default:
895
+					// carry any other data over
896
+					$session_data[ $key ] = $this->_session_data[ $key ];
897
+			}
898
+		}
899
+		$this->_session_data = $session_data;
900
+		// creating a new session does not require saving to the db just yet
901
+		if (! $new_session) {
902
+			// ready? let's save
903
+			if ($this->_save_session_to_db()) {
904
+				return true;
905
+			}
906
+			return false;
907
+		}
908
+		// meh, why not?
909
+		return true;
910
+	}
911
+
912
+
913
+	/**
914
+	 * @create session data array
915
+	 * @throws EE_Error
916
+	 * @throws InvalidArgumentException
917
+	 * @throws InvalidDataTypeException
918
+	 * @throws InvalidInterfaceException
919
+	 * @throws ReflectionException
920
+	 */
921
+	private function _create_espresso_session()
922
+	{
923
+		do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
924
+		// use the update function for now with $new_session arg set to TRUE
925
+		$this->update(true);
926
+	}
927
+
928
+	/**
929
+	 * Detects if there is anything worth saving in the session (eg the cart is a good one, notices are pretty good
930
+	 * too). This is used when determining if we want to save the session or not.
931
+	 * @since 4.9.67.p
932
+	 * @return bool
933
+	 */
934
+	private function sessionHasStuffWorthSaving()
935
+	{
936
+		return $this->save_state === EE_Session::SAVE_STATE_DIRTY
937
+			   // we may want to eventually remove the following
938
+			   // on the assumption that the above check is enough
939
+			   || $this->cart() instanceof EE_Cart
940
+			   || (
941
+				   isset($this->_session_data['ee_notices'])
942
+				   && (
943
+					   ! empty($this->_session_data['ee_notices']['attention'])
944
+					   || ! empty($this->_session_data['ee_notices']['errors'])
945
+					   || ! empty($this->_session_data['ee_notices']['success'])
946
+				   )
947
+			   );
948
+	}
949
+
950
+
951
+	/**
952
+	 * _save_session_to_db
953
+	 *
954
+	 * @param bool $clear_session
955
+	 * @return bool
956
+	 * @throws EE_Error
957
+	 * @throws InvalidArgumentException
958
+	 * @throws InvalidDataTypeException
959
+	 * @throws InvalidInterfaceException
960
+	 * @throws ReflectionException
961
+	 */
962
+	private function _save_session_to_db($clear_session = false)
963
+	{
964
+		// don't save sessions for crawlers
965
+		// and unless we're deleting the session data, don't save anything if there isn't a cart
966
+		if (
967
+			$this->request->isBot()
968
+			|| (
969
+				! $clear_session
970
+				&& ! $this->sessionHasStuffWorthSaving()
971
+				&& apply_filters('FHEE__EE_Session___save_session_to_db__abort_session_save', true)
972
+			)
973
+		) {
974
+			return false;
975
+		}
976
+		$transaction = $this->transaction();
977
+		if ($transaction instanceof EE_Transaction) {
978
+			if (! $transaction->ID()) {
979
+				$transaction->save();
980
+			}
981
+			$this->_session_data['transaction'] = $transaction->ID();
982
+		}
983
+		// then serialize all of our session data
984
+		$session_data = serialize($this->_session_data);
985
+		// do we need to also encode it to avoid corrupted data when saved to the db?
986
+		$session_data = $this->_use_encryption
987
+			? $this->encryption->base64_string_encode($session_data)
988
+			: $session_data;
989
+		// maybe save hash check
990
+		if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
991
+			$this->cache_storage->add(
992
+				EE_Session::hash_check_prefix . $this->_sid,
993
+				md5($session_data),
994
+				$this->session_lifespan->inSeconds()
995
+			);
996
+		}
997
+		// we're using the Transient API for storing session data,
998
+		$saved = $this->cache_storage->add(
999
+			EE_Session::session_id_prefix . $this->_sid,
1000
+			$session_data,
1001
+			$this->session_lifespan->inSeconds()
1002
+		);
1003
+		$this->setSaveState(EE_Session::SAVE_STATE_CLEAN);
1004
+		return $saved;
1005
+	}
1006
+
1007
+
1008
+	/**
1009
+	 * @get    the full page request the visitor is accessing
1010
+	 * @return string
1011
+	 */
1012
+	public function _get_page_visit()
1013
+	{
1014
+		$page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
1015
+		// check for request url
1016
+		if ($this->request->serverParamIsSet('REQUEST_URI')) {
1017
+			$page_id = '?';
1018
+			$e_reg = '';
1019
+			$request_uri = $this->request->getServerParam('REQUEST_URI');
1020
+			$ru_bits = explode('?', $request_uri);
1021
+			$request_uri = $ru_bits[0];
1022
+			$http_host = $this->request->getServerParam('HTTP_HOST');
1023
+			// check for page_id in SERVER REQUEST
1024
+			if ($this->request->requestParamIsSet('page_id')) {
1025
+				// rebuild $e_reg without any of the extra parameters
1026
+				$page_id .= 'page_id=' . $this->request->getRequestParam('page_id', 0, 'int') . '&amp;';
1027
+			}
1028
+			// check for $e_reg in SERVER REQUEST
1029
+			if ($this->request->requestParamIsSet('ee')) {
1030
+				// rebuild $e_reg without any of the extra parameters
1031
+				$e_reg = 'ee=' . $this->request->getRequestParam('ee');
1032
+			}
1033
+			$page_visit = esc_url(rtrim($http_host . $request_uri . $page_id . $e_reg, '?'));
1034
+		}
1035
+		return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
1036
+	}
1037
+
1038
+
1039
+	/**
1040
+	 * @the    current wp user id
1041
+	 * @return int
1042
+	 */
1043
+	public function _wp_user_id()
1044
+	{
1045
+		// if I need to explain the following lines of code, then you shouldn't be looking at this!
1046
+		$this->_wp_user_id = get_current_user_id();
1047
+		return $this->_wp_user_id;
1048
+	}
1049
+
1050
+
1051
+	/**
1052
+	 * Clear EE_Session data
1053
+	 *
1054
+	 * @param string $class
1055
+	 * @param string $function
1056
+	 * @return void
1057
+	 * @throws EE_Error
1058
+	 * @throws InvalidArgumentException
1059
+	 * @throws InvalidDataTypeException
1060
+	 * @throws InvalidInterfaceException
1061
+	 * @throws ReflectionException
1062
+	 */
1063
+	public function clear_session($class = '', $function = '')
1064
+	{
1065 1065
 //         echo '
1066 1066
 // <h3 style="color:#999;line-height:.9em;">
1067 1067
 // <span style="color:#2EA2CC">' . __CLASS__ . '</span>::<span style="color:#E76700">' . __FUNCTION__ . '( ' . $class . '::' . $function . '() )</span><br/>
1068 1068
 // <span style="font-size:9px;font-weight:normal;">' . __FILE__ . '</span>    <b style="font-size:10px;">  ' . __LINE__ . ' </b>
1069 1069
 // </h3>';
1070
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1071
-        $this->reset_cart();
1072
-        $this->reset_checkout();
1073
-        $this->reset_transaction();
1074
-        // wipe out everything that isn't a default session datum
1075
-        $this->reset_data(array_keys($this->_session_data));
1076
-        // reset initial site access time and the session expiration
1077
-        $this->_set_init_access_and_expiration();
1078
-        $this->setSaveState();
1079
-        $this->_save_session_to_db(true);
1080
-    }
1081
-
1082
-
1083
-    /**
1084
-     * resets all non-default session vars. Returns TRUE on success, FALSE on fail
1085
-     *
1086
-     * @param array|mixed $data_to_reset
1087
-     * @param bool        $show_all_notices
1088
-     * @return bool
1089
-     */
1090
-    public function reset_data($data_to_reset = array(), $show_all_notices = false)
1091
-    {
1092
-        // if $data_to_reset is not in an array, then put it in one
1093
-        if (! is_array($data_to_reset)) {
1094
-            $data_to_reset = array($data_to_reset);
1095
-        }
1096
-        // nothing ??? go home!
1097
-        if (empty($data_to_reset)) {
1098
-            EE_Error::add_error(
1099
-                esc_html__(
1100
-                    'No session data could be reset, because no session var name was provided.',
1101
-                    'event_espresso'
1102
-                ),
1103
-                __FILE__,
1104
-                __FUNCTION__,
1105
-                __LINE__
1106
-            );
1107
-            return false;
1108
-        }
1109
-        $return_value = true;
1110
-        // since $data_to_reset is an array, cycle through the values
1111
-        foreach ($data_to_reset as $reset) {
1112
-            // first check to make sure it is a valid session var
1113
-            if (isset($this->_session_data[ $reset ])) {
1114
-                // then check to make sure it is not a default var
1115
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1116
-                    // remove session var
1117
-                    unset($this->_session_data[ $reset ]);
1118
-                    $this->setSaveState();
1119
-                    if ($show_all_notices) {
1120
-                        EE_Error::add_success(
1121
-                            sprintf(
1122
-                                esc_html__('The session variable %s was removed.', 'event_espresso'),
1123
-                                $reset
1124
-                            ),
1125
-                            __FILE__,
1126
-                            __FUNCTION__,
1127
-                            __LINE__
1128
-                        );
1129
-                    }
1130
-                } else {
1131
-                    // yeeeeeeeeerrrrrrrrrrr OUT !!!!
1132
-                    if ($show_all_notices) {
1133
-                        EE_Error::add_error(
1134
-                            sprintf(
1135
-                                esc_html__(
1136
-                                    'Sorry! %s is a default session datum and can not be reset.',
1137
-                                    'event_espresso'
1138
-                                ),
1139
-                                $reset
1140
-                            ),
1141
-                            __FILE__,
1142
-                            __FUNCTION__,
1143
-                            __LINE__
1144
-                        );
1145
-                    }
1146
-                    $return_value = false;
1147
-                }
1148
-            } elseif ($show_all_notices) {
1149
-                // oops! that session var does not exist!
1150
-                EE_Error::add_error(
1151
-                    sprintf(
1152
-                        esc_html__(
1153
-                            'The session item provided, %s, is invalid or does not exist.',
1154
-                            'event_espresso'
1155
-                        ),
1156
-                        $reset
1157
-                    ),
1158
-                    __FILE__,
1159
-                    __FUNCTION__,
1160
-                    __LINE__
1161
-                );
1162
-                $return_value = false;
1163
-            }
1164
-        } // end of foreach
1165
-        return $return_value;
1166
-    }
1167
-
1168
-
1169
-    /**
1170
-     *   wp_loaded
1171
-     *
1172
-     * @throws EE_Error
1173
-     * @throws InvalidDataTypeException
1174
-     * @throws InvalidInterfaceException
1175
-     * @throws InvalidArgumentException
1176
-     * @throws ReflectionException
1177
-     */
1178
-    public function wp_loaded()
1179
-    {
1180
-        if ($this->request->requestParamIsSet('clear_session')) {
1181
-            $this->clear_session(__CLASS__, __FUNCTION__);
1182
-        }
1183
-    }
1184
-
1185
-
1186
-    /**
1187
-     * Used to reset the entire object (for tests).
1188
-     *
1189
-     * @since 4.3.0
1190
-     * @throws EE_Error
1191
-     * @throws InvalidDataTypeException
1192
-     * @throws InvalidInterfaceException
1193
-     * @throws InvalidArgumentException
1194
-     * @throws ReflectionException
1195
-     */
1196
-    public function reset_instance()
1197
-    {
1198
-        $this->clear_session();
1199
-        self::$_instance = null;
1200
-    }
1201
-
1202
-
1203
-    public function configure_garbage_collection_filters()
1204
-    {
1205
-        // run old filter we had for controlling session cleanup
1206
-        $expired_session_transient_delete_query_limit = absint(
1207
-            apply_filters(
1208
-                'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1209
-                50
1210
-            )
1211
-        );
1212
-        // is there a value? or one that is different than the default 50 records?
1213
-        if ($expired_session_transient_delete_query_limit === 0) {
1214
-            // hook into TransientCacheStorage in case Session cleanup was turned off
1215
-            add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1216
-        } elseif ($expired_session_transient_delete_query_limit !== 50) {
1217
-            // or use that for the new transient cleanup query limit
1218
-            add_filter(
1219
-                'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1220
-                function () use ($expired_session_transient_delete_query_limit) {
1221
-                    return $expired_session_transient_delete_query_limit;
1222
-                }
1223
-            );
1224
-        }
1225
-    }
1226
-
1227
-
1228
-    /**
1229
-     * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1230
-     * @param $data1
1231
-     * @return string
1232
-     */
1233
-    private function find_serialize_error($data1)
1234
-    {
1235
-        $error = '<pre>';
1236
-        $data2 = preg_replace_callback(
1237
-            '!s:(\d+):"(.*?)";!',
1238
-            function ($match) {
1239
-                return ($match[1] === strlen($match[2]))
1240
-                    ? $match[0]
1241
-                    : 's:'
1242
-                      . strlen($match[2])
1243
-                      . ':"'
1244
-                      . $match[2]
1245
-                      . '";';
1246
-            },
1247
-            $data1
1248
-        );
1249
-        $max = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1250
-        $error .= $data1 . PHP_EOL;
1251
-        $error .= $data2 . PHP_EOL;
1252
-        for ($i = 0; $i < $max; $i++) {
1253
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1254
-                $error .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1255
-                $error .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1256
-                $error .= "\t-> Line Number = $i" . PHP_EOL;
1257
-                $start = ($i - 20);
1258
-                $start = ($start < 0) ? 0 : $start;
1259
-                $length = 40;
1260
-                $point = $max - $i;
1261
-                if ($point < 20) {
1262
-                    $rlength = 1;
1263
-                    $rpoint = -$point;
1264
-                } else {
1265
-                    $rpoint = $length - 20;
1266
-                    $rlength = 1;
1267
-                }
1268
-                $error .= "\t-> Section Data1  = ";
1269
-                $error .= substr_replace(
1270
-                    substr($data1, $start, $length),
1271
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1272
-                    $rpoint,
1273
-                    $rlength
1274
-                );
1275
-                $error .= PHP_EOL;
1276
-                $error .= "\t-> Section Data2  = ";
1277
-                $error .= substr_replace(
1278
-                    substr($data2, $start, $length),
1279
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1280
-                    $rpoint,
1281
-                    $rlength
1282
-                );
1283
-                $error .= PHP_EOL;
1284
-            }
1285
-        }
1286
-        $error .= '</pre>';
1287
-        return $error;
1288
-    }
1289
-
1290
-
1291
-    /**
1292
-     * Saves an  array of settings used for configuring aspects of session behaviour
1293
-     *
1294
-     * @param array $updated_settings
1295
-     */
1296
-    private function updateSessionSettings(array $updated_settings = array())
1297
-    {
1298
-        // add existing settings, but only if not included in incoming $updated_settings array
1299
-        $updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, array());
1300
-        update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1301
-    }
1302
-
1303
-
1304
-    /**
1305
-     * garbage_collection
1306
-     */
1307
-    public function garbageCollection()
1308
-    {
1309
-        // only perform during regular requests if last garbage collection was over an hour ago
1310
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1311
-            $this->_last_gc = time();
1312
-            $this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1313
-            /** @type WPDB $wpdb */
1314
-            global $wpdb;
1315
-            // filter the query limit. Set to 0 to turn off garbage collection
1316
-            $expired_session_transient_delete_query_limit = absint(
1317
-                apply_filters(
1318
-                    'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1319
-                    50
1320
-                )
1321
-            );
1322
-            // non-zero LIMIT means take out the trash
1323
-            if ($expired_session_transient_delete_query_limit) {
1324
-                $session_key = str_replace('_', '\_', EE_Session::session_id_prefix);
1325
-                $hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1326
-                // since transient expiration timestamps are set in the future, we can compare against NOW
1327
-                // but we only want to pick up any trash that's been around for more than a day
1328
-                $expiration = time() - DAY_IN_SECONDS;
1329
-                $SQL = "
1070
+		do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1071
+		$this->reset_cart();
1072
+		$this->reset_checkout();
1073
+		$this->reset_transaction();
1074
+		// wipe out everything that isn't a default session datum
1075
+		$this->reset_data(array_keys($this->_session_data));
1076
+		// reset initial site access time and the session expiration
1077
+		$this->_set_init_access_and_expiration();
1078
+		$this->setSaveState();
1079
+		$this->_save_session_to_db(true);
1080
+	}
1081
+
1082
+
1083
+	/**
1084
+	 * resets all non-default session vars. Returns TRUE on success, FALSE on fail
1085
+	 *
1086
+	 * @param array|mixed $data_to_reset
1087
+	 * @param bool        $show_all_notices
1088
+	 * @return bool
1089
+	 */
1090
+	public function reset_data($data_to_reset = array(), $show_all_notices = false)
1091
+	{
1092
+		// if $data_to_reset is not in an array, then put it in one
1093
+		if (! is_array($data_to_reset)) {
1094
+			$data_to_reset = array($data_to_reset);
1095
+		}
1096
+		// nothing ??? go home!
1097
+		if (empty($data_to_reset)) {
1098
+			EE_Error::add_error(
1099
+				esc_html__(
1100
+					'No session data could be reset, because no session var name was provided.',
1101
+					'event_espresso'
1102
+				),
1103
+				__FILE__,
1104
+				__FUNCTION__,
1105
+				__LINE__
1106
+			);
1107
+			return false;
1108
+		}
1109
+		$return_value = true;
1110
+		// since $data_to_reset is an array, cycle through the values
1111
+		foreach ($data_to_reset as $reset) {
1112
+			// first check to make sure it is a valid session var
1113
+			if (isset($this->_session_data[ $reset ])) {
1114
+				// then check to make sure it is not a default var
1115
+				if (! array_key_exists($reset, $this->_default_session_vars)) {
1116
+					// remove session var
1117
+					unset($this->_session_data[ $reset ]);
1118
+					$this->setSaveState();
1119
+					if ($show_all_notices) {
1120
+						EE_Error::add_success(
1121
+							sprintf(
1122
+								esc_html__('The session variable %s was removed.', 'event_espresso'),
1123
+								$reset
1124
+							),
1125
+							__FILE__,
1126
+							__FUNCTION__,
1127
+							__LINE__
1128
+						);
1129
+					}
1130
+				} else {
1131
+					// yeeeeeeeeerrrrrrrrrrr OUT !!!!
1132
+					if ($show_all_notices) {
1133
+						EE_Error::add_error(
1134
+							sprintf(
1135
+								esc_html__(
1136
+									'Sorry! %s is a default session datum and can not be reset.',
1137
+									'event_espresso'
1138
+								),
1139
+								$reset
1140
+							),
1141
+							__FILE__,
1142
+							__FUNCTION__,
1143
+							__LINE__
1144
+						);
1145
+					}
1146
+					$return_value = false;
1147
+				}
1148
+			} elseif ($show_all_notices) {
1149
+				// oops! that session var does not exist!
1150
+				EE_Error::add_error(
1151
+					sprintf(
1152
+						esc_html__(
1153
+							'The session item provided, %s, is invalid or does not exist.',
1154
+							'event_espresso'
1155
+						),
1156
+						$reset
1157
+					),
1158
+					__FILE__,
1159
+					__FUNCTION__,
1160
+					__LINE__
1161
+				);
1162
+				$return_value = false;
1163
+			}
1164
+		} // end of foreach
1165
+		return $return_value;
1166
+	}
1167
+
1168
+
1169
+	/**
1170
+	 *   wp_loaded
1171
+	 *
1172
+	 * @throws EE_Error
1173
+	 * @throws InvalidDataTypeException
1174
+	 * @throws InvalidInterfaceException
1175
+	 * @throws InvalidArgumentException
1176
+	 * @throws ReflectionException
1177
+	 */
1178
+	public function wp_loaded()
1179
+	{
1180
+		if ($this->request->requestParamIsSet('clear_session')) {
1181
+			$this->clear_session(__CLASS__, __FUNCTION__);
1182
+		}
1183
+	}
1184
+
1185
+
1186
+	/**
1187
+	 * Used to reset the entire object (for tests).
1188
+	 *
1189
+	 * @since 4.3.0
1190
+	 * @throws EE_Error
1191
+	 * @throws InvalidDataTypeException
1192
+	 * @throws InvalidInterfaceException
1193
+	 * @throws InvalidArgumentException
1194
+	 * @throws ReflectionException
1195
+	 */
1196
+	public function reset_instance()
1197
+	{
1198
+		$this->clear_session();
1199
+		self::$_instance = null;
1200
+	}
1201
+
1202
+
1203
+	public function configure_garbage_collection_filters()
1204
+	{
1205
+		// run old filter we had for controlling session cleanup
1206
+		$expired_session_transient_delete_query_limit = absint(
1207
+			apply_filters(
1208
+				'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1209
+				50
1210
+			)
1211
+		);
1212
+		// is there a value? or one that is different than the default 50 records?
1213
+		if ($expired_session_transient_delete_query_limit === 0) {
1214
+			// hook into TransientCacheStorage in case Session cleanup was turned off
1215
+			add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1216
+		} elseif ($expired_session_transient_delete_query_limit !== 50) {
1217
+			// or use that for the new transient cleanup query limit
1218
+			add_filter(
1219
+				'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1220
+				function () use ($expired_session_transient_delete_query_limit) {
1221
+					return $expired_session_transient_delete_query_limit;
1222
+				}
1223
+			);
1224
+		}
1225
+	}
1226
+
1227
+
1228
+	/**
1229
+	 * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1230
+	 * @param $data1
1231
+	 * @return string
1232
+	 */
1233
+	private function find_serialize_error($data1)
1234
+	{
1235
+		$error = '<pre>';
1236
+		$data2 = preg_replace_callback(
1237
+			'!s:(\d+):"(.*?)";!',
1238
+			function ($match) {
1239
+				return ($match[1] === strlen($match[2]))
1240
+					? $match[0]
1241
+					: 's:'
1242
+					  . strlen($match[2])
1243
+					  . ':"'
1244
+					  . $match[2]
1245
+					  . '";';
1246
+			},
1247
+			$data1
1248
+		);
1249
+		$max = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1250
+		$error .= $data1 . PHP_EOL;
1251
+		$error .= $data2 . PHP_EOL;
1252
+		for ($i = 0; $i < $max; $i++) {
1253
+			if (@$data1[ $i ] !== @$data2[ $i ]) {
1254
+				$error .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1255
+				$error .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1256
+				$error .= "\t-> Line Number = $i" . PHP_EOL;
1257
+				$start = ($i - 20);
1258
+				$start = ($start < 0) ? 0 : $start;
1259
+				$length = 40;
1260
+				$point = $max - $i;
1261
+				if ($point < 20) {
1262
+					$rlength = 1;
1263
+					$rpoint = -$point;
1264
+				} else {
1265
+					$rpoint = $length - 20;
1266
+					$rlength = 1;
1267
+				}
1268
+				$error .= "\t-> Section Data1  = ";
1269
+				$error .= substr_replace(
1270
+					substr($data1, $start, $length),
1271
+					"<b style=\"color:green\">{$data1[ $i ]}</b>",
1272
+					$rpoint,
1273
+					$rlength
1274
+				);
1275
+				$error .= PHP_EOL;
1276
+				$error .= "\t-> Section Data2  = ";
1277
+				$error .= substr_replace(
1278
+					substr($data2, $start, $length),
1279
+					"<b style=\"color:red\">{$data2[ $i ]}</b>",
1280
+					$rpoint,
1281
+					$rlength
1282
+				);
1283
+				$error .= PHP_EOL;
1284
+			}
1285
+		}
1286
+		$error .= '</pre>';
1287
+		return $error;
1288
+	}
1289
+
1290
+
1291
+	/**
1292
+	 * Saves an  array of settings used for configuring aspects of session behaviour
1293
+	 *
1294
+	 * @param array $updated_settings
1295
+	 */
1296
+	private function updateSessionSettings(array $updated_settings = array())
1297
+	{
1298
+		// add existing settings, but only if not included in incoming $updated_settings array
1299
+		$updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, array());
1300
+		update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1301
+	}
1302
+
1303
+
1304
+	/**
1305
+	 * garbage_collection
1306
+	 */
1307
+	public function garbageCollection()
1308
+	{
1309
+		// only perform during regular requests if last garbage collection was over an hour ago
1310
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1311
+			$this->_last_gc = time();
1312
+			$this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1313
+			/** @type WPDB $wpdb */
1314
+			global $wpdb;
1315
+			// filter the query limit. Set to 0 to turn off garbage collection
1316
+			$expired_session_transient_delete_query_limit = absint(
1317
+				apply_filters(
1318
+					'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1319
+					50
1320
+				)
1321
+			);
1322
+			// non-zero LIMIT means take out the trash
1323
+			if ($expired_session_transient_delete_query_limit) {
1324
+				$session_key = str_replace('_', '\_', EE_Session::session_id_prefix);
1325
+				$hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1326
+				// since transient expiration timestamps are set in the future, we can compare against NOW
1327
+				// but we only want to pick up any trash that's been around for more than a day
1328
+				$expiration = time() - DAY_IN_SECONDS;
1329
+				$SQL = "
1330 1330
                     SELECT option_name
1331 1331
                     FROM {$wpdb->options}
1332 1332
                     WHERE
@@ -1335,17 +1335,17 @@  discard block
 block discarded – undo
1335 1335
                     AND option_value < {$expiration}
1336 1336
                     LIMIT {$expired_session_transient_delete_query_limit}
1337 1337
                 ";
1338
-                // produces something like:
1339
-                // SELECT option_name FROM wp_options
1340
-                // WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1341
-                // OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1342
-                // AND option_value < 1508368198 LIMIT 50
1343
-                $expired_sessions = $wpdb->get_col($SQL);
1344
-                // valid results?
1345
-                if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1346
-                    $this->cache_storage->deleteMany($expired_sessions, true);
1347
-                }
1348
-            }
1349
-        }
1350
-    }
1338
+				// produces something like:
1339
+				// SELECT option_name FROM wp_options
1340
+				// WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1341
+				// OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1342
+				// AND option_value < 1508368198 LIMIT 50
1343
+				$expired_sessions = $wpdb->get_col($SQL);
1344
+				// valid results?
1345
+				if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1346
+					$this->cache_storage->deleteMany($expired_sessions, true);
1347
+				}
1348
+			}
1349
+		}
1350
+	}
1351 1351
 }
Please login to merge, or discard this patch.
core/services/orm/tree_traversal/ModelObjNode.php 2 patches
Indentation   +188 added lines, -188 removed lines patch added patch discarded remove patch
@@ -22,206 +22,206 @@
 block discarded – undo
22 22
  */
23 23
 class ModelObjNode extends BaseNode
24 24
 {
25
-    /**
26
-     * @var int|string
27
-     */
28
-    protected $id;
25
+	/**
26
+	 * @var int|string
27
+	 */
28
+	protected $id;
29 29
 
30
-    /**
31
-     * @var EEM_Base
32
-     */
33
-    protected $model;
30
+	/**
31
+	 * @var EEM_Base
32
+	 */
33
+	protected $model;
34 34
 
35
-    /**
36
-     * @var RelationNode[]
37
-     */
38
-    protected $nodes;
35
+	/**
36
+	 * @var RelationNode[]
37
+	 */
38
+	protected $nodes;
39 39
 
40
-    /**
41
-     * We don't pass the model objects because this needs to serialize to something tiny for effiency.
42
-     * @param $model_obj_id
43
-     * @param EEM_Base $model
44
-     * @param array $dont_traverse_models array of model names we DON'T want to traverse.
45
-     */
46
-    public function __construct($model_obj_id, EEM_Base $model, array $dont_traverse_models = [])
47
-    {
48
-        $this->id = $model_obj_id;
49
-        $this->model = $model;
50
-        $this->dont_traverse_models = $dont_traverse_models;
51
-    }
40
+	/**
41
+	 * We don't pass the model objects because this needs to serialize to something tiny for effiency.
42
+	 * @param $model_obj_id
43
+	 * @param EEM_Base $model
44
+	 * @param array $dont_traverse_models array of model names we DON'T want to traverse.
45
+	 */
46
+	public function __construct($model_obj_id, EEM_Base $model, array $dont_traverse_models = [])
47
+	{
48
+		$this->id = $model_obj_id;
49
+		$this->model = $model;
50
+		$this->dont_traverse_models = $dont_traverse_models;
51
+	}
52 52
 
53
-    /**
54
-     * Creates a relation node for each relation of this model's relations.
55
-     * Does NOT call `discover` on them yet though.
56
-     * @since 4.10.12.p
57
-     * @throws \EE_Error
58
-     * @throws InvalidDataTypeException
59
-     * @throws InvalidInterfaceException
60
-     * @throws InvalidArgumentException
61
-     * @throws ReflectionException
62
-     */
63
-    protected function discover()
64
-    {
65
-        $this->nodes = [];
66
-        foreach ($this->model->relation_settings() as $relationName => $relation) {
67
-            // Make sure this isn't one of the models we were told to not traverse into.
68
-            if (in_array($relationName, $this->dont_traverse_models)) {
69
-                continue;
70
-            }
71
-            if ($relation instanceof EE_Has_Many_Relation) {
72
-                $this->nodes[ $relationName ] = new RelationNode(
73
-                    $this->id,
74
-                    $this->model,
75
-                    $relation->get_other_model(),
76
-                    $this->dont_traverse_models
77
-                );
78
-            } elseif (
79
-                $relation instanceof EE_HABTM_Relation &&
80
-                ! in_array(
81
-                    $relation->get_join_model()->get_this_model_name(),
82
-                    $this->dont_traverse_models
83
-                )
84
-            ) {
85
-                $this->nodes[ $relation->get_join_model()->get_this_model_name() ] = new RelationNode(
86
-                    $this->id,
87
-                    $this->model,
88
-                    $relation->get_join_model(),
89
-                    $this->dont_traverse_models
90
-                );
91
-            }
92
-        }
93
-        ksort($this->nodes);
94
-    }
53
+	/**
54
+	 * Creates a relation node for each relation of this model's relations.
55
+	 * Does NOT call `discover` on them yet though.
56
+	 * @since 4.10.12.p
57
+	 * @throws \EE_Error
58
+	 * @throws InvalidDataTypeException
59
+	 * @throws InvalidInterfaceException
60
+	 * @throws InvalidArgumentException
61
+	 * @throws ReflectionException
62
+	 */
63
+	protected function discover()
64
+	{
65
+		$this->nodes = [];
66
+		foreach ($this->model->relation_settings() as $relationName => $relation) {
67
+			// Make sure this isn't one of the models we were told to not traverse into.
68
+			if (in_array($relationName, $this->dont_traverse_models)) {
69
+				continue;
70
+			}
71
+			if ($relation instanceof EE_Has_Many_Relation) {
72
+				$this->nodes[ $relationName ] = new RelationNode(
73
+					$this->id,
74
+					$this->model,
75
+					$relation->get_other_model(),
76
+					$this->dont_traverse_models
77
+				);
78
+			} elseif (
79
+				$relation instanceof EE_HABTM_Relation &&
80
+				! in_array(
81
+					$relation->get_join_model()->get_this_model_name(),
82
+					$this->dont_traverse_models
83
+				)
84
+			) {
85
+				$this->nodes[ $relation->get_join_model()->get_this_model_name() ] = new RelationNode(
86
+					$this->id,
87
+					$this->model,
88
+					$relation->get_join_model(),
89
+					$this->dont_traverse_models
90
+				);
91
+			}
92
+		}
93
+		ksort($this->nodes);
94
+	}
95 95
 
96 96
 
97
-    /**
98
-     * Whether this item has already been initialized
99
-     */
100
-    protected function isDiscovered()
101
-    {
102
-        return $this->nodes !== null && is_array($this->nodes);
103
-    }
97
+	/**
98
+	 * Whether this item has already been initialized
99
+	 */
100
+	protected function isDiscovered()
101
+	{
102
+		return $this->nodes !== null && is_array($this->nodes);
103
+	}
104 104
 
105
-    /**
106
-     * @since 4.10.12.p
107
-     * @return boolean
108
-     */
109
-    public function isComplete()
110
-    {
111
-        if ($this->complete === null) {
112
-            $this->complete = false;
113
-        }
114
-        return $this->complete;
115
-    }
105
+	/**
106
+	 * @since 4.10.12.p
107
+	 * @return boolean
108
+	 */
109
+	public function isComplete()
110
+	{
111
+		if ($this->complete === null) {
112
+			$this->complete = false;
113
+		}
114
+		return $this->complete;
115
+	}
116 116
 
117
-    /**
118
-     * Triggers working on each child relation node that has work to do.
119
-     * @since 4.10.12.p
120
-     * @param $model_objects_to_identify
121
-     * @return int units of work done
122
-     */
123
-    protected function work($model_objects_to_identify)
124
-    {
125
-        $num_identified = 0;
126
-        // Begin assuming we'll finish all the work on this node and its children...
127
-        $this->complete = true;
128
-        foreach ($this->nodes as $model_name => $relation_node) {
129
-            $num_identified += $relation_node->visit($model_objects_to_identify - $num_identified);
130
-            // To save on space when serializing, only bother keeping a record of relation nodes that actually found
131
-            // related model objects.
132
-            if ($relation_node->isComplete() && $relation_node->countSubNodes() === 0) {
133
-                unset($this->nodes[ $model_name ]);
134
-            }
135
-            if ($num_identified >= $model_objects_to_identify) {
136
-                // ...but admit we're wrong if the work exceeded the budget.
137
-                $this->complete = false;
138
-                break;
139
-            }
140
-        }
141
-        return $num_identified;
142
-    }
117
+	/**
118
+	 * Triggers working on each child relation node that has work to do.
119
+	 * @since 4.10.12.p
120
+	 * @param $model_objects_to_identify
121
+	 * @return int units of work done
122
+	 */
123
+	protected function work($model_objects_to_identify)
124
+	{
125
+		$num_identified = 0;
126
+		// Begin assuming we'll finish all the work on this node and its children...
127
+		$this->complete = true;
128
+		foreach ($this->nodes as $model_name => $relation_node) {
129
+			$num_identified += $relation_node->visit($model_objects_to_identify - $num_identified);
130
+			// To save on space when serializing, only bother keeping a record of relation nodes that actually found
131
+			// related model objects.
132
+			if ($relation_node->isComplete() && $relation_node->countSubNodes() === 0) {
133
+				unset($this->nodes[ $model_name ]);
134
+			}
135
+			if ($num_identified >= $model_objects_to_identify) {
136
+				// ...but admit we're wrong if the work exceeded the budget.
137
+				$this->complete = false;
138
+				break;
139
+			}
140
+		}
141
+		return $num_identified;
142
+	}
143 143
 
144
-    /**
145
-     * @since 4.10.12.p
146
-     * @return array
147
-     * @throws \EE_Error
148
-     * @throws InvalidDataTypeException
149
-     * @throws InvalidInterfaceException
150
-     * @throws InvalidArgumentException
151
-     * @throws ReflectionException
152
-     */
153
-    public function toArray()
154
-    {
155
-        $tree = [
156
-            'id' => $this->id,
157
-            'complete' => $this->isComplete(),
158
-            'rels' => []
159
-        ];
160
-        if ($this->nodes === null) {
161
-            $tree['rels'] = null;
162
-        } else {
163
-            foreach ($this->nodes as $relation_name => $relation_node) {
164
-                $tree['rels'][ $relation_name ] = $relation_node->toArray();
165
-            }
166
-        }
167
-        return $tree;
168
-    }
144
+	/**
145
+	 * @since 4.10.12.p
146
+	 * @return array
147
+	 * @throws \EE_Error
148
+	 * @throws InvalidDataTypeException
149
+	 * @throws InvalidInterfaceException
150
+	 * @throws InvalidArgumentException
151
+	 * @throws ReflectionException
152
+	 */
153
+	public function toArray()
154
+	{
155
+		$tree = [
156
+			'id' => $this->id,
157
+			'complete' => $this->isComplete(),
158
+			'rels' => []
159
+		];
160
+		if ($this->nodes === null) {
161
+			$tree['rels'] = null;
162
+		} else {
163
+			foreach ($this->nodes as $relation_name => $relation_node) {
164
+				$tree['rels'][ $relation_name ] = $relation_node->toArray();
165
+			}
166
+		}
167
+		return $tree;
168
+	}
169 169
 
170
-    /**
171
-     * @since 4.10.12.p
172
-     * @return array|mixed
173
-     * @throws InvalidArgumentException
174
-     * @throws InvalidDataTypeException
175
-     * @throws InvalidInterfaceException
176
-     * @throws ReflectionException
177
-     * @throws \EE_Error
178
-     */
179
-    public function getIds()
180
-    {
181
-        $ids = [
182
-            $this->model->get_this_model_name() => [
183
-                $this->id => $this->id
184
-            ]
185
-        ];
186
-        if ($this->nodes && is_array($this->nodes)) {
187
-            foreach ($this->nodes as $relation_node) {
188
-                $ids = array_replace_recursive($ids, $relation_node->getIds());
189
-            }
190
-        }
191
-        return $ids;
192
-    }
170
+	/**
171
+	 * @since 4.10.12.p
172
+	 * @return array|mixed
173
+	 * @throws InvalidArgumentException
174
+	 * @throws InvalidDataTypeException
175
+	 * @throws InvalidInterfaceException
176
+	 * @throws ReflectionException
177
+	 * @throws \EE_Error
178
+	 */
179
+	public function getIds()
180
+	{
181
+		$ids = [
182
+			$this->model->get_this_model_name() => [
183
+				$this->id => $this->id
184
+			]
185
+		];
186
+		if ($this->nodes && is_array($this->nodes)) {
187
+			foreach ($this->nodes as $relation_node) {
188
+				$ids = array_replace_recursive($ids, $relation_node->getIds());
189
+			}
190
+		}
191
+		return $ids;
192
+	}
193 193
 
194
-    /**
195
-     * Don't serialize the models. Just record their names on some dynamic properties.
196
-     * @since 4.10.12.p
197
-     */
198
-    public function __sleep()
199
-    {
200
-        $this->m = $this->model->get_this_model_name();
201
-        return array_merge(
202
-            [
203
-                'm',
204
-                'id',
205
-                'nodes',
206
-            ],
207
-            parent::__sleep()
208
-        );
209
-    }
194
+	/**
195
+	 * Don't serialize the models. Just record their names on some dynamic properties.
196
+	 * @since 4.10.12.p
197
+	 */
198
+	public function __sleep()
199
+	{
200
+		$this->m = $this->model->get_this_model_name();
201
+		return array_merge(
202
+			[
203
+				'm',
204
+				'id',
205
+				'nodes',
206
+			],
207
+			parent::__sleep()
208
+		);
209
+	}
210 210
 
211
-    /**
212
-     * Use the dynamic properties to instantiate the models we use.
213
-     * @since 4.10.12.p
214
-     * @throws EE_Error
215
-     * @throws InvalidArgumentException
216
-     * @throws InvalidDataTypeException
217
-     * @throws InvalidInterfaceException
218
-     * @throws ReflectionException
219
-     */
220
-    public function __wakeup()
221
-    {
222
-        $this->model = EE_Registry::instance()->load_model($this->m);
223
-        parent::__wakeup();
224
-    }
211
+	/**
212
+	 * Use the dynamic properties to instantiate the models we use.
213
+	 * @since 4.10.12.p
214
+	 * @throws EE_Error
215
+	 * @throws InvalidArgumentException
216
+	 * @throws InvalidDataTypeException
217
+	 * @throws InvalidInterfaceException
218
+	 * @throws ReflectionException
219
+	 */
220
+	public function __wakeup()
221
+	{
222
+		$this->model = EE_Registry::instance()->load_model($this->m);
223
+		parent::__wakeup();
224
+	}
225 225
 }
226 226
 // End of file Visitor.php
227 227
 // Location: EventEspresso\core\services\orm\tree_traversal/Visitor.php
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -69,7 +69,7 @@  discard block
 block discarded – undo
69 69
                 continue;
70 70
             }
71 71
             if ($relation instanceof EE_Has_Many_Relation) {
72
-                $this->nodes[ $relationName ] = new RelationNode(
72
+                $this->nodes[$relationName] = new RelationNode(
73 73
                     $this->id,
74 74
                     $this->model,
75 75
                     $relation->get_other_model(),
@@ -82,7 +82,7 @@  discard block
 block discarded – undo
82 82
                     $this->dont_traverse_models
83 83
                 )
84 84
             ) {
85
-                $this->nodes[ $relation->get_join_model()->get_this_model_name() ] = new RelationNode(
85
+                $this->nodes[$relation->get_join_model()->get_this_model_name()] = new RelationNode(
86 86
                     $this->id,
87 87
                     $this->model,
88 88
                     $relation->get_join_model(),
@@ -130,7 +130,7 @@  discard block
 block discarded – undo
130 130
             // To save on space when serializing, only bother keeping a record of relation nodes that actually found
131 131
             // related model objects.
132 132
             if ($relation_node->isComplete() && $relation_node->countSubNodes() === 0) {
133
-                unset($this->nodes[ $model_name ]);
133
+                unset($this->nodes[$model_name]);
134 134
             }
135 135
             if ($num_identified >= $model_objects_to_identify) {
136 136
                 // ...but admit we're wrong if the work exceeded the budget.
@@ -161,7 +161,7 @@  discard block
 block discarded – undo
161 161
             $tree['rels'] = null;
162 162
         } else {
163 163
             foreach ($this->nodes as $relation_name => $relation_node) {
164
-                $tree['rels'][ $relation_name ] = $relation_node->toArray();
164
+                $tree['rels'][$relation_name] = $relation_node->toArray();
165 165
             }
166 166
         }
167 167
         return $tree;
Please login to merge, or discard this patch.
core/libraries/plugin_api/EE_Register_Model_Extensions.lib.php 2 patches
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -68,11 +68,11 @@  discard block
 block discarded – undo
68 68
         }
69 69
 
70 70
         // make sure we don't register twice
71
-        if (isset(self::$_registry[ $identifier ])) {
71
+        if (isset(self::$_registry[$identifier])) {
72 72
             return;
73 73
         }
74 74
         // check correct loading
75
-        if (! did_action('AHEE__EE_System__load_espresso_addons') || did_action('AHEE__EE_Admin__loaded')) {
75
+        if ( ! did_action('AHEE__EE_System__load_espresso_addons') || did_action('AHEE__EE_Admin__loaded')) {
76 76
             EE_Error::doing_it_wrong(
77 77
                 __METHOD__,
78 78
                 sprintf(
@@ -89,30 +89,30 @@  discard block
 block discarded – undo
89 89
             );
90 90
         }
91 91
 
92
-        self::$_registry[ $identifier ]   = $setup_args;
93
-        self::$_extensions[ $identifier ] = [];
92
+        self::$_registry[$identifier]   = $setup_args;
93
+        self::$_extensions[$identifier] = [];
94 94
 
95 95
         if (isset($setup_args['model_extension_paths'])) {
96
-            require_once(EE_LIBRARIES . 'plugin_api/db/EEME_Base.lib.php');
96
+            require_once(EE_LIBRARIES.'plugin_api/db/EEME_Base.lib.php');
97 97
             $class_to_filepath_map = EEH_File::get_contents_of_folders($setup_args['model_extension_paths']);
98 98
             // remove all files that are not PHP
99 99
             foreach ($class_to_filepath_map as $class => $path) {
100 100
                 if (substr($path, strlen($path) - 3) !== 'php') {
101
-                    unset($class_to_filepath_map[ $class ]);
101
+                    unset($class_to_filepath_map[$class]);
102 102
                 }
103 103
             }
104 104
             EEH_Autoloader::register_autoloader($class_to_filepath_map);
105 105
             foreach (array_keys($class_to_filepath_map) as $classname) {
106
-                self::$_extensions[ $identifier ]['models'][ $classname ] = new $classname();
106
+                self::$_extensions[$identifier]['models'][$classname] = new $classname();
107 107
             }
108 108
             unset($setup_args['model_extension_paths']);
109 109
         }
110 110
         if (isset($setup_args['class_extension_paths'])) {
111
-            require_once(EE_LIBRARIES . 'plugin_api/db/EEE_Base_Class.lib.php');
111
+            require_once(EE_LIBRARIES.'plugin_api/db/EEE_Base_Class.lib.php');
112 112
             $class_to_filepath_map = EEH_File::get_contents_of_folders($setup_args['class_extension_paths']);
113 113
             EEH_Autoloader::register_autoloader($class_to_filepath_map);
114 114
             foreach (array_keys($class_to_filepath_map) as $classname) {
115
-                self::$_extensions[ $identifier ]['classes'][ $classname ] = new $classname();
115
+                self::$_extensions[$identifier]['classes'][$classname] = new $classname();
116 116
             }
117 117
             unset($setup_args['class_extension_paths']);
118 118
         }
@@ -131,9 +131,9 @@  discard block
 block discarded – undo
131 131
      */
132 132
     public static function deregister($identifier = '')
133 133
     {
134
-        if (isset(self::$_registry[ $identifier ])) {
135
-            unset(self::$_registry[ $identifier ]);
136
-            foreach (self::$_extensions[ $identifier ] as $extension_of_type) {
134
+        if (isset(self::$_registry[$identifier])) {
135
+            unset(self::$_registry[$identifier]);
136
+            foreach (self::$_extensions[$identifier] as $extension_of_type) {
137 137
                 foreach ($extension_of_type as $extension) {
138 138
                     $extension->deregister();
139 139
                 }
Please login to merge, or discard this patch.
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -11,132 +11,132 @@
 block discarded – undo
11 11
  */
12 12
 class EE_Register_Model_Extensions implements EEI_Plugin_API
13 13
 {
14
-    protected static $_registry;
14
+	protected static $_registry;
15 15
 
16
-    protected static $_extensions = [];
16
+	protected static $_extensions = [];
17 17
 
18 18
 
19
-    /**
20
-     * register method for setting up model extensions
21
-     *
22
-     * @param string $identifier            unique id for the extensions being setup
23
-     * @param array  $setup_args            {
24
-     * @return void
25
-     * @throws EE_Error
26
-     * @type  array  $model_extension_paths array of folders containing DB model extensions, where each file follows
27
-     *                                      the models naming convention, which is:
28
-     *                                      EEME_{your_plugin_slug}_model_name_extended}.model_ext.php.
29
-     *                                      Where {your_plugin_slug} is really anything you want (but something having
30
-     *                                      to do with your addon, like 'Calendar' or '3D_View') and
31
-     *                                      model_name_extended} is the model extended.
32
-     *                                      The class contained in teh file should extend
33
-     *                                      EEME_Base_{model_name_extended}.model_ext.php.
34
-     *                                      Where {your_plugin_slug} is really anything you want (but something
35
-     *                                      having to do with your addon, like 'Calendar' or '3D_View') and
36
-     *                                      {model_name_extended} is the model extended. The class contained in teh
37
-     *                                      file should extend EEME_Base
38
-     * @type array   $class_extension_paths array of folders containing DB class extensions, where each file follows
39
-     *                                      the model class extension naming convention, which is:
40
-     *                                      EEE_{your_plugin_slug}_model_name_extended}.class_ext.php.
41
-     *                                      Where {your_plugin_slug} is something like 'Calendar','MailChimp',etc,
42
-     *                                      and model_name_extended} is the name of the model extended, eg
43
-     *                                      'Attendee','Event',etc.
44
-     *                                      The class contained in the file should extend EEE_Base_Class
45
-     *                                      ._{model_name_extended}.class_ext.php.
46
-     *                                      Where {your_plugin_slug} is something like 'Calendar','MailChimp',etc,
47
-     *                                      and {model_name_extended} is the name of the model extended, eg
48
-     *                                      'Attendee','Event',etc. The class contained in the file should extend
49
-     *                                      EEE_Base_Class.
50
-     *                                      }
51
-     *
52
-     */
53
-    public static function register($identifier = '', array $setup_args = [])
54
-    {
55
-        // required fields MUST be present, so let's make sure they are.
56
-        if (
57
-            empty($identifier)
58
-            || ! is_array($setup_args)
59
-            || (empty($setup_args['model_extension_paths']) && empty($setup_args['class_extension_paths']))
60
-        ) {
61
-            throw new EE_Error(
62
-                esc_html__(
63
-                    'In order to register Model extensions with EE_Register_Model_Extensions::register(), you must include a "model_id" (a unique identifier for this set of models), and an array containing the following keys: "model_extension_paths" (an array of full server paths to folders that contain model extensions), and "class_extension_paths" (an array of full server paths to folders that contain class extensions)',
64
-                    'event_espresso'
65
-                )
66
-            );
67
-        }
19
+	/**
20
+	 * register method for setting up model extensions
21
+	 *
22
+	 * @param string $identifier            unique id for the extensions being setup
23
+	 * @param array  $setup_args            {
24
+	 * @return void
25
+	 * @throws EE_Error
26
+	 * @type  array  $model_extension_paths array of folders containing DB model extensions, where each file follows
27
+	 *                                      the models naming convention, which is:
28
+	 *                                      EEME_{your_plugin_slug}_model_name_extended}.model_ext.php.
29
+	 *                                      Where {your_plugin_slug} is really anything you want (but something having
30
+	 *                                      to do with your addon, like 'Calendar' or '3D_View') and
31
+	 *                                      model_name_extended} is the model extended.
32
+	 *                                      The class contained in teh file should extend
33
+	 *                                      EEME_Base_{model_name_extended}.model_ext.php.
34
+	 *                                      Where {your_plugin_slug} is really anything you want (but something
35
+	 *                                      having to do with your addon, like 'Calendar' or '3D_View') and
36
+	 *                                      {model_name_extended} is the model extended. The class contained in teh
37
+	 *                                      file should extend EEME_Base
38
+	 * @type array   $class_extension_paths array of folders containing DB class extensions, where each file follows
39
+	 *                                      the model class extension naming convention, which is:
40
+	 *                                      EEE_{your_plugin_slug}_model_name_extended}.class_ext.php.
41
+	 *                                      Where {your_plugin_slug} is something like 'Calendar','MailChimp',etc,
42
+	 *                                      and model_name_extended} is the name of the model extended, eg
43
+	 *                                      'Attendee','Event',etc.
44
+	 *                                      The class contained in the file should extend EEE_Base_Class
45
+	 *                                      ._{model_name_extended}.class_ext.php.
46
+	 *                                      Where {your_plugin_slug} is something like 'Calendar','MailChimp',etc,
47
+	 *                                      and {model_name_extended} is the name of the model extended, eg
48
+	 *                                      'Attendee','Event',etc. The class contained in the file should extend
49
+	 *                                      EEE_Base_Class.
50
+	 *                                      }
51
+	 *
52
+	 */
53
+	public static function register($identifier = '', array $setup_args = [])
54
+	{
55
+		// required fields MUST be present, so let's make sure they are.
56
+		if (
57
+			empty($identifier)
58
+			|| ! is_array($setup_args)
59
+			|| (empty($setup_args['model_extension_paths']) && empty($setup_args['class_extension_paths']))
60
+		) {
61
+			throw new EE_Error(
62
+				esc_html__(
63
+					'In order to register Model extensions with EE_Register_Model_Extensions::register(), you must include a "model_id" (a unique identifier for this set of models), and an array containing the following keys: "model_extension_paths" (an array of full server paths to folders that contain model extensions), and "class_extension_paths" (an array of full server paths to folders that contain class extensions)',
64
+					'event_espresso'
65
+				)
66
+			);
67
+		}
68 68
 
69
-        // make sure we don't register twice
70
-        if (isset(self::$_registry[ $identifier ])) {
71
-            return;
72
-        }
73
-        // check correct loading
74
-        if (! did_action('AHEE__EE_System__load_espresso_addons') || did_action('AHEE__EE_Admin__loaded')) {
75
-            EE_Error::doing_it_wrong(
76
-                __METHOD__,
77
-                sprintf(
78
-                    esc_html__(
79
-                        'An attempt was made to register "%1$s" as a Model extension has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register models.%2$s Hook Status: %2$s "AHEE__EE_System__load_espresso_addons" : %3$s %2$s "AHEE__EE_Admin__loaded" : %4$s%2$s',
80
-                        'event_espresso'
81
-                    ),
82
-                    $identifier,
83
-                    '<br />',
84
-                    did_action('AHEE__EE_System__load_espresso_addons') ? 'action done' : 'action NOT done',
85
-                    did_action('AHEE__EE_Admin__loaded') ? 'action done' : 'action NOT done'
86
-                ),
87
-                '4.3'
88
-            );
89
-        }
69
+		// make sure we don't register twice
70
+		if (isset(self::$_registry[ $identifier ])) {
71
+			return;
72
+		}
73
+		// check correct loading
74
+		if (! did_action('AHEE__EE_System__load_espresso_addons') || did_action('AHEE__EE_Admin__loaded')) {
75
+			EE_Error::doing_it_wrong(
76
+				__METHOD__,
77
+				sprintf(
78
+					esc_html__(
79
+						'An attempt was made to register "%1$s" as a Model extension has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register models.%2$s Hook Status: %2$s "AHEE__EE_System__load_espresso_addons" : %3$s %2$s "AHEE__EE_Admin__loaded" : %4$s%2$s',
80
+						'event_espresso'
81
+					),
82
+					$identifier,
83
+					'<br />',
84
+					did_action('AHEE__EE_System__load_espresso_addons') ? 'action done' : 'action NOT done',
85
+					did_action('AHEE__EE_Admin__loaded') ? 'action done' : 'action NOT done'
86
+				),
87
+				'4.3'
88
+			);
89
+		}
90 90
 
91
-        self::$_registry[ $identifier ]   = $setup_args;
92
-        self::$_extensions[ $identifier ] = [];
91
+		self::$_registry[ $identifier ]   = $setup_args;
92
+		self::$_extensions[ $identifier ] = [];
93 93
 
94
-        if (isset($setup_args['model_extension_paths'])) {
95
-            require_once(EE_LIBRARIES . 'plugin_api/db/EEME_Base.lib.php');
96
-            $class_to_filepath_map = EEH_File::get_contents_of_folders($setup_args['model_extension_paths']);
97
-            // remove all files that are not PHP
98
-            foreach ($class_to_filepath_map as $class => $path) {
99
-                if (substr($path, strlen($path) - 3) !== 'php') {
100
-                    unset($class_to_filepath_map[ $class ]);
101
-                }
102
-            }
103
-            EEH_Autoloader::register_autoloader($class_to_filepath_map);
104
-            foreach (array_keys($class_to_filepath_map) as $classname) {
105
-                self::$_extensions[ $identifier ]['models'][ $classname ] = new $classname();
106
-            }
107
-            unset($setup_args['model_extension_paths']);
108
-        }
109
-        if (isset($setup_args['class_extension_paths'])) {
110
-            require_once(EE_LIBRARIES . 'plugin_api/db/EEE_Base_Class.lib.php');
111
-            $class_to_filepath_map = EEH_File::get_contents_of_folders($setup_args['class_extension_paths']);
112
-            EEH_Autoloader::register_autoloader($class_to_filepath_map);
113
-            foreach (array_keys($class_to_filepath_map) as $classname) {
114
-                self::$_extensions[ $identifier ]['classes'][ $classname ] = new $classname();
115
-            }
116
-            unset($setup_args['class_extension_paths']);
117
-        }
118
-        foreach ($setup_args as $unknown_key => $unknown_config) {
119
-            throw new EE_Error(
120
-                sprintf(esc_html__("The key '%s' is not a known key for registering a model", "event_espresso"), $unknown_key)
121
-            );
122
-        }
123
-    }
94
+		if (isset($setup_args['model_extension_paths'])) {
95
+			require_once(EE_LIBRARIES . 'plugin_api/db/EEME_Base.lib.php');
96
+			$class_to_filepath_map = EEH_File::get_contents_of_folders($setup_args['model_extension_paths']);
97
+			// remove all files that are not PHP
98
+			foreach ($class_to_filepath_map as $class => $path) {
99
+				if (substr($path, strlen($path) - 3) !== 'php') {
100
+					unset($class_to_filepath_map[ $class ]);
101
+				}
102
+			}
103
+			EEH_Autoloader::register_autoloader($class_to_filepath_map);
104
+			foreach (array_keys($class_to_filepath_map) as $classname) {
105
+				self::$_extensions[ $identifier ]['models'][ $classname ] = new $classname();
106
+			}
107
+			unset($setup_args['model_extension_paths']);
108
+		}
109
+		if (isset($setup_args['class_extension_paths'])) {
110
+			require_once(EE_LIBRARIES . 'plugin_api/db/EEE_Base_Class.lib.php');
111
+			$class_to_filepath_map = EEH_File::get_contents_of_folders($setup_args['class_extension_paths']);
112
+			EEH_Autoloader::register_autoloader($class_to_filepath_map);
113
+			foreach (array_keys($class_to_filepath_map) as $classname) {
114
+				self::$_extensions[ $identifier ]['classes'][ $classname ] = new $classname();
115
+			}
116
+			unset($setup_args['class_extension_paths']);
117
+		}
118
+		foreach ($setup_args as $unknown_key => $unknown_config) {
119
+			throw new EE_Error(
120
+				sprintf(esc_html__("The key '%s' is not a known key for registering a model", "event_espresso"), $unknown_key)
121
+			);
122
+		}
123
+	}
124 124
 
125 125
 
126
-    /**
127
-     * deregister
128
-     *
129
-     * @param string $identifier
130
-     */
131
-    public static function deregister($identifier = '')
132
-    {
133
-        if (isset(self::$_registry[ $identifier ])) {
134
-            unset(self::$_registry[ $identifier ]);
135
-            foreach (self::$_extensions[ $identifier ] as $extension_of_type) {
136
-                foreach ($extension_of_type as $extension) {
137
-                    $extension->deregister();
138
-                }
139
-            }
140
-        }
141
-    }
126
+	/**
127
+	 * deregister
128
+	 *
129
+	 * @param string $identifier
130
+	 */
131
+	public static function deregister($identifier = '')
132
+	{
133
+		if (isset(self::$_registry[ $identifier ])) {
134
+			unset(self::$_registry[ $identifier ]);
135
+			foreach (self::$_extensions[ $identifier ] as $extension_of_type) {
136
+				foreach ($extension_of_type as $extension) {
137
+					$extension->deregister();
138
+				}
139
+			}
140
+		}
141
+	}
142 142
 }
Please login to merge, or discard this patch.
core/libraries/plugin_api/EE_Register_Payment_Method.lib.php 2 patches
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -59,7 +59,7 @@  discard block
 block discarded – undo
59 59
             );
60 60
         }
61 61
         // make sure we don't register twice
62
-        if (isset(self::$_settings[ $identifier ])) {
62
+        if (isset(self::$_settings[$identifier])) {
63 63
             return;
64 64
         }
65 65
         // make sure this was called in the right place!
@@ -77,7 +77,7 @@  discard block
 block discarded – undo
77 77
             );
78 78
         }
79 79
         // setup $_settings array from incoming values.
80
-        self::$_settings[ $identifier ] = [
80
+        self::$_settings[$identifier] = [
81 81
             // array of full server paths to any EE_PMT_Base children used
82 82
             'payment_method_paths' => isset($setup_args['payment_method_paths'])
83 83
                 ? (array) $setup_args['payment_method_paths']
@@ -93,12 +93,12 @@  discard block
 block discarded – undo
93 93
         if (did_action('FHEE__EE_Payment_Method_Manager__register_payment_methods__registered_payment_methods')) {
94 94
             $payment_method_manager = LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
95 95
             // register payment methods directly
96
-            foreach (self::$_settings[ $identifier ]['payment_method_paths'] as $payment_method_path) {
96
+            foreach (self::$_settings[$identifier]['payment_method_paths'] as $payment_method_path) {
97 97
                 $payment_method_manager->register_payment_method($payment_method_path);
98 98
             }
99 99
             $capabilities = LoaderFactory::getLoader()->getShared('EE_Capabilities');
100 100
             $capabilities->addCaps(
101
-                self::getPaymentMethodCapabilities(self::$_settings[ $identifier ])
101
+                self::getPaymentMethodCapabilities(self::$_settings[$identifier])
102 102
             );
103 103
         }
104 104
     }
@@ -135,13 +135,13 @@  discard block
 block discarded – undo
135 135
      */
136 136
     public static function deregister($identifier = '')
137 137
     {
138
-        if (isset(self::$_settings[ $identifier ])) {
138
+        if (isset(self::$_settings[$identifier])) {
139 139
             // set action for just this module id to delay deregistration until core is loaded and ready.
140
-            $module_settings = self::$_settings[ $identifier ];
141
-            unset(self::$_settings[ $identifier ]);
140
+            $module_settings = self::$_settings[$identifier];
141
+            unset(self::$_settings[$identifier]);
142 142
             add_action(
143 143
                 'AHEE__EE_System__core_loaded_and_ready',
144
-                function () use ($module_settings) {
144
+                function() use ($module_settings) {
145 145
                     $capabilities = LoaderFactory::getLoader()->getShared('EE_Capabilities');
146 146
                     $capabilities->removeCaps(
147 147
                         EE_Register_Payment_Method::getPaymentMethodCapabilities($module_settings)
Please login to merge, or discard this patch.
Indentation   +151 added lines, -151 removed lines patch added patch discarded remove patch
@@ -18,163 +18,163 @@
 block discarded – undo
18 18
  */
19 19
 class EE_Register_Payment_Method implements EEI_Plugin_API
20 20
 {
21
-    /**
22
-     * Holds values for registered payment methods
23
-     *
24
-     * @var array
25
-     */
26
-    protected static $_settings = [];
21
+	/**
22
+	 * Holds values for registered payment methods
23
+	 *
24
+	 * @var array
25
+	 */
26
+	protected static $_settings = [];
27 27
 
28 28
 
29
-    /**
30
-     * Method for registering new EE_PMT_Base children
31
-     *
32
-     * @param string  $identifier           a unique identifier for this set of modules Required.
33
-     * @param array   $setup_args           an array of arguments provided for registering modules Required.{
34
-     * @type string[] $payment_method_paths each element is the folder containing the EE_PMT_Base child class
35
-     *                                      (eg, 'public_html/wp-content/plugins/my_plugin/Payomatic/' which contains
36
-     *                                      the files EE_PMT_Payomatic.pm.php)
37
-     *                                      }
38
-     * @return void
39
-     * @throws EE_Error
40
-     * @type array payment_method_paths    an array of full server paths to folders containing any EE_PMT_Base
41
-     *                                      children, or to the EED_Module files themselves
42
-     * @throws InvalidDataTypeException
43
-     * @throws DomainException
44
-     * @throws InvalidArgumentException
45
-     * @throws InvalidInterfaceException
46
-     * @throws InvalidDataTypeException
47
-     * @since    4.5.0
48
-     */
49
-    public static function register($identifier = '', array $setup_args = [])
50
-    {
51
-        // required fields MUST be present, so let's make sure they are.
52
-        if (empty($identifier) || ! is_array($setup_args) || empty($setup_args['payment_method_paths'])) {
53
-            throw new EE_Error(
54
-                esc_html__(
55
-                    'In order to register Payment Methods with EE_Register_Payment_Method::register(), you must include a "payment_method_id" (a unique identifier for this set of modules), and an array containing the following keys: "payment_method_paths" (an array of full server paths to folders that contain modules, or to the module files themselves)',
56
-                    'event_espresso'
57
-                )
58
-            );
59
-        }
60
-        // make sure we don't register twice
61
-        if (isset(self::$_settings[ $identifier ])) {
62
-            return;
63
-        }
64
-        // make sure this was called in the right place!
65
-        if (
66
-            ! did_action('AHEE__EE_System__load_espresso_addons')
67
-            || did_action('AHEE__EE_System__register_shortcodes_modules_and_widgets')
68
-        ) {
69
-            EE_Error::doing_it_wrong(
70
-                __METHOD__,
71
-                esc_html__(
72
-                    'An attempt to register modules has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__register_shortcodes_modules_and_widgets" hook to register modules.',
73
-                    'event_espresso'
74
-                ),
75
-                '4.3.0'
76
-            );
77
-        }
78
-        // setup $_settings array from incoming values.
79
-        self::$_settings[ $identifier ] = [
80
-            // array of full server paths to any EE_PMT_Base children used
81
-            'payment_method_paths' => isset($setup_args['payment_method_paths'])
82
-                ? (array) $setup_args['payment_method_paths']
83
-                : [],
84
-        ];
85
-        // add to list of modules to be registered
86
-        add_filter(
87
-            'FHEE__EE_Payment_Method_Manager__register_payment_methods__payment_methods_to_register',
88
-            ['EE_Register_Payment_Method', 'add_payment_methods']
89
-        );
90
-        // If EE_Payment_Method_Manager::register_payment_methods has already been called,
91
-        // then we need to add our caps for this payment method manually
92
-        if (did_action('FHEE__EE_Payment_Method_Manager__register_payment_methods__registered_payment_methods')) {
93
-            $payment_method_manager = LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
94
-            // register payment methods directly
95
-            foreach (self::$_settings[ $identifier ]['payment_method_paths'] as $payment_method_path) {
96
-                $payment_method_manager->register_payment_method($payment_method_path);
97
-            }
98
-            $capabilities = LoaderFactory::getLoader()->getShared('EE_Capabilities');
99
-            $capabilities->addCaps(
100
-                self::getPaymentMethodCapabilities(self::$_settings[ $identifier ])
101
-            );
102
-        }
103
-    }
29
+	/**
30
+	 * Method for registering new EE_PMT_Base children
31
+	 *
32
+	 * @param string  $identifier           a unique identifier for this set of modules Required.
33
+	 * @param array   $setup_args           an array of arguments provided for registering modules Required.{
34
+	 * @type string[] $payment_method_paths each element is the folder containing the EE_PMT_Base child class
35
+	 *                                      (eg, 'public_html/wp-content/plugins/my_plugin/Payomatic/' which contains
36
+	 *                                      the files EE_PMT_Payomatic.pm.php)
37
+	 *                                      }
38
+	 * @return void
39
+	 * @throws EE_Error
40
+	 * @type array payment_method_paths    an array of full server paths to folders containing any EE_PMT_Base
41
+	 *                                      children, or to the EED_Module files themselves
42
+	 * @throws InvalidDataTypeException
43
+	 * @throws DomainException
44
+	 * @throws InvalidArgumentException
45
+	 * @throws InvalidInterfaceException
46
+	 * @throws InvalidDataTypeException
47
+	 * @since    4.5.0
48
+	 */
49
+	public static function register($identifier = '', array $setup_args = [])
50
+	{
51
+		// required fields MUST be present, so let's make sure they are.
52
+		if (empty($identifier) || ! is_array($setup_args) || empty($setup_args['payment_method_paths'])) {
53
+			throw new EE_Error(
54
+				esc_html__(
55
+					'In order to register Payment Methods with EE_Register_Payment_Method::register(), you must include a "payment_method_id" (a unique identifier for this set of modules), and an array containing the following keys: "payment_method_paths" (an array of full server paths to folders that contain modules, or to the module files themselves)',
56
+					'event_espresso'
57
+				)
58
+			);
59
+		}
60
+		// make sure we don't register twice
61
+		if (isset(self::$_settings[ $identifier ])) {
62
+			return;
63
+		}
64
+		// make sure this was called in the right place!
65
+		if (
66
+			! did_action('AHEE__EE_System__load_espresso_addons')
67
+			|| did_action('AHEE__EE_System__register_shortcodes_modules_and_widgets')
68
+		) {
69
+			EE_Error::doing_it_wrong(
70
+				__METHOD__,
71
+				esc_html__(
72
+					'An attempt to register modules has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__register_shortcodes_modules_and_widgets" hook to register modules.',
73
+					'event_espresso'
74
+				),
75
+				'4.3.0'
76
+			);
77
+		}
78
+		// setup $_settings array from incoming values.
79
+		self::$_settings[ $identifier ] = [
80
+			// array of full server paths to any EE_PMT_Base children used
81
+			'payment_method_paths' => isset($setup_args['payment_method_paths'])
82
+				? (array) $setup_args['payment_method_paths']
83
+				: [],
84
+		];
85
+		// add to list of modules to be registered
86
+		add_filter(
87
+			'FHEE__EE_Payment_Method_Manager__register_payment_methods__payment_methods_to_register',
88
+			['EE_Register_Payment_Method', 'add_payment_methods']
89
+		);
90
+		// If EE_Payment_Method_Manager::register_payment_methods has already been called,
91
+		// then we need to add our caps for this payment method manually
92
+		if (did_action('FHEE__EE_Payment_Method_Manager__register_payment_methods__registered_payment_methods')) {
93
+			$payment_method_manager = LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
94
+			// register payment methods directly
95
+			foreach (self::$_settings[ $identifier ]['payment_method_paths'] as $payment_method_path) {
96
+				$payment_method_manager->register_payment_method($payment_method_path);
97
+			}
98
+			$capabilities = LoaderFactory::getLoader()->getShared('EE_Capabilities');
99
+			$capabilities->addCaps(
100
+				self::getPaymentMethodCapabilities(self::$_settings[ $identifier ])
101
+			);
102
+		}
103
+	}
104 104
 
105 105
 
106
-    /**
107
-     * Filters the list of payment methods to add ours.
108
-     * and they're just full filepaths to FOLDERS containing a payment method class file. Eg.
109
-     *
110
-     * @param array $payment_method_folders array of paths to all payment methods that require registering
111
-     * @return array
112
-     */
113
-    public static function add_payment_methods(array $payment_method_folders)
114
-    {
115
-        foreach (self::$_settings as $settings) {
116
-            foreach ($settings['payment_method_paths'] as $payment_method_path) {
117
-                $payment_method_folders[] = $payment_method_path;
118
-            }
119
-        }
120
-        return $payment_method_folders;
121
-    }
106
+	/**
107
+	 * Filters the list of payment methods to add ours.
108
+	 * and they're just full filepaths to FOLDERS containing a payment method class file. Eg.
109
+	 *
110
+	 * @param array $payment_method_folders array of paths to all payment methods that require registering
111
+	 * @return array
112
+	 */
113
+	public static function add_payment_methods(array $payment_method_folders)
114
+	{
115
+		foreach (self::$_settings as $settings) {
116
+			foreach ($settings['payment_method_paths'] as $payment_method_path) {
117
+				$payment_method_folders[] = $payment_method_path;
118
+			}
119
+		}
120
+		return $payment_method_folders;
121
+	}
122 122
 
123 123
 
124
-    /**
125
-     * This deregisters a module that was previously registered with a specific $identifier.
126
-     *
127
-     * @param string $identifier the name for the module that was previously registered
128
-     * @return void
129
-     * @throws DomainException
130
-     * @throws InvalidArgumentException
131
-     * @throws InvalidInterfaceException
132
-     * @throws InvalidDataTypeException
133
-     * @since    4.3.0
134
-     */
135
-    public static function deregister($identifier = '')
136
-    {
137
-        if (isset(self::$_settings[ $identifier ])) {
138
-            // set action for just this module id to delay deregistration until core is loaded and ready.
139
-            $module_settings = self::$_settings[ $identifier ];
140
-            unset(self::$_settings[ $identifier ]);
141
-            add_action(
142
-                'AHEE__EE_System__core_loaded_and_ready',
143
-                function () use ($module_settings) {
144
-                    $capabilities = LoaderFactory::getLoader()->getShared('EE_Capabilities');
145
-                    $capabilities->removeCaps(
146
-                        EE_Register_Payment_Method::getPaymentMethodCapabilities($module_settings)
147
-                    );
148
-                }
149
-            );
150
-        }
151
-    }
124
+	/**
125
+	 * This deregisters a module that was previously registered with a specific $identifier.
126
+	 *
127
+	 * @param string $identifier the name for the module that was previously registered
128
+	 * @return void
129
+	 * @throws DomainException
130
+	 * @throws InvalidArgumentException
131
+	 * @throws InvalidInterfaceException
132
+	 * @throws InvalidDataTypeException
133
+	 * @since    4.3.0
134
+	 */
135
+	public static function deregister($identifier = '')
136
+	{
137
+		if (isset(self::$_settings[ $identifier ])) {
138
+			// set action for just this module id to delay deregistration until core is loaded and ready.
139
+			$module_settings = self::$_settings[ $identifier ];
140
+			unset(self::$_settings[ $identifier ]);
141
+			add_action(
142
+				'AHEE__EE_System__core_loaded_and_ready',
143
+				function () use ($module_settings) {
144
+					$capabilities = LoaderFactory::getLoader()->getShared('EE_Capabilities');
145
+					$capabilities->removeCaps(
146
+						EE_Register_Payment_Method::getPaymentMethodCapabilities($module_settings)
147
+					);
148
+				}
149
+			);
150
+		}
151
+	}
152 152
 
153 153
 
154
-    /**
155
-     * returns an array of the caps that get added when a Payment Method is registered
156
-     *
157
-     * @param array $settings
158
-     * @return array
159
-     * @throws DomainException
160
-     * @throws InvalidArgumentException
161
-     * @throws InvalidInterfaceException
162
-     * @throws InvalidDataTypeException
163
-     * @access private  Developers do NOT use this method.  It's only public for PHP5.3 closure support (see deregister)
164
-     *                  When we drop support for PHP5.3 this will be made private again.  You have been warned.
165
-     */
166
-    public static function getPaymentMethodCapabilities(array $settings)
167
-    {
168
-        $payment_method_manager = LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
169
-        $payment_method_caps    = ['administrator' => []];
170
-        if (isset($settings['payment_method_paths'])) {
171
-            foreach ($settings['payment_method_paths'] as $payment_method_path) {
172
-                $payment_method_caps = $payment_method_manager->addPaymentMethodCap(
173
-                    strtolower(basename($payment_method_path)),
174
-                    $payment_method_caps
175
-                );
176
-            }
177
-        }
178
-        return $payment_method_caps;
179
-    }
154
+	/**
155
+	 * returns an array of the caps that get added when a Payment Method is registered
156
+	 *
157
+	 * @param array $settings
158
+	 * @return array
159
+	 * @throws DomainException
160
+	 * @throws InvalidArgumentException
161
+	 * @throws InvalidInterfaceException
162
+	 * @throws InvalidDataTypeException
163
+	 * @access private  Developers do NOT use this method.  It's only public for PHP5.3 closure support (see deregister)
164
+	 *                  When we drop support for PHP5.3 this will be made private again.  You have been warned.
165
+	 */
166
+	public static function getPaymentMethodCapabilities(array $settings)
167
+	{
168
+		$payment_method_manager = LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
169
+		$payment_method_caps    = ['administrator' => []];
170
+		if (isset($settings['payment_method_paths'])) {
171
+			foreach ($settings['payment_method_paths'] as $payment_method_path) {
172
+				$payment_method_caps = $payment_method_manager->addPaymentMethodCap(
173
+					strtolower(basename($payment_method_path)),
174
+					$payment_method_caps
175
+				);
176
+			}
177
+		}
178
+		return $payment_method_caps;
179
+	}
180 180
 }
Please login to merge, or discard this patch.
core/libraries/plugin_api/EE_Register_Messages_Template_Pack.lib.php 2 patches
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -70,13 +70,13 @@  discard block
 block discarded – undo
70 70
         }
71 71
 
72 72
         // make sure we don't register twice
73
-        if (isset(self::$_registry[ $identifier ])) {
73
+        if (isset(self::$_registry[$identifier])) {
74 74
             return;
75 75
         }
76 76
 
77 77
         // check that incoming $identifier doesn't already exist. If it does then we'll create a unique reference for this template pack.
78
-        if (isset(self::$_registry[ $identifier ])) {
79
-            $identifier = uniqid() . '_' . $identifier;
78
+        if (isset(self::$_registry[$identifier])) {
79
+            $identifier = uniqid().'_'.$identifier;
80 80
         }
81 81
 
82 82
 
@@ -99,7 +99,7 @@  discard block
 block discarded – undo
99 99
         }
100 100
 
101 101
         if (self::_verify_class_not_exist($setup_args['classname'])) {
102
-            self::$_registry[ $identifier ] = [
102
+            self::$_registry[$identifier] = [
103 103
                 'path'      => (string) $setup_args['path'],
104 104
                 'classname' => (string) $setup_args['classname'],
105 105
             ];
@@ -151,14 +151,14 @@  discard block
 block discarded – undo
151 151
     {
152 152
         foreach (self::$_registry as $args) {
153 153
             // verify class_exists
154
-            if (! class_exists($args['classname'])) {
155
-                require_once($args['path'] . '/' . $args['classname'] . '.class.php');
154
+            if ( ! class_exists($args['classname'])) {
155
+                require_once($args['path'].'/'.$args['classname'].'.class.php');
156 156
             }
157 157
 
158 158
             // check again!
159 159
             if (class_exists($args['classname'])) {
160 160
                 $template_pack                           = new $args['classname']();
161
-                $template_packs[ $template_pack->dbref ] = $template_pack;
161
+                $template_packs[$template_pack->dbref] = $template_pack;
162 162
             }
163 163
         }
164 164
 
@@ -208,6 +208,6 @@  discard block
 block discarded – undo
208 208
      */
209 209
     public static function deregister($identifier = '')
210 210
     {
211
-        unset(self::$_registry[ $identifier ]);
211
+        unset(self::$_registry[$identifier]);
212 212
     }
213 213
 }
Please login to merge, or discard this patch.
Indentation   +198 added lines, -198 removed lines patch added patch discarded remove patch
@@ -10,202 +10,202 @@
 block discarded – undo
10 10
  */
11 11
 class EE_Register_Messages_Template_Pack implements EEI_Plugin_API
12 12
 {
13
-    /**
14
-     * Holds values for registered template pack
15
-     *
16
-     * @since 4.5.0
17
-     *
18
-     * @var array
19
-     */
20
-    protected static $_registry = [];
21
-
22
-
23
-    /**
24
-     * Used to register a new template pack with the messages system.
25
-     *
26
-     * Template packs are primarily defined via class extending EE_Messages_Template_Pack and are typically used to
27
-     * change entire layouts for a set of message templates.  This method is used to register the new template pack and
28
-     * automatically have it loaded in the appropriate places.
29
-     *
30
-     * This registry also verifies that there isn't already a template pack registered with the same name and if there
31
-     * is then it will add an EE_Error notice.
32
-     *
33
-     * Note that this only handles registering the your Template Pack class with the message template pack system.
34
-     * However, there is also a naming schema you must follow for templates you are providing with your template pack.
35
-     *
36
-     * @param string $identifier The internal reference used to refer to this template pack.  Note, this is first come,
37
-     *                           first serve.  If there is already a template pack registered with this name then the
38
-     *                           registry will assign a unique reference for it so it can still be activated (but this
39
-     *                           makes it harder to deregister as it will be unique per load - so its best to try to
40
-     *                           make this a unique string!)
41
-     * @param array  $setup_args array {
42
-     *                           An array of required values for registering the template pack.
43
-     * @type string  $path       The path for the new template pack class.
44
-     * @type string  $classname  The name of the new Template Pack Class.
45
-     *                           }
46
-     *
47
-     * @return void
48
-     * @throws EE_Error
49
-     *
50
-     * @see    core/libraries/messages/defaults/default/* for all the example templates the default template pack
51
-     *         supports.
52
-     *
53
-     *
54
-     * @since  4.5.0
55
-     * @see    EE_Messages_Template_Pack_Default for an example class
56
-     */
57
-    public static function register($identifier = '', array $setup_args = [])
58
-    {
59
-
60
-        // check for required params
61
-        if (empty($identifier) || empty($setup_args['path']) || empty($setup_args['classname'])) {
62
-            throw new EE_Error(
63
-                esc_html__(
64
-                    'In order to register a new template pack for the EE Messages system, you must include a value to reference the template pack being registered and the setup_args must have the path for the new template pack class as well as the classname for the new Template Pack Class. ',
65
-                    'event_espresso'
66
-                )
67
-            );
68
-        }
69
-
70
-        // make sure we don't register twice
71
-        if (isset(self::$_registry[ $identifier ])) {
72
-            return;
73
-        }
74
-
75
-        // check that incoming $identifier doesn't already exist. If it does then we'll create a unique reference for this template pack.
76
-        if (isset(self::$_registry[ $identifier ])) {
77
-            $identifier = uniqid() . '_' . $identifier;
78
-        }
79
-
80
-
81
-        // make sure this was called in the right place!
82
-        if (
83
-            ! did_action('EE_Brewing_Regular___messages_caf')
84
-            || did_action('AHEE__EE_System__perform_activations_upgrades_and_migrations')
85
-        ) {
86
-            EE_Error::doing_it_wrong(
87
-                __METHOD__,
88
-                sprintf(
89
-                    esc_html__(
90
-                        'A EE Messages Template Pack given the reference "%s" has been attempted to be registered with the EE Messages System.  It may or may not work because it should be only called on the "EE_Brewing_Regular__messages_caf" hook.',
91
-                        'event_espresso'
92
-                    ),
93
-                    $identifier
94
-                ),
95
-                '4.5.0'
96
-            );
97
-        }
98
-
99
-        if (self::_verify_class_not_exist($setup_args['classname'])) {
100
-            self::$_registry[ $identifier ] = [
101
-                'path'      => (string) $setup_args['path'],
102
-                'classname' => (string) $setup_args['classname'],
103
-            ];
104
-        }
105
-
106
-        // hook into the system
107
-        add_filter(
108
-            'FHEE__EED_Messages___set_messages_paths___MSG_PATHS',
109
-            ['EE_Register_Messages_Template_Pack', 'set_template_pack_path'],
110
-            10
111
-        );
112
-        add_filter(
113
-            'FHEE__EED_Messages__get_template_packs__template_packs',
114
-            ['EE_Register_Messages_Template_Pack', 'set_template_pack'],
115
-            10
116
-        );
117
-    }
118
-
119
-
120
-    /**
121
-     * Callback for the FHEE__EED_Messages___set_messages_paths___MSG_PATHS filter.  This adds this template packs path
122
-     * to the messages autoloader paths.
123
-     *
124
-     * @param array $paths Array of paths already registered with the messages autoloader
125
-     *
126
-     * @return array
127
-     * @since  4.5.0
128
-     *
129
-     */
130
-    public static function set_template_pack_path(array $paths)
131
-    {
132
-        foreach (self::$_registry as $args) {
133
-            $paths[] = $args['path'];
134
-        }
135
-        return $paths;
136
-    }
137
-
138
-
139
-    /**
140
-     * Callback for the FHEE__EED_Messages__get_template_packs__template_packs filter. This adds the instantiated,
141
-     * registered template pack to the template packs array when requested by client code.
142
-     *
143
-     * @param EE_Messages_Template_Pack[] $template_packs
144
-     * @return EE_Messages_Template_Pack[]
145
-     * @since 4.5.0
146
-     *
147
-     */
148
-    public static function set_template_pack(array $template_packs)
149
-    {
150
-        foreach (self::$_registry as $args) {
151
-            // verify class_exists
152
-            if (! class_exists($args['classname'])) {
153
-                require_once($args['path'] . '/' . $args['classname'] . '.class.php');
154
-            }
155
-
156
-            // check again!
157
-            if (class_exists($args['classname'])) {
158
-                $template_pack                           = new $args['classname']();
159
-                $template_packs[ $template_pack->dbref ] = $template_pack;
160
-            }
161
-        }
162
-
163
-        return $template_packs;
164
-    }
165
-
166
-
167
-    /**
168
-     * This verifies that the classes for each registered template pack are unique  names.
169
-     *
170
-     * @param string $classname The classname being checked
171
-     *
172
-     * @return bool
173
-     */
174
-    private static function _verify_class_not_exist($classname)
175
-    {
176
-        // loop through the existing registry and see if the classname is already present.
177
-        foreach (self::$_registry as $args) {
178
-            if ($args['classname'] == $classname) {
179
-                EE_Error::add_error(
180
-                    sprintf(
181
-                        esc_html__(
182
-                            'The %s template pack that you just activated cannot be registered with the messages system because there is already a template pack active using the same classname.  Contact the author of this template pack to let them know of the conflict.  To stop seeing this message you will need to deactivate this template pack.',
183
-                            'event_espresso'
184
-                        ),
185
-                        $classname
186
-                    ),
187
-                    __FILE__,
188
-                    __LINE__,
189
-                    __FUNCTION__
190
-                );
191
-                return false;
192
-            }
193
-        }
194
-        return true;
195
-    }
196
-
197
-
198
-    /**
199
-     * This deregisters a variation set that was previously registered with the given slug.
200
-     *
201
-     * @param string $identifier The name for the variation set that was previously registered.
202
-     *
203
-     * @return void
204
-     * @since 4.5.0
205
-     *
206
-     */
207
-    public static function deregister($identifier = '')
208
-    {
209
-        unset(self::$_registry[ $identifier ]);
210
-    }
13
+	/**
14
+	 * Holds values for registered template pack
15
+	 *
16
+	 * @since 4.5.0
17
+	 *
18
+	 * @var array
19
+	 */
20
+	protected static $_registry = [];
21
+
22
+
23
+	/**
24
+	 * Used to register a new template pack with the messages system.
25
+	 *
26
+	 * Template packs are primarily defined via class extending EE_Messages_Template_Pack and are typically used to
27
+	 * change entire layouts for a set of message templates.  This method is used to register the new template pack and
28
+	 * automatically have it loaded in the appropriate places.
29
+	 *
30
+	 * This registry also verifies that there isn't already a template pack registered with the same name and if there
31
+	 * is then it will add an EE_Error notice.
32
+	 *
33
+	 * Note that this only handles registering the your Template Pack class with the message template pack system.
34
+	 * However, there is also a naming schema you must follow for templates you are providing with your template pack.
35
+	 *
36
+	 * @param string $identifier The internal reference used to refer to this template pack.  Note, this is first come,
37
+	 *                           first serve.  If there is already a template pack registered with this name then the
38
+	 *                           registry will assign a unique reference for it so it can still be activated (but this
39
+	 *                           makes it harder to deregister as it will be unique per load - so its best to try to
40
+	 *                           make this a unique string!)
41
+	 * @param array  $setup_args array {
42
+	 *                           An array of required values for registering the template pack.
43
+	 * @type string  $path       The path for the new template pack class.
44
+	 * @type string  $classname  The name of the new Template Pack Class.
45
+	 *                           }
46
+	 *
47
+	 * @return void
48
+	 * @throws EE_Error
49
+	 *
50
+	 * @see    core/libraries/messages/defaults/default/* for all the example templates the default template pack
51
+	 *         supports.
52
+	 *
53
+	 *
54
+	 * @since  4.5.0
55
+	 * @see    EE_Messages_Template_Pack_Default for an example class
56
+	 */
57
+	public static function register($identifier = '', array $setup_args = [])
58
+	{
59
+
60
+		// check for required params
61
+		if (empty($identifier) || empty($setup_args['path']) || empty($setup_args['classname'])) {
62
+			throw new EE_Error(
63
+				esc_html__(
64
+					'In order to register a new template pack for the EE Messages system, you must include a value to reference the template pack being registered and the setup_args must have the path for the new template pack class as well as the classname for the new Template Pack Class. ',
65
+					'event_espresso'
66
+				)
67
+			);
68
+		}
69
+
70
+		// make sure we don't register twice
71
+		if (isset(self::$_registry[ $identifier ])) {
72
+			return;
73
+		}
74
+
75
+		// check that incoming $identifier doesn't already exist. If it does then we'll create a unique reference for this template pack.
76
+		if (isset(self::$_registry[ $identifier ])) {
77
+			$identifier = uniqid() . '_' . $identifier;
78
+		}
79
+
80
+
81
+		// make sure this was called in the right place!
82
+		if (
83
+			! did_action('EE_Brewing_Regular___messages_caf')
84
+			|| did_action('AHEE__EE_System__perform_activations_upgrades_and_migrations')
85
+		) {
86
+			EE_Error::doing_it_wrong(
87
+				__METHOD__,
88
+				sprintf(
89
+					esc_html__(
90
+						'A EE Messages Template Pack given the reference "%s" has been attempted to be registered with the EE Messages System.  It may or may not work because it should be only called on the "EE_Brewing_Regular__messages_caf" hook.',
91
+						'event_espresso'
92
+					),
93
+					$identifier
94
+				),
95
+				'4.5.0'
96
+			);
97
+		}
98
+
99
+		if (self::_verify_class_not_exist($setup_args['classname'])) {
100
+			self::$_registry[ $identifier ] = [
101
+				'path'      => (string) $setup_args['path'],
102
+				'classname' => (string) $setup_args['classname'],
103
+			];
104
+		}
105
+
106
+		// hook into the system
107
+		add_filter(
108
+			'FHEE__EED_Messages___set_messages_paths___MSG_PATHS',
109
+			['EE_Register_Messages_Template_Pack', 'set_template_pack_path'],
110
+			10
111
+		);
112
+		add_filter(
113
+			'FHEE__EED_Messages__get_template_packs__template_packs',
114
+			['EE_Register_Messages_Template_Pack', 'set_template_pack'],
115
+			10
116
+		);
117
+	}
118
+
119
+
120
+	/**
121
+	 * Callback for the FHEE__EED_Messages___set_messages_paths___MSG_PATHS filter.  This adds this template packs path
122
+	 * to the messages autoloader paths.
123
+	 *
124
+	 * @param array $paths Array of paths already registered with the messages autoloader
125
+	 *
126
+	 * @return array
127
+	 * @since  4.5.0
128
+	 *
129
+	 */
130
+	public static function set_template_pack_path(array $paths)
131
+	{
132
+		foreach (self::$_registry as $args) {
133
+			$paths[] = $args['path'];
134
+		}
135
+		return $paths;
136
+	}
137
+
138
+
139
+	/**
140
+	 * Callback for the FHEE__EED_Messages__get_template_packs__template_packs filter. This adds the instantiated,
141
+	 * registered template pack to the template packs array when requested by client code.
142
+	 *
143
+	 * @param EE_Messages_Template_Pack[] $template_packs
144
+	 * @return EE_Messages_Template_Pack[]
145
+	 * @since 4.5.0
146
+	 *
147
+	 */
148
+	public static function set_template_pack(array $template_packs)
149
+	{
150
+		foreach (self::$_registry as $args) {
151
+			// verify class_exists
152
+			if (! class_exists($args['classname'])) {
153
+				require_once($args['path'] . '/' . $args['classname'] . '.class.php');
154
+			}
155
+
156
+			// check again!
157
+			if (class_exists($args['classname'])) {
158
+				$template_pack                           = new $args['classname']();
159
+				$template_packs[ $template_pack->dbref ] = $template_pack;
160
+			}
161
+		}
162
+
163
+		return $template_packs;
164
+	}
165
+
166
+
167
+	/**
168
+	 * This verifies that the classes for each registered template pack are unique  names.
169
+	 *
170
+	 * @param string $classname The classname being checked
171
+	 *
172
+	 * @return bool
173
+	 */
174
+	private static function _verify_class_not_exist($classname)
175
+	{
176
+		// loop through the existing registry and see if the classname is already present.
177
+		foreach (self::$_registry as $args) {
178
+			if ($args['classname'] == $classname) {
179
+				EE_Error::add_error(
180
+					sprintf(
181
+						esc_html__(
182
+							'The %s template pack that you just activated cannot be registered with the messages system because there is already a template pack active using the same classname.  Contact the author of this template pack to let them know of the conflict.  To stop seeing this message you will need to deactivate this template pack.',
183
+							'event_espresso'
184
+						),
185
+						$classname
186
+					),
187
+					__FILE__,
188
+					__LINE__,
189
+					__FUNCTION__
190
+				);
191
+				return false;
192
+			}
193
+		}
194
+		return true;
195
+	}
196
+
197
+
198
+	/**
199
+	 * This deregisters a variation set that was previously registered with the given slug.
200
+	 *
201
+	 * @param string $identifier The name for the variation set that was previously registered.
202
+	 *
203
+	 * @return void
204
+	 * @since 4.5.0
205
+	 *
206
+	 */
207
+	public static function deregister($identifier = '')
208
+	{
209
+		unset(self::$_registry[ $identifier ]);
210
+	}
211 211
 }
Please login to merge, or discard this patch.