Completed
Branch BUG/update-unit-tests (7b5400)
by
unknown
07:51 queued 05:38
created
core/db_classes/EE_Question_Form_Input.class.php 2 patches
Spacing   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
      */
115 115
     public function set_question_form_input_meta($q_meta = [])
116 116
     {
117
-        $default_q_meta  = [
117
+        $default_q_meta = [
118 118
             'att_nmbr'       => 1,
119 119
             'ticket_id'      => '',
120 120
             'date'           => '',
@@ -160,13 +160,13 @@  discard block
 block discarded – undo
160 160
      */
161 161
     private function _set_input_name($qstn_id)
162 162
     {
163
-        if (! empty($qstn_id)) {
163
+        if ( ! empty($qstn_id)) {
164 164
             $ANS_ID  = $this->get('ANS_ID');
165
-            $qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']';
165
+            $qstn_id = ! empty($ANS_ID) ? '['.$qstn_id.']['.$ANS_ID.']' : '['.$qstn_id.']';
166 166
         }
167 167
         $this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
168
-            ? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id
169
-            : $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'];
168
+            ? $this->_QST_meta['input_prefix'].$this->_QST_meta['input_name'].$qstn_id
169
+            : $this->_QST_meta['input_prefix'].$this->_QST_meta['input_name'];
170 170
     }
171 171
 
172 172
 
@@ -181,7 +181,7 @@  discard block
 block discarded – undo
181 181
      */
182 182
     public function get($property = null)
183 183
     {
184
-        if (! empty($property)) {
184
+        if ( ! empty($property)) {
185 185
             if (EEM_Question::instance()->has_field($property)) {
186 186
                 return $this->_QST->get($property);
187 187
             } elseif (EEM_Answer::instance()->has_field($property)) {
@@ -207,7 +207,7 @@  discard block
 block discarded – undo
207 207
     {
208 208
         // first try regular property exists method which works as expected in PHP 5.3+
209 209
         $prop = EEH_Class_Tools::has_property($classname, $property);
210
-        if (! $prop) {
210
+        if ( ! $prop) {
211 211
             // use reflection for < PHP 5.3 as a double check when property is not found, possible due to access restriction
212 212
             $reflector = new ReflectionClass($classname);
213 213
             $prop      = $reflector->hasProperty($property);
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
             ? $this->_QST_meta['input_id']
232 232
             : sanitize_key(strip_tags($this->_QST->get('QST_display_text')));
233 233
         $this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
234
-            ? $input_id . '-' . $qstn_id
234
+            ? $input_id.'-'.$qstn_id
235 235
             : $input_id;
236 236
     }
237 237
 
@@ -272,8 +272,8 @@  discard block
 block discarded – undo
272 272
             $date = $this->_QST_meta['date'];
273 273
             $time = $this->_QST_meta['time'];
274 274
             $price_id = $this->_QST_meta['price_id'];
275
-            if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) {
276
-                $answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ];
275
+            if (isset($this->form_data['qstn'][$EVT_ID][$att_nmbr][$date][$time][$price_id][$qstn_id])) {
276
+                $answer = $this->form_data['qstn'][$EVT_ID][$att_nmbr][$date][$time][$price_id][$qstn_id];
277 277
                 $this->_ANS->set('ANS_value', $answer);
278 278
             }
279 279
         }
@@ -292,42 +292,42 @@  discard block
 block discarded – undo
292 292
      */
293 293
     public static function generate_question_form_inputs_for_object($object = false, $input_types = [])
294 294
     {
295
-        if (! is_object($object)) {
295
+        if ( ! is_object($object)) {
296 296
             return [];
297 297
         }
298 298
         $inputs = [];
299 299
         $fields = $object->get_model()->field_settings(false);
300 300
         foreach ($fields as $field_ID => $field) {
301 301
             if ($field instanceof EE_Model_Field_Base) {
302
-                if (isset($input_types[ $field_ID ])) {
302
+                if (isset($input_types[$field_ID])) {
303 303
                     // get saved value for field
304 304
                     $value = $object->get($field_ID);
305 305
                     // if no saved value, then use default
306 306
                     $value = $value !== null ? $value : $field->get_default_value();
307 307
                     // determine question type
308
-                    $type = isset($input_types[ $field_ID ]) ? $input_types[ $field_ID ]['type'] : 'TEXT';
308
+                    $type = isset($input_types[$field_ID]) ? $input_types[$field_ID]['type'] : 'TEXT';
309 309
                     // input name
310
-                    $input_name = isset($input_types[ $field_ID ]) && isset($input_types[ $field_ID ]['input_name'])
311
-                        ? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']'
310
+                    $input_name = isset($input_types[$field_ID]) && isset($input_types[$field_ID]['input_name'])
311
+                        ? $input_types[$field_ID]['input_name'].'['.$field_ID.']'
312 312
                         : $field_ID;
313 313
                     // css class for input
314
-                    $class = isset($input_types[ $field_ID ]['class']) && ! empty($input_types[ $field_ID ]['class'])
315
-                        ? ' ' . $input_types[ $field_ID ]['class']
314
+                    $class = isset($input_types[$field_ID]['class']) && ! empty($input_types[$field_ID]['class'])
315
+                        ? ' '.$input_types[$field_ID]['class']
316 316
                         : '';
317 317
                     // whether to apply htmlentities to answer
318
-                    $htmlentities = isset($input_types[ $field_ID ]['htmlentities'])
319
-                        ? $input_types[ $field_ID ]['htmlentities']
318
+                    $htmlentities = isset($input_types[$field_ID]['htmlentities'])
319
+                        ? $input_types[$field_ID]['htmlentities']
320 320
                         : true;
321 321
                     // whether to apply htmlentities to answer
322
-                    $label_b4 = isset($input_types[ $field_ID ]['label_b4'])
323
-                        ? $input_types[ $field_ID ]['label_b4']
322
+                    $label_b4 = isset($input_types[$field_ID]['label_b4'])
323
+                        ? $input_types[$field_ID]['label_b4']
324 324
                         : false;
325 325
                     // whether to apply htmlentities to answer
326
-                    $use_desc_4_label = isset($input_types[ $field_ID ]['use_desc_4_label'])
327
-                        ? $input_types[ $field_ID ]['use_desc_4_label']
326
+                    $use_desc_4_label = isset($input_types[$field_ID]['use_desc_4_label'])
327
+                        ? $input_types[$field_ID]['use_desc_4_label']
328 328
                         : false;
329 329
                     // whether input is disabled
330
-                    $disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled'];
330
+                    $disabled = isset($input_types[$field_ID]['disabled']) && $input_types[$field_ID]['disabled'];
331 331
 
332 332
                     // create EE_Question_Form_Input object
333 333
                     $QFI = new EE_Question_Form_Input(
@@ -347,9 +347,9 @@  discard block
 block discarded – undo
347 347
                             ]
348 348
                         ),
349 349
                         [
350
-                            'input_id'         => $field_ID . '-' . $object->ID(),
350
+                            'input_id'         => $field_ID.'-'.$object->ID(),
351 351
                             'input_name'       => $input_name,
352
-                            'input_class'      => $field_ID . $class,
352
+                            'input_class'      => $field_ID.$class,
353 353
                             'input_prefix'     => '',
354 354
                             'append_qstn_id'   => false,
355 355
                             'htmlentities'     => $htmlentities,
@@ -360,10 +360,10 @@  discard block
 block discarded – undo
360 360
                     // does question type have options ?
361 361
                     if (
362 362
                         in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX'])
363
-                        && isset($input_types[ $field_ID ])
364
-                        && isset($input_types[ $field_ID ]['options'])
363
+                        && isset($input_types[$field_ID])
364
+                        && isset($input_types[$field_ID]['options'])
365 365
                     ) {
366
-                        foreach ($input_types[ $field_ID ]['options'] as $option) {
366
+                        foreach ($input_types[$field_ID]['options'] as $option) {
367 367
                             $option    = stripslashes_deep($option);
368 368
                             $option_id = ! empty($option['id']) ? $option['id'] : 0;
369 369
                             $QSO       = EE_Question_Option::new_instance(
@@ -381,7 +381,7 @@  discard block
 block discarded – undo
381 381
                     if ($disabled || $field_ID == $object->get_model()->primary_key_name()) {
382 382
                         $QFI->set('QST_disabled', true);
383 383
                     }
384
-                    $inputs[ $field_ID ] = $QFI;
384
+                    $inputs[$field_ID] = $QFI;
385 385
                 }
386 386
             }
387 387
         }
@@ -414,7 +414,7 @@  discard block
 block discarded – undo
414 414
      */
415 415
     public function set($property = null, $value = null)
416 416
     {
417
-        if (! empty($property)) {
417
+        if ( ! empty($property)) {
418 418
             if (EEM_Question::instance()->has_field($property)) {
419 419
                 $this->_QST->set($property, $value);
420 420
             } elseif (EEM_Answer::instance()->has_field($property)) {
@@ -460,6 +460,6 @@  discard block
 block discarded – undo
460 460
      */
461 461
     public function get_meta($key = false)
462 462
     {
463
-        return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false;
463
+        return $key && isset($this->_QST_meta[$key]) ? $this->_QST_meta[$key] : false;
464 464
     }
465 465
 }
Please login to merge, or discard this patch.
Indentation   +446 added lines, -446 removed lines patch added patch discarded remove patch
@@ -15,450 +15,450 @@
 block discarded – undo
15 15
  */
16 16
 class EE_Question_Form_Input
17 17
 {
18
-    /**
19
-     *    EE_Question object
20
-     *
21
-     * @access private
22
-     * @var object
23
-     */
24
-    private $_QST = null;
25
-
26
-    /**
27
-     *    EE_Answer object
28
-     *
29
-     * @access private
30
-     * @var object
31
-     */
32
-    private $_ANS = null;
33
-
34
-    /**
35
-     *    $_QST_meta
36
-     * @access private
37
-     * @var array
38
-     */
39
-    private $_QST_meta = [];
40
-
41
-    /**
42
-     *    $QST_input_name
43
-     * @access private
44
-     * @var string
45
-     */
46
-    private $QST_input_name = '';
47
-
48
-    /**
49
-     *    $QST_input_id
50
-     * @access private
51
-     * @var string
52
-     */
53
-    private $QST_input_id = '';
54
-
55
-    /**
56
-     *    $QST_input_class
57
-     * @access private
58
-     * @var string
59
-     */
60
-    private $QST_input_class = '';
61
-
62
-    /**
63
-     * @var bool $QST_disabled
64
-     */
65
-    private $QST_disabled = false;
66
-
67
-    /**
68
-     * @var RequestInterface
69
-     */
70
-    protected $request;
71
-
72
-    /**
73
-     * @var array
74
-     */
75
-    protected $form_data;
76
-
77
-
78
-    /**
79
-     * constructor for questions
80
-     *
81
-     * @param EE_Question $QST EE_Question object
82
-     * @param EE_Answer   $ANS EE_Answer object
83
-     * @param array       $q_meta
84
-     * @throws EE_Error
85
-     * @throws ReflectionException
86
-     */
87
-    public function __construct(EE_Question $QST = null, EE_Answer $ANS = null, $q_meta = [])
88
-    {
89
-        $this->request   = LoaderFactory::getLoader()->getShared(RequestInterface::class);
90
-        $this->form_data = $this->request->requestParams();
91
-        if (empty($QST) || empty($ANS)) {
92
-            EE_Error::add_error(
93
-                esc_html__('An error occurred. A valid EE_Question or EE_Answer object was not received.', 'event_espresso'),
94
-                __FILE__,
95
-                __FUNCTION__,
96
-                __LINE__
97
-            );
98
-            return null;
99
-        }
100
-        $this->_QST = $QST;
101
-        $this->_ANS = $ANS;
102
-        $this->set_question_form_input_meta($q_meta);
103
-        $this->set_question_form_input_init();
104
-    }
105
-
106
-
107
-    /**
108
-     * sets meta data for the question form input
109
-     *
110
-     * @access public
111
-     * @param array $q_meta
112
-     * @return void
113
-     */
114
-    public function set_question_form_input_meta($q_meta = [])
115
-    {
116
-        $default_q_meta  = [
117
-            'att_nmbr'       => 1,
118
-            'ticket_id'      => '',
119
-            'date'           => '',
120
-            'time'           => '',
121
-            'input_name'     => '',
122
-            'input_id'       => '',
123
-            'input_class'    => '',
124
-            'input_prefix'   => 'qstn',
125
-            'append_qstn_id' => true,
126
-            'htmlentities'   => true,
127
-            'allow_null'     => false,
128
-        ];
129
-        $this->_QST_meta = array_merge($default_q_meta, $q_meta);
130
-    }
131
-
132
-
133
-    /**
134
-     * set_question_form_input_init
135
-     *
136
-     * @access public
137
-     * @return void
138
-     * @throws EE_Error
139
-     * @throws ReflectionException
140
-     */
141
-    public function set_question_form_input_init()
142
-    {
143
-        $qstn_id = $this->_QST->system_ID() ? $this->_QST->system_ID() : $this->_QST->ID();
144
-        $this->_set_input_name($qstn_id);
145
-        $this->_set_input_id($qstn_id);
146
-        $this->_set_input_class();
147
-        $this->set_question_form_input_answer($qstn_id);
148
-    }
149
-
150
-
151
-    /**
152
-     * set_input_name
153
-     *
154
-     * @access private
155
-     * @param $qstn_id
156
-     * @return void
157
-     * @throws EE_Error
158
-     * @throws ReflectionException
159
-     */
160
-    private function _set_input_name($qstn_id)
161
-    {
162
-        if (! empty($qstn_id)) {
163
-            $ANS_ID  = $this->get('ANS_ID');
164
-            $qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']';
165
-        }
166
-        $this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
167
-            ? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id
168
-            : $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'];
169
-    }
170
-
171
-
172
-    /**
173
-     * get property values for question form input
174
-     *
175
-     * @access public
176
-     * @param string $property
177
-     * @return mixed
178
-     * @throws EE_Error
179
-     * @throws ReflectionException
180
-     */
181
-    public function get($property = null)
182
-    {
183
-        if (! empty($property)) {
184
-            if (EEM_Question::instance()->has_field($property)) {
185
-                return $this->_QST->get($property);
186
-            } elseif (EEM_Answer::instance()->has_field($property)) {
187
-                return $this->_ANS->get($property);
188
-            } elseif ($this->_question_form_input_property_exists(__CLASS__, $property)) {
189
-                return $this->{$property};
190
-            }
191
-        }
192
-        return null;
193
-    }
194
-
195
-
196
-    /**
197
-     *    _question_form_input_property_exists
198
-     *
199
-     * @access private
200
-     * @param string $classname
201
-     * @param string $property
202
-     * @return boolean
203
-     * @throws ReflectionException
204
-     */
205
-    private function _question_form_input_property_exists($classname, $property)
206
-    {
207
-        // first try regular property exists method which works as expected in PHP 5.3+
208
-        $prop = EEH_Class_Tools::has_property($classname, $property);
209
-        if (! $prop) {
210
-            // use reflection for < PHP 5.3 as a double check when property is not found, possible due to access restriction
211
-            $reflector = new ReflectionClass($classname);
212
-            $prop      = $reflector->hasProperty($property);
213
-        }
214
-        return $prop;
215
-    }
216
-
217
-
218
-    /**
219
-     * set_input_id
220
-     *
221
-     * @access private
222
-     * @param $qstn_id
223
-     * @return void
224
-     * @throws EE_Error
225
-     * @throws ReflectionException
226
-     */
227
-    private function _set_input_id($qstn_id)
228
-    {
229
-        $input_id           = isset($this->_QST_meta['input_id']) && ! empty($this->_QST_meta['input_id'])
230
-            ? $this->_QST_meta['input_id']
231
-            : sanitize_key(strip_tags($this->_QST->get('QST_display_text')));
232
-        $this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
233
-            ? $input_id . '-' . $qstn_id
234
-            : $input_id;
235
-    }
236
-
237
-
238
-    /**
239
-     * set_input_class
240
-     *
241
-     * @access private
242
-     * @return void
243
-     */
244
-    private function _set_input_class()
245
-    {
246
-        $this->QST_input_class = isset($this->_QST_meta['input_class']) ? $this->_QST_meta['input_class'] : '';
247
-    }
248
-
249
-
250
-    /**
251
-     * set_question_form_input_answer
252
-     *
253
-     * @access public
254
-     * @param mixed    int | string    $qstn_id
255
-     * @return void
256
-     * @throws EE_Error
257
-     * @throws ReflectionException
258
-     */
259
-    public function set_question_form_input_answer($qstn_id)
260
-    {
261
-        // check for answer in $this->form_data in case we are reprocessing a form after an error
262
-        if (
263
-            isset($this->_QST_meta['EVT_ID'])
264
-            && isset($this->_QST_meta['att_nmbr'])
265
-            && isset($this->_QST_meta['date'])
266
-            && isset($this->_QST_meta['time'])
267
-            && isset($this->_QST_meta['price_id'])
268
-        ) {
269
-            $EVT_ID = $this->_QST_meta['EVT_ID'];
270
-            $att_nmbr = $this->_QST_meta['att_nmbr'];
271
-            $date = $this->_QST_meta['date'];
272
-            $time = $this->_QST_meta['time'];
273
-            $price_id = $this->_QST_meta['price_id'];
274
-            if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) {
275
-                $answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ];
276
-                $this->_ANS->set('ANS_value', $answer);
277
-            }
278
-        }
279
-    }
280
-
281
-
282
-    /**
283
-     *        generate_question_form_inputs_for_object
284
-     *
285
-     * @access    protected
286
-     * @param bool|object $object $object
287
-     * @param array       $input_types
288
-     * @return        array
289
-     * @throws EE_Error
290
-     * @throws ReflectionException
291
-     */
292
-    public static function generate_question_form_inputs_for_object($object = false, $input_types = [])
293
-    {
294
-        if (! is_object($object)) {
295
-            return [];
296
-        }
297
-        $inputs = [];
298
-        $fields = $object->get_model()->field_settings(false);
299
-        foreach ($fields as $field_ID => $field) {
300
-            if ($field instanceof EE_Model_Field_Base) {
301
-                if (isset($input_types[ $field_ID ])) {
302
-                    // get saved value for field
303
-                    $value = $object->get($field_ID);
304
-                    // if no saved value, then use default
305
-                    $value = $value !== null ? $value : $field->get_default_value();
306
-                    // determine question type
307
-                    $type = isset($input_types[ $field_ID ]) ? $input_types[ $field_ID ]['type'] : 'TEXT';
308
-                    // input name
309
-                    $input_name = isset($input_types[ $field_ID ]) && isset($input_types[ $field_ID ]['input_name'])
310
-                        ? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']'
311
-                        : $field_ID;
312
-                    // css class for input
313
-                    $class = isset($input_types[ $field_ID ]['class']) && ! empty($input_types[ $field_ID ]['class'])
314
-                        ? ' ' . $input_types[ $field_ID ]['class']
315
-                        : '';
316
-                    // whether to apply htmlentities to answer
317
-                    $htmlentities = isset($input_types[ $field_ID ]['htmlentities'])
318
-                        ? $input_types[ $field_ID ]['htmlentities']
319
-                        : true;
320
-                    // whether to apply htmlentities to answer
321
-                    $label_b4 = isset($input_types[ $field_ID ]['label_b4'])
322
-                        ? $input_types[ $field_ID ]['label_b4']
323
-                        : false;
324
-                    // whether to apply htmlentities to answer
325
-                    $use_desc_4_label = isset($input_types[ $field_ID ]['use_desc_4_label'])
326
-                        ? $input_types[ $field_ID ]['use_desc_4_label']
327
-                        : false;
328
-                    // whether input is disabled
329
-                    $disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled'];
330
-
331
-                    // create EE_Question_Form_Input object
332
-                    $QFI = new EE_Question_Form_Input(
333
-                        EE_Question::new_instance(
334
-                            [
335
-                                'QST_ID'           => 0,
336
-                                'QST_display_text' => $field->get_nicename(),
337
-                                'QST_type'         => $type,
338
-                            ]
339
-                        ),
340
-                        EE_Answer::new_instance(
341
-                            [
342
-                                'ANS_ID'    => 0,
343
-                                'QST_ID'    => 0,
344
-                                'REG_ID'    => 0,
345
-                                'ANS_value' => $value,
346
-                            ]
347
-                        ),
348
-                        [
349
-                            'input_id'         => $field_ID . '-' . $object->ID(),
350
-                            'input_name'       => $input_name,
351
-                            'input_class'      => $field_ID . $class,
352
-                            'input_prefix'     => '',
353
-                            'append_qstn_id'   => false,
354
-                            'htmlentities'     => $htmlentities,
355
-                            'label_b4'         => $label_b4,
356
-                            'use_desc_4_label' => $use_desc_4_label,
357
-                        ]
358
-                    );
359
-                    // does question type have options ?
360
-                    if (
361
-                        in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX'])
362
-                        && isset($input_types[ $field_ID ])
363
-                        && isset($input_types[ $field_ID ]['options'])
364
-                    ) {
365
-                        foreach ($input_types[ $field_ID ]['options'] as $option) {
366
-                            $option    = stripslashes_deep($option);
367
-                            $option_id = ! empty($option['id']) ? $option['id'] : 0;
368
-                            $QSO       = EE_Question_Option::new_instance(
369
-                                [
370
-                                    'QSO_value'   => (string) $option_id,
371
-                                    'QSO_desc'    => $option['text'],
372
-                                    'QSO_deleted' => false,
373
-                                ]
374
-                            );
375
-                            // all QST (and ANS) properties can be accessed indirectly thru QFI
376
-                            $QFI->add_temp_option($QSO);
377
-                        }
378
-                    }
379
-                    // we don't want ppl manually changing primary keys cuz that would just lead to total craziness man
380
-                    if ($disabled || $field_ID == $object->get_model()->primary_key_name()) {
381
-                        $QFI->set('QST_disabled', true);
382
-                    }
383
-                    $inputs[ $field_ID ] = $QFI;
384
-                }
385
-            }
386
-        }
387
-        return $inputs;
388
-    }
389
-
390
-
391
-    /**
392
-     *    add_temp_option
393
-     *
394
-     * @access public
395
-     * @param EE_Question_Option $QSO EE_Question_Option
396
-     * @return void
397
-     */
398
-    public function add_temp_option(EE_Question_Option $QSO)
399
-    {
400
-        $this->_QST->add_temp_option($QSO);
401
-    }
402
-
403
-
404
-    /**
405
-     * set property values for question form input
406
-     *
407
-     * @access public
408
-     * @param string $property
409
-     * @param mixed  $value
410
-     * @return void
411
-     * @throws EE_Error
412
-     * @throws ReflectionException
413
-     */
414
-    public function set($property = null, $value = null)
415
-    {
416
-        if (! empty($property)) {
417
-            if (EEM_Question::instance()->has_field($property)) {
418
-                $this->_QST->set($property, $value);
419
-            } elseif (EEM_Answer::instance()->has_field($property)) {
420
-                $this->_ANS->set($property, $value);
421
-            } elseif ($this->_question_form_input_property_exists(__CLASS__, $property)) {
422
-                $this->{$property} = $value;
423
-            }
424
-        }
425
-    }
426
-
427
-
428
-    /**
429
-     *    _question_form_input_property_exists
430
-     *
431
-     * @access public
432
-     * @param boolean      $notDeletedOptionsOnly            1
433
-     *                                                       whether to return ALL options, or only the ones which have
434
-     *                                                       not yet been deleted
435
-     * @param string|array $selected_value_to_always_include , when retrieving options to an ANSWERED question,
436
-     *                                                       we want to usually only show non-deleted options AND the
437
-     *                                                       value that was selected for the answer, whether it was
438
-     *                                                       trashed or not.
439
-     * @return EE_Question_Option
440
-     */
441
-    public function options($notDeletedOptionsOnly = true, $selected_value_to_always_include = null)
442
-    {
443
-        $temp_options = $this->_QST->temp_options();
444
-        return ! empty($temp_options)
445
-            ? $temp_options
446
-            : $this->_QST->options(
447
-                $notDeletedOptionsOnly,
448
-                $selected_value_to_always_include
449
-            );
450
-    }
451
-
452
-
453
-    /**
454
-     *    get_meta
455
-     *
456
-     * @access public
457
-     * @param mixed $key
458
-     * @return mixed
459
-     */
460
-    public function get_meta($key = false)
461
-    {
462
-        return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false;
463
-    }
18
+	/**
19
+	 *    EE_Question object
20
+	 *
21
+	 * @access private
22
+	 * @var object
23
+	 */
24
+	private $_QST = null;
25
+
26
+	/**
27
+	 *    EE_Answer object
28
+	 *
29
+	 * @access private
30
+	 * @var object
31
+	 */
32
+	private $_ANS = null;
33
+
34
+	/**
35
+	 *    $_QST_meta
36
+	 * @access private
37
+	 * @var array
38
+	 */
39
+	private $_QST_meta = [];
40
+
41
+	/**
42
+	 *    $QST_input_name
43
+	 * @access private
44
+	 * @var string
45
+	 */
46
+	private $QST_input_name = '';
47
+
48
+	/**
49
+	 *    $QST_input_id
50
+	 * @access private
51
+	 * @var string
52
+	 */
53
+	private $QST_input_id = '';
54
+
55
+	/**
56
+	 *    $QST_input_class
57
+	 * @access private
58
+	 * @var string
59
+	 */
60
+	private $QST_input_class = '';
61
+
62
+	/**
63
+	 * @var bool $QST_disabled
64
+	 */
65
+	private $QST_disabled = false;
66
+
67
+	/**
68
+	 * @var RequestInterface
69
+	 */
70
+	protected $request;
71
+
72
+	/**
73
+	 * @var array
74
+	 */
75
+	protected $form_data;
76
+
77
+
78
+	/**
79
+	 * constructor for questions
80
+	 *
81
+	 * @param EE_Question $QST EE_Question object
82
+	 * @param EE_Answer   $ANS EE_Answer object
83
+	 * @param array       $q_meta
84
+	 * @throws EE_Error
85
+	 * @throws ReflectionException
86
+	 */
87
+	public function __construct(EE_Question $QST = null, EE_Answer $ANS = null, $q_meta = [])
88
+	{
89
+		$this->request   = LoaderFactory::getLoader()->getShared(RequestInterface::class);
90
+		$this->form_data = $this->request->requestParams();
91
+		if (empty($QST) || empty($ANS)) {
92
+			EE_Error::add_error(
93
+				esc_html__('An error occurred. A valid EE_Question or EE_Answer object was not received.', 'event_espresso'),
94
+				__FILE__,
95
+				__FUNCTION__,
96
+				__LINE__
97
+			);
98
+			return null;
99
+		}
100
+		$this->_QST = $QST;
101
+		$this->_ANS = $ANS;
102
+		$this->set_question_form_input_meta($q_meta);
103
+		$this->set_question_form_input_init();
104
+	}
105
+
106
+
107
+	/**
108
+	 * sets meta data for the question form input
109
+	 *
110
+	 * @access public
111
+	 * @param array $q_meta
112
+	 * @return void
113
+	 */
114
+	public function set_question_form_input_meta($q_meta = [])
115
+	{
116
+		$default_q_meta  = [
117
+			'att_nmbr'       => 1,
118
+			'ticket_id'      => '',
119
+			'date'           => '',
120
+			'time'           => '',
121
+			'input_name'     => '',
122
+			'input_id'       => '',
123
+			'input_class'    => '',
124
+			'input_prefix'   => 'qstn',
125
+			'append_qstn_id' => true,
126
+			'htmlentities'   => true,
127
+			'allow_null'     => false,
128
+		];
129
+		$this->_QST_meta = array_merge($default_q_meta, $q_meta);
130
+	}
131
+
132
+
133
+	/**
134
+	 * set_question_form_input_init
135
+	 *
136
+	 * @access public
137
+	 * @return void
138
+	 * @throws EE_Error
139
+	 * @throws ReflectionException
140
+	 */
141
+	public function set_question_form_input_init()
142
+	{
143
+		$qstn_id = $this->_QST->system_ID() ? $this->_QST->system_ID() : $this->_QST->ID();
144
+		$this->_set_input_name($qstn_id);
145
+		$this->_set_input_id($qstn_id);
146
+		$this->_set_input_class();
147
+		$this->set_question_form_input_answer($qstn_id);
148
+	}
149
+
150
+
151
+	/**
152
+	 * set_input_name
153
+	 *
154
+	 * @access private
155
+	 * @param $qstn_id
156
+	 * @return void
157
+	 * @throws EE_Error
158
+	 * @throws ReflectionException
159
+	 */
160
+	private function _set_input_name($qstn_id)
161
+	{
162
+		if (! empty($qstn_id)) {
163
+			$ANS_ID  = $this->get('ANS_ID');
164
+			$qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']';
165
+		}
166
+		$this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
167
+			? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id
168
+			: $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'];
169
+	}
170
+
171
+
172
+	/**
173
+	 * get property values for question form input
174
+	 *
175
+	 * @access public
176
+	 * @param string $property
177
+	 * @return mixed
178
+	 * @throws EE_Error
179
+	 * @throws ReflectionException
180
+	 */
181
+	public function get($property = null)
182
+	{
183
+		if (! empty($property)) {
184
+			if (EEM_Question::instance()->has_field($property)) {
185
+				return $this->_QST->get($property);
186
+			} elseif (EEM_Answer::instance()->has_field($property)) {
187
+				return $this->_ANS->get($property);
188
+			} elseif ($this->_question_form_input_property_exists(__CLASS__, $property)) {
189
+				return $this->{$property};
190
+			}
191
+		}
192
+		return null;
193
+	}
194
+
195
+
196
+	/**
197
+	 *    _question_form_input_property_exists
198
+	 *
199
+	 * @access private
200
+	 * @param string $classname
201
+	 * @param string $property
202
+	 * @return boolean
203
+	 * @throws ReflectionException
204
+	 */
205
+	private function _question_form_input_property_exists($classname, $property)
206
+	{
207
+		// first try regular property exists method which works as expected in PHP 5.3+
208
+		$prop = EEH_Class_Tools::has_property($classname, $property);
209
+		if (! $prop) {
210
+			// use reflection for < PHP 5.3 as a double check when property is not found, possible due to access restriction
211
+			$reflector = new ReflectionClass($classname);
212
+			$prop      = $reflector->hasProperty($property);
213
+		}
214
+		return $prop;
215
+	}
216
+
217
+
218
+	/**
219
+	 * set_input_id
220
+	 *
221
+	 * @access private
222
+	 * @param $qstn_id
223
+	 * @return void
224
+	 * @throws EE_Error
225
+	 * @throws ReflectionException
226
+	 */
227
+	private function _set_input_id($qstn_id)
228
+	{
229
+		$input_id           = isset($this->_QST_meta['input_id']) && ! empty($this->_QST_meta['input_id'])
230
+			? $this->_QST_meta['input_id']
231
+			: sanitize_key(strip_tags($this->_QST->get('QST_display_text')));
232
+		$this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
233
+			? $input_id . '-' . $qstn_id
234
+			: $input_id;
235
+	}
236
+
237
+
238
+	/**
239
+	 * set_input_class
240
+	 *
241
+	 * @access private
242
+	 * @return void
243
+	 */
244
+	private function _set_input_class()
245
+	{
246
+		$this->QST_input_class = isset($this->_QST_meta['input_class']) ? $this->_QST_meta['input_class'] : '';
247
+	}
248
+
249
+
250
+	/**
251
+	 * set_question_form_input_answer
252
+	 *
253
+	 * @access public
254
+	 * @param mixed    int | string    $qstn_id
255
+	 * @return void
256
+	 * @throws EE_Error
257
+	 * @throws ReflectionException
258
+	 */
259
+	public function set_question_form_input_answer($qstn_id)
260
+	{
261
+		// check for answer in $this->form_data in case we are reprocessing a form after an error
262
+		if (
263
+			isset($this->_QST_meta['EVT_ID'])
264
+			&& isset($this->_QST_meta['att_nmbr'])
265
+			&& isset($this->_QST_meta['date'])
266
+			&& isset($this->_QST_meta['time'])
267
+			&& isset($this->_QST_meta['price_id'])
268
+		) {
269
+			$EVT_ID = $this->_QST_meta['EVT_ID'];
270
+			$att_nmbr = $this->_QST_meta['att_nmbr'];
271
+			$date = $this->_QST_meta['date'];
272
+			$time = $this->_QST_meta['time'];
273
+			$price_id = $this->_QST_meta['price_id'];
274
+			if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) {
275
+				$answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ];
276
+				$this->_ANS->set('ANS_value', $answer);
277
+			}
278
+		}
279
+	}
280
+
281
+
282
+	/**
283
+	 *        generate_question_form_inputs_for_object
284
+	 *
285
+	 * @access    protected
286
+	 * @param bool|object $object $object
287
+	 * @param array       $input_types
288
+	 * @return        array
289
+	 * @throws EE_Error
290
+	 * @throws ReflectionException
291
+	 */
292
+	public static function generate_question_form_inputs_for_object($object = false, $input_types = [])
293
+	{
294
+		if (! is_object($object)) {
295
+			return [];
296
+		}
297
+		$inputs = [];
298
+		$fields = $object->get_model()->field_settings(false);
299
+		foreach ($fields as $field_ID => $field) {
300
+			if ($field instanceof EE_Model_Field_Base) {
301
+				if (isset($input_types[ $field_ID ])) {
302
+					// get saved value for field
303
+					$value = $object->get($field_ID);
304
+					// if no saved value, then use default
305
+					$value = $value !== null ? $value : $field->get_default_value();
306
+					// determine question type
307
+					$type = isset($input_types[ $field_ID ]) ? $input_types[ $field_ID ]['type'] : 'TEXT';
308
+					// input name
309
+					$input_name = isset($input_types[ $field_ID ]) && isset($input_types[ $field_ID ]['input_name'])
310
+						? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']'
311
+						: $field_ID;
312
+					// css class for input
313
+					$class = isset($input_types[ $field_ID ]['class']) && ! empty($input_types[ $field_ID ]['class'])
314
+						? ' ' . $input_types[ $field_ID ]['class']
315
+						: '';
316
+					// whether to apply htmlentities to answer
317
+					$htmlentities = isset($input_types[ $field_ID ]['htmlentities'])
318
+						? $input_types[ $field_ID ]['htmlentities']
319
+						: true;
320
+					// whether to apply htmlentities to answer
321
+					$label_b4 = isset($input_types[ $field_ID ]['label_b4'])
322
+						? $input_types[ $field_ID ]['label_b4']
323
+						: false;
324
+					// whether to apply htmlentities to answer
325
+					$use_desc_4_label = isset($input_types[ $field_ID ]['use_desc_4_label'])
326
+						? $input_types[ $field_ID ]['use_desc_4_label']
327
+						: false;
328
+					// whether input is disabled
329
+					$disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled'];
330
+
331
+					// create EE_Question_Form_Input object
332
+					$QFI = new EE_Question_Form_Input(
333
+						EE_Question::new_instance(
334
+							[
335
+								'QST_ID'           => 0,
336
+								'QST_display_text' => $field->get_nicename(),
337
+								'QST_type'         => $type,
338
+							]
339
+						),
340
+						EE_Answer::new_instance(
341
+							[
342
+								'ANS_ID'    => 0,
343
+								'QST_ID'    => 0,
344
+								'REG_ID'    => 0,
345
+								'ANS_value' => $value,
346
+							]
347
+						),
348
+						[
349
+							'input_id'         => $field_ID . '-' . $object->ID(),
350
+							'input_name'       => $input_name,
351
+							'input_class'      => $field_ID . $class,
352
+							'input_prefix'     => '',
353
+							'append_qstn_id'   => false,
354
+							'htmlentities'     => $htmlentities,
355
+							'label_b4'         => $label_b4,
356
+							'use_desc_4_label' => $use_desc_4_label,
357
+						]
358
+					);
359
+					// does question type have options ?
360
+					if (
361
+						in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX'])
362
+						&& isset($input_types[ $field_ID ])
363
+						&& isset($input_types[ $field_ID ]['options'])
364
+					) {
365
+						foreach ($input_types[ $field_ID ]['options'] as $option) {
366
+							$option    = stripslashes_deep($option);
367
+							$option_id = ! empty($option['id']) ? $option['id'] : 0;
368
+							$QSO       = EE_Question_Option::new_instance(
369
+								[
370
+									'QSO_value'   => (string) $option_id,
371
+									'QSO_desc'    => $option['text'],
372
+									'QSO_deleted' => false,
373
+								]
374
+							);
375
+							// all QST (and ANS) properties can be accessed indirectly thru QFI
376
+							$QFI->add_temp_option($QSO);
377
+						}
378
+					}
379
+					// we don't want ppl manually changing primary keys cuz that would just lead to total craziness man
380
+					if ($disabled || $field_ID == $object->get_model()->primary_key_name()) {
381
+						$QFI->set('QST_disabled', true);
382
+					}
383
+					$inputs[ $field_ID ] = $QFI;
384
+				}
385
+			}
386
+		}
387
+		return $inputs;
388
+	}
389
+
390
+
391
+	/**
392
+	 *    add_temp_option
393
+	 *
394
+	 * @access public
395
+	 * @param EE_Question_Option $QSO EE_Question_Option
396
+	 * @return void
397
+	 */
398
+	public function add_temp_option(EE_Question_Option $QSO)
399
+	{
400
+		$this->_QST->add_temp_option($QSO);
401
+	}
402
+
403
+
404
+	/**
405
+	 * set property values for question form input
406
+	 *
407
+	 * @access public
408
+	 * @param string $property
409
+	 * @param mixed  $value
410
+	 * @return void
411
+	 * @throws EE_Error
412
+	 * @throws ReflectionException
413
+	 */
414
+	public function set($property = null, $value = null)
415
+	{
416
+		if (! empty($property)) {
417
+			if (EEM_Question::instance()->has_field($property)) {
418
+				$this->_QST->set($property, $value);
419
+			} elseif (EEM_Answer::instance()->has_field($property)) {
420
+				$this->_ANS->set($property, $value);
421
+			} elseif ($this->_question_form_input_property_exists(__CLASS__, $property)) {
422
+				$this->{$property} = $value;
423
+			}
424
+		}
425
+	}
426
+
427
+
428
+	/**
429
+	 *    _question_form_input_property_exists
430
+	 *
431
+	 * @access public
432
+	 * @param boolean      $notDeletedOptionsOnly            1
433
+	 *                                                       whether to return ALL options, or only the ones which have
434
+	 *                                                       not yet been deleted
435
+	 * @param string|array $selected_value_to_always_include , when retrieving options to an ANSWERED question,
436
+	 *                                                       we want to usually only show non-deleted options AND the
437
+	 *                                                       value that was selected for the answer, whether it was
438
+	 *                                                       trashed or not.
439
+	 * @return EE_Question_Option
440
+	 */
441
+	public function options($notDeletedOptionsOnly = true, $selected_value_to_always_include = null)
442
+	{
443
+		$temp_options = $this->_QST->temp_options();
444
+		return ! empty($temp_options)
445
+			? $temp_options
446
+			: $this->_QST->options(
447
+				$notDeletedOptionsOnly,
448
+				$selected_value_to_always_include
449
+			);
450
+	}
451
+
452
+
453
+	/**
454
+	 *    get_meta
455
+	 *
456
+	 * @access public
457
+	 * @param mixed $key
458
+	 * @return mixed
459
+	 */
460
+	public function get_meta($key = false)
461
+	{
462
+		return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false;
463
+	}
464 464
 }
Please login to merge, or discard this patch.
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/EE_Addon.core.php 2 patches
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -576,7 +576,7 @@  discard block
 block discarded – undo
576 576
      */
577 577
     public function get_activation_indicator_option_name()
578 578
     {
579
-        return 'ee_activation_' . $this->name();
579
+        return 'ee_activation_'.$this->name();
580 580
     }
581 581
 
582 582
 
@@ -663,13 +663,13 @@  discard block
 block discarded – undo
663 663
      */
664 664
     public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
665 665
     {
666
-        if (! $version_history) {
666
+        if ( ! $version_history) {
667 667
             $version_history = $this->get_activation_history();
668 668
         }
669 669
         if ($current_version_to_add === null) {
670 670
             $current_version_to_add = $this->version();
671 671
         }
672
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
672
+        $version_history[$current_version_to_add][] = date('Y-m-d H:i:s', time());
673 673
         // resave
674 674
         return update_option($this->get_activation_history_option_name(), $version_history);
675 675
     }
@@ -682,7 +682,7 @@  discard block
 block discarded – undo
682 682
      */
683 683
     public function get_activation_history_option_name()
684 684
     {
685
-        return self::ee_addon_version_history_option_prefix . $this->name();
685
+        return self::ee_addon_version_history_option_prefix.$this->name();
686 686
     }
687 687
 
688 688
 
@@ -757,7 +757,7 @@  discard block
 block discarded – undo
757 757
         // is admin and not in M-Mode ?
758 758
         if (is_admin() && ! EE_Maintenance_Mode::instance()->level()) {
759 759
             add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
760
-            add_filter('after_plugin_row_' . $this->_plugin_basename, array($this, 'after_plugin_row'), 10, 3);
760
+            add_filter('after_plugin_row_'.$this->_plugin_basename, array($this, 'after_plugin_row'), 10, 3);
761 761
         }
762 762
     }
763 763
 
@@ -776,7 +776,7 @@  discard block
 block discarded – undo
776 776
             // before other links
777 777
             array_unshift(
778 778
                 $links,
779
-                '<a href="admin.php?page=' . $this->plugin_action_slug() . '">'
779
+                '<a href="admin.php?page='.$this->plugin_action_slug().'">'
780 780
                 . esc_html__('Settings', 'event_espresso')
781 781
                 . '</a>'
782 782
             );
@@ -799,15 +799,15 @@  discard block
 block discarded – undo
799 799
     {
800 800
         $after_plugin_row = '';
801 801
         $plugins_page_row = $this->get_plugins_page_row();
802
-        if (! empty($plugins_page_row) && $plugin_file === $this->plugin_basename()) {
802
+        if ( ! empty($plugins_page_row) && $plugin_file === $this->plugin_basename()) {
803 803
             $class = $status ? 'active' : 'inactive';
804 804
             $link_text = isset($plugins_page_row['link_text']) ? $plugins_page_row['link_text'] : '';
805 805
             $link_url = isset($plugins_page_row['link_url']) ? $plugins_page_row['link_url'] : '';
806 806
             $description = isset($plugins_page_row['description'])
807 807
                 ? $plugins_page_row['description']
808 808
                 : '';
809
-            if (! empty($link_text) && ! empty($link_url) && ! empty($description)) {
810
-                $after_plugin_row .= '<tr id="' . sanitize_title($plugin_file) . '-ee-addon" class="' . $class . '">';
809
+            if ( ! empty($link_text) && ! empty($link_url) && ! empty($description)) {
810
+                $after_plugin_row .= '<tr id="'.sanitize_title($plugin_file).'-ee-addon" class="'.$class.'">';
811 811
                 $after_plugin_row .= '<th class="check-column" scope="row"></th>';
812 812
                 $after_plugin_row .= '<td class="ee-addon-upsell-info-title-td plugin-title column-primary">';
813 813
                 $after_plugin_row .= '<style>
@@ -849,7 +849,7 @@  discard block
 block discarded – undo
849 849
 </style>';
850 850
                 $after_plugin_row .= '
851 851
 <p class="ee-addon-upsell-info-dv">
852
-	<a class="ee-button" href="' . $link_url . '">'
852
+	<a class="ee-button" href="' . $link_url.'">'
853 853
                                      . $link_text
854 854
                                      . ' &nbsp;<span class="dashicons dashicons-arrow-right-alt2" style="margin:0;"></span>'
855 855
                                      . '</a>
Please login to merge, or discard this patch.
Indentation   +844 added lines, -844 removed lines patch added patch discarded remove patch
@@ -17,798 +17,798 @@  discard block
 block discarded – undo
17 17
  */
18 18
 abstract class EE_Addon extends EE_Configurable implements RequiresDependencyMapInterface, RequiresDomainInterface
19 19
 {
20
-    /**
21
-     * prefix to be added onto an addon's plugin slug to make a wp option name
22
-     * which will be used to store the plugin's activation history
23
-     */
24
-    const ee_addon_version_history_option_prefix = 'ee_version_history_';
25
-
26
-    /**
27
-     * @var $_version
28
-     * @type string
29
-     */
30
-    protected $_version = '';
31
-
32
-    /**
33
-     * @var $_min_core_version
34
-     * @type string
35
-     */
36
-    protected $_min_core_version = '';
37
-
38
-    /**
39
-     * derived from plugin 'main_file_path using plugin_basename()
40
-     *
41
-     * @type string $_plugin_basename
42
-     */
43
-    protected $_plugin_basename = '';
44
-
45
-    /**
46
-     * A non-internationalized name to identify this addon for use in URLs, etc
47
-     *
48
-     * @type string $_plugin_slug
49
-     */
50
-    protected $_plugin_slug = '';
51
-
52
-    /**
53
-     * A non-internationalized name to identify this addon. Eg 'Calendar','MailChimp',etc/
54
-     *
55
-     * @type string _addon_name
56
-     */
57
-    protected $_addon_name = '';
58
-
59
-    /**
60
-     * one of the EE_System::req_type_* constants
61
-     *
62
-     * @type int $_req_type
63
-     */
64
-    protected $_req_type;
65
-
66
-    /**
67
-     * page slug to be used when generating the "Settings" link on the WP plugin page
68
-     *
69
-     * @type string $_plugin_action_slug
70
-     */
71
-    protected $_plugin_action_slug = '';
72
-
73
-    /**
74
-     * if not empty, inserts a new table row after this plugin's row on the WP Plugins page
75
-     * that can be used for adding upgrading/marketing info
76
-     *
77
-     * @type array $_plugins_page_row
78
-     */
79
-    protected $_plugins_page_row = array();
80
-
81
-
82
-    /**
83
-     *    filepath to the main file, which can be used for register_activation_hook, register_deactivation_hook, etc.
84
-     *
85
-     * @type string
86
-     */
87
-    protected $_main_plugin_file;
88
-
89
-    /**
90
-     *    This is the slug used to identify this add-on within the plugin update engine.
91
-     *
92
-     * @type string
93
-     */
94
-    protected $pue_slug;
95
-
96
-
97
-    /**
98
-     * @var EE_Dependency_Map $dependency_map
99
-     */
100
-    private $dependency_map;
101
-
102
-
103
-    /**
104
-     * @var DomainInterface $domain
105
-     */
106
-    private $domain;
107
-
108
-
109
-    /**
110
-     * @param EE_Dependency_Map $dependency_map [optional]
111
-     * @param DomainInterface   $domain         [optional]
112
-     */
113
-    public function __construct(EE_Dependency_Map $dependency_map = null, DomainInterface $domain = null)
114
-    {
115
-        if ($dependency_map instanceof EE_Dependency_Map) {
116
-            $this->setDependencyMap($dependency_map);
117
-        }
118
-        if ($domain instanceof DomainInterface) {
119
-            $this->setDomain($domain);
120
-        }
121
-        add_action('AHEE__EE_System__load_controllers__load_admin_controllers', array($this, 'admin_init'));
122
-    }
123
-
124
-
125
-    /**
126
-     * @param EE_Dependency_Map $dependency_map
127
-     */
128
-    public function setDependencyMap($dependency_map)
129
-    {
130
-        $this->dependency_map = $dependency_map;
131
-    }
132
-
133
-
134
-    /**
135
-     * @return EE_Dependency_Map
136
-     */
137
-    public function dependencyMap()
138
-    {
139
-        return $this->dependency_map;
140
-    }
141
-
142
-
143
-    /**
144
-     * @param DomainInterface $domain
145
-     */
146
-    public function setDomain(DomainInterface $domain)
147
-    {
148
-        $this->domain = $domain;
149
-    }
150
-
151
-    /**
152
-     * @return DomainInterface
153
-     */
154
-    public function domain()
155
-    {
156
-        return $this->domain;
157
-    }
158
-
159
-
160
-    /**
161
-     * @param mixed $version
162
-     */
163
-    public function set_version($version = null)
164
-    {
165
-        $this->_version = $version;
166
-    }
167
-
168
-
169
-    /**
170
-     * get__version
171
-     *
172
-     * @return string
173
-     */
174
-    public function version()
175
-    {
176
-        return $this->_version;
177
-    }
178
-
179
-
180
-    /**
181
-     * @param mixed $min_core_version
182
-     */
183
-    public function set_min_core_version($min_core_version = null)
184
-    {
185
-        $this->_min_core_version = $min_core_version;
186
-    }
187
-
188
-
189
-    /**
190
-     * get__min_core_version
191
-     *
192
-     * @return string
193
-     */
194
-    public function min_core_version()
195
-    {
196
-        return $this->_min_core_version;
197
-    }
198
-
199
-
200
-    /**
201
-     * Sets addon_name
202
-     *
203
-     * @param string $addon_name
204
-     * @return boolean
205
-     */
206
-    public function set_name($addon_name)
207
-    {
208
-        return $this->_addon_name = $addon_name;
209
-    }
210
-
211
-
212
-    /**
213
-     * Gets addon_name
214
-     *
215
-     * @return string
216
-     */
217
-    public function name()
218
-    {
219
-        return $this->_addon_name;
220
-    }
221
-
222
-
223
-    /**
224
-     * @return string
225
-     */
226
-    public function plugin_basename()
227
-    {
228
-
229
-        return $this->_plugin_basename;
230
-    }
231
-
232
-
233
-    /**
234
-     * @param string $plugin_basename
235
-     */
236
-    public function set_plugin_basename($plugin_basename)
237
-    {
238
-
239
-        $this->_plugin_basename = $plugin_basename;
240
-    }
241
-
242
-
243
-    /**
244
-     * @return string
245
-     */
246
-    public function plugin_slug()
247
-    {
248
-
249
-        return $this->_plugin_slug;
250
-    }
251
-
252
-
253
-    /**
254
-     * @param string $plugin_slug
255
-     */
256
-    public function set_plugin_slug($plugin_slug)
257
-    {
258
-
259
-        $this->_plugin_slug = $plugin_slug;
260
-    }
261
-
262
-
263
-    /**
264
-     * @return string
265
-     */
266
-    public function plugin_action_slug()
267
-    {
268
-
269
-        return $this->_plugin_action_slug;
270
-    }
271
-
272
-
273
-    /**
274
-     * @param string $plugin_action_slug
275
-     */
276
-    public function set_plugin_action_slug($plugin_action_slug)
277
-    {
278
-
279
-        $this->_plugin_action_slug = $plugin_action_slug;
280
-    }
281
-
282
-
283
-    /**
284
-     * @return array
285
-     */
286
-    public function get_plugins_page_row()
287
-    {
288
-
289
-        return $this->_plugins_page_row;
290
-    }
291
-
292
-
293
-    /**
294
-     * @param array $plugins_page_row
295
-     */
296
-    public function set_plugins_page_row($plugins_page_row = array())
297
-    {
298
-        // sigh.... check for example content that I stupidly merged to master and remove it if found
299
-        if (
300
-            ! is_array($plugins_page_row)
301
-            && strpos($plugins_page_row, '<h3>Promotions Addon Upsell Info</h3>') !== false
302
-        ) {
303
-            $plugins_page_row = array();
304
-        }
305
-        $this->_plugins_page_row = (array) $plugins_page_row;
306
-    }
307
-
308
-
309
-    /**
310
-     * Called when EE core detects this addon has been activated for the first time.
311
-     * If the site isn't in maintenance mode, should setup the addon's database
312
-     *
313
-     * @return void
314
-     */
315
-    public function new_install()
316
-    {
317
-        $classname = get_class($this);
318
-        do_action("AHEE__{$classname}__new_install");
319
-        do_action('AHEE__EE_Addon__new_install', $this);
320
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
321
-        add_action(
322
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
323
-            array($this, 'initialize_db_if_no_migrations_required')
324
-        );
325
-    }
326
-
327
-
328
-    /**
329
-     * Called when EE core detects this addon has been reactivated. When this happens,
330
-     * it's good to just check that your data is still intact
331
-     *
332
-     * @return void
333
-     */
334
-    public function reactivation()
335
-    {
336
-        $classname = get_class($this);
337
-        do_action("AHEE__{$classname}__reactivation");
338
-        do_action('AHEE__EE_Addon__reactivation', $this);
339
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
340
-        add_action(
341
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
342
-            array($this, 'initialize_db_if_no_migrations_required')
343
-        );
344
-    }
345
-
346
-
347
-    /**
348
-     * Called when the registered deactivation hook for this addon fires.
349
-     *
350
-     * @throws EE_Error
351
-     */
352
-    public function deactivation()
353
-    {
354
-        $classname = get_class($this);
355
-        do_action("AHEE__{$classname}__deactivation");
356
-        do_action('AHEE__EE_Addon__deactivation', $this);
357
-        // check if the site no longer needs to be in maintenance mode
358
-        EE_Register_Addon::deregister($this->name());
359
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
360
-    }
361
-
362
-
363
-    /**
364
-     * Takes care of double-checking that we're not in maintenance mode, and then
365
-     * initializing this addon's necessary initial data. This is called by default on new activations
366
-     * and reactivations.
367
-     *
368
-     * @param boolean $verify_schema whether to verify the database's schema for this addon, or just its data.
369
-     *                               This is a resource-intensive job so we prefer to only do it when necessary
370
-     * @return void
371
-     * @throws \EE_Error
372
-     * @throws InvalidInterfaceException
373
-     * @throws InvalidDataTypeException
374
-     * @throws InvalidArgumentException
375
-     */
376
-    public function initialize_db_if_no_migrations_required($verify_schema = true)
377
-    {
378
-        if ($verify_schema === '') {
379
-            // wp core bug imo: if no args are passed to `do_action('some_hook_name')` besides the hook's name
380
-            // (ie, no 2nd or 3rd arguments), instead of calling the registered callbacks with no arguments, it
381
-            // calls them with an argument of an empty string (ie ""), which evaluates to false
382
-            // so we need to treat the empty string as if nothing had been passed, and should instead use the default
383
-            $verify_schema = true;
384
-        }
385
-        if (EE_Maintenance_Mode::instance()->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
386
-            if ($verify_schema) {
387
-                $this->initialize_db();
388
-            }
389
-            $this->initialize_default_data();
390
-            // @todo: this will probably need to be adjusted in 4.4 as the array changed formats I believe
391
-            EE_Data_Migration_Manager::instance()->update_current_database_state_to(
392
-                array(
393
-                    'slug'    => $this->name(),
394
-                    'version' => $this->version(),
395
-                )
396
-            );
397
-            /* make sure core's data is a-ok
20
+	/**
21
+	 * prefix to be added onto an addon's plugin slug to make a wp option name
22
+	 * which will be used to store the plugin's activation history
23
+	 */
24
+	const ee_addon_version_history_option_prefix = 'ee_version_history_';
25
+
26
+	/**
27
+	 * @var $_version
28
+	 * @type string
29
+	 */
30
+	protected $_version = '';
31
+
32
+	/**
33
+	 * @var $_min_core_version
34
+	 * @type string
35
+	 */
36
+	protected $_min_core_version = '';
37
+
38
+	/**
39
+	 * derived from plugin 'main_file_path using plugin_basename()
40
+	 *
41
+	 * @type string $_plugin_basename
42
+	 */
43
+	protected $_plugin_basename = '';
44
+
45
+	/**
46
+	 * A non-internationalized name to identify this addon for use in URLs, etc
47
+	 *
48
+	 * @type string $_plugin_slug
49
+	 */
50
+	protected $_plugin_slug = '';
51
+
52
+	/**
53
+	 * A non-internationalized name to identify this addon. Eg 'Calendar','MailChimp',etc/
54
+	 *
55
+	 * @type string _addon_name
56
+	 */
57
+	protected $_addon_name = '';
58
+
59
+	/**
60
+	 * one of the EE_System::req_type_* constants
61
+	 *
62
+	 * @type int $_req_type
63
+	 */
64
+	protected $_req_type;
65
+
66
+	/**
67
+	 * page slug to be used when generating the "Settings" link on the WP plugin page
68
+	 *
69
+	 * @type string $_plugin_action_slug
70
+	 */
71
+	protected $_plugin_action_slug = '';
72
+
73
+	/**
74
+	 * if not empty, inserts a new table row after this plugin's row on the WP Plugins page
75
+	 * that can be used for adding upgrading/marketing info
76
+	 *
77
+	 * @type array $_plugins_page_row
78
+	 */
79
+	protected $_plugins_page_row = array();
80
+
81
+
82
+	/**
83
+	 *    filepath to the main file, which can be used for register_activation_hook, register_deactivation_hook, etc.
84
+	 *
85
+	 * @type string
86
+	 */
87
+	protected $_main_plugin_file;
88
+
89
+	/**
90
+	 *    This is the slug used to identify this add-on within the plugin update engine.
91
+	 *
92
+	 * @type string
93
+	 */
94
+	protected $pue_slug;
95
+
96
+
97
+	/**
98
+	 * @var EE_Dependency_Map $dependency_map
99
+	 */
100
+	private $dependency_map;
101
+
102
+
103
+	/**
104
+	 * @var DomainInterface $domain
105
+	 */
106
+	private $domain;
107
+
108
+
109
+	/**
110
+	 * @param EE_Dependency_Map $dependency_map [optional]
111
+	 * @param DomainInterface   $domain         [optional]
112
+	 */
113
+	public function __construct(EE_Dependency_Map $dependency_map = null, DomainInterface $domain = null)
114
+	{
115
+		if ($dependency_map instanceof EE_Dependency_Map) {
116
+			$this->setDependencyMap($dependency_map);
117
+		}
118
+		if ($domain instanceof DomainInterface) {
119
+			$this->setDomain($domain);
120
+		}
121
+		add_action('AHEE__EE_System__load_controllers__load_admin_controllers', array($this, 'admin_init'));
122
+	}
123
+
124
+
125
+	/**
126
+	 * @param EE_Dependency_Map $dependency_map
127
+	 */
128
+	public function setDependencyMap($dependency_map)
129
+	{
130
+		$this->dependency_map = $dependency_map;
131
+	}
132
+
133
+
134
+	/**
135
+	 * @return EE_Dependency_Map
136
+	 */
137
+	public function dependencyMap()
138
+	{
139
+		return $this->dependency_map;
140
+	}
141
+
142
+
143
+	/**
144
+	 * @param DomainInterface $domain
145
+	 */
146
+	public function setDomain(DomainInterface $domain)
147
+	{
148
+		$this->domain = $domain;
149
+	}
150
+
151
+	/**
152
+	 * @return DomainInterface
153
+	 */
154
+	public function domain()
155
+	{
156
+		return $this->domain;
157
+	}
158
+
159
+
160
+	/**
161
+	 * @param mixed $version
162
+	 */
163
+	public function set_version($version = null)
164
+	{
165
+		$this->_version = $version;
166
+	}
167
+
168
+
169
+	/**
170
+	 * get__version
171
+	 *
172
+	 * @return string
173
+	 */
174
+	public function version()
175
+	{
176
+		return $this->_version;
177
+	}
178
+
179
+
180
+	/**
181
+	 * @param mixed $min_core_version
182
+	 */
183
+	public function set_min_core_version($min_core_version = null)
184
+	{
185
+		$this->_min_core_version = $min_core_version;
186
+	}
187
+
188
+
189
+	/**
190
+	 * get__min_core_version
191
+	 *
192
+	 * @return string
193
+	 */
194
+	public function min_core_version()
195
+	{
196
+		return $this->_min_core_version;
197
+	}
198
+
199
+
200
+	/**
201
+	 * Sets addon_name
202
+	 *
203
+	 * @param string $addon_name
204
+	 * @return boolean
205
+	 */
206
+	public function set_name($addon_name)
207
+	{
208
+		return $this->_addon_name = $addon_name;
209
+	}
210
+
211
+
212
+	/**
213
+	 * Gets addon_name
214
+	 *
215
+	 * @return string
216
+	 */
217
+	public function name()
218
+	{
219
+		return $this->_addon_name;
220
+	}
221
+
222
+
223
+	/**
224
+	 * @return string
225
+	 */
226
+	public function plugin_basename()
227
+	{
228
+
229
+		return $this->_plugin_basename;
230
+	}
231
+
232
+
233
+	/**
234
+	 * @param string $plugin_basename
235
+	 */
236
+	public function set_plugin_basename($plugin_basename)
237
+	{
238
+
239
+		$this->_plugin_basename = $plugin_basename;
240
+	}
241
+
242
+
243
+	/**
244
+	 * @return string
245
+	 */
246
+	public function plugin_slug()
247
+	{
248
+
249
+		return $this->_plugin_slug;
250
+	}
251
+
252
+
253
+	/**
254
+	 * @param string $plugin_slug
255
+	 */
256
+	public function set_plugin_slug($plugin_slug)
257
+	{
258
+
259
+		$this->_plugin_slug = $plugin_slug;
260
+	}
261
+
262
+
263
+	/**
264
+	 * @return string
265
+	 */
266
+	public function plugin_action_slug()
267
+	{
268
+
269
+		return $this->_plugin_action_slug;
270
+	}
271
+
272
+
273
+	/**
274
+	 * @param string $plugin_action_slug
275
+	 */
276
+	public function set_plugin_action_slug($plugin_action_slug)
277
+	{
278
+
279
+		$this->_plugin_action_slug = $plugin_action_slug;
280
+	}
281
+
282
+
283
+	/**
284
+	 * @return array
285
+	 */
286
+	public function get_plugins_page_row()
287
+	{
288
+
289
+		return $this->_plugins_page_row;
290
+	}
291
+
292
+
293
+	/**
294
+	 * @param array $plugins_page_row
295
+	 */
296
+	public function set_plugins_page_row($plugins_page_row = array())
297
+	{
298
+		// sigh.... check for example content that I stupidly merged to master and remove it if found
299
+		if (
300
+			! is_array($plugins_page_row)
301
+			&& strpos($plugins_page_row, '<h3>Promotions Addon Upsell Info</h3>') !== false
302
+		) {
303
+			$plugins_page_row = array();
304
+		}
305
+		$this->_plugins_page_row = (array) $plugins_page_row;
306
+	}
307
+
308
+
309
+	/**
310
+	 * Called when EE core detects this addon has been activated for the first time.
311
+	 * If the site isn't in maintenance mode, should setup the addon's database
312
+	 *
313
+	 * @return void
314
+	 */
315
+	public function new_install()
316
+	{
317
+		$classname = get_class($this);
318
+		do_action("AHEE__{$classname}__new_install");
319
+		do_action('AHEE__EE_Addon__new_install', $this);
320
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
321
+		add_action(
322
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
323
+			array($this, 'initialize_db_if_no_migrations_required')
324
+		);
325
+	}
326
+
327
+
328
+	/**
329
+	 * Called when EE core detects this addon has been reactivated. When this happens,
330
+	 * it's good to just check that your data is still intact
331
+	 *
332
+	 * @return void
333
+	 */
334
+	public function reactivation()
335
+	{
336
+		$classname = get_class($this);
337
+		do_action("AHEE__{$classname}__reactivation");
338
+		do_action('AHEE__EE_Addon__reactivation', $this);
339
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
340
+		add_action(
341
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
342
+			array($this, 'initialize_db_if_no_migrations_required')
343
+		);
344
+	}
345
+
346
+
347
+	/**
348
+	 * Called when the registered deactivation hook for this addon fires.
349
+	 *
350
+	 * @throws EE_Error
351
+	 */
352
+	public function deactivation()
353
+	{
354
+		$classname = get_class($this);
355
+		do_action("AHEE__{$classname}__deactivation");
356
+		do_action('AHEE__EE_Addon__deactivation', $this);
357
+		// check if the site no longer needs to be in maintenance mode
358
+		EE_Register_Addon::deregister($this->name());
359
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
360
+	}
361
+
362
+
363
+	/**
364
+	 * Takes care of double-checking that we're not in maintenance mode, and then
365
+	 * initializing this addon's necessary initial data. This is called by default on new activations
366
+	 * and reactivations.
367
+	 *
368
+	 * @param boolean $verify_schema whether to verify the database's schema for this addon, or just its data.
369
+	 *                               This is a resource-intensive job so we prefer to only do it when necessary
370
+	 * @return void
371
+	 * @throws \EE_Error
372
+	 * @throws InvalidInterfaceException
373
+	 * @throws InvalidDataTypeException
374
+	 * @throws InvalidArgumentException
375
+	 */
376
+	public function initialize_db_if_no_migrations_required($verify_schema = true)
377
+	{
378
+		if ($verify_schema === '') {
379
+			// wp core bug imo: if no args are passed to `do_action('some_hook_name')` besides the hook's name
380
+			// (ie, no 2nd or 3rd arguments), instead of calling the registered callbacks with no arguments, it
381
+			// calls them with an argument of an empty string (ie ""), which evaluates to false
382
+			// so we need to treat the empty string as if nothing had been passed, and should instead use the default
383
+			$verify_schema = true;
384
+		}
385
+		if (EE_Maintenance_Mode::instance()->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
386
+			if ($verify_schema) {
387
+				$this->initialize_db();
388
+			}
389
+			$this->initialize_default_data();
390
+			// @todo: this will probably need to be adjusted in 4.4 as the array changed formats I believe
391
+			EE_Data_Migration_Manager::instance()->update_current_database_state_to(
392
+				array(
393
+					'slug'    => $this->name(),
394
+					'version' => $this->version(),
395
+				)
396
+			);
397
+			/* make sure core's data is a-ok
398 398
              * (at the time of writing, we especially want to verify all the caps are present
399 399
              * because payment method type capabilities are added dynamically, and it's
400 400
              * possible this addon added a payment method. But it's also possible
401 401
              * other data needs to be verified)
402 402
              */
403
-            EEH_Activation::initialize_db_content();
404
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
405
-            $rewrite_rules = LoaderFactory::getLoader()->getShared(
406
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
407
-            );
408
-            $rewrite_rules->flushRewriteRules();
409
-            // in case there are lots of addons being activated at once, let's force garbage collection
410
-            // to help avoid memory limit errors
411
-            // EEH_Debug_Tools::instance()->measure_memory( 'db content initialized for ' . get_class( $this), true );
412
-            gc_collect_cycles();
413
-        } else {
414
-            // ask the data migration manager to init this addon's data
415
-            // when migrations are finished because we can't do it now
416
-            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for($this->name());
417
-        }
418
-    }
419
-
420
-
421
-    /**
422
-     * Used to setup this addon's database tables, but not necessarily any default
423
-     * data in them. The default is to actually use the most up-to-date data migration script
424
-     * for this addon, and just use its schema_changes_before_migration() and schema_changes_after_migration()
425
-     * methods to setup the db.
426
-     */
427
-    public function initialize_db()
428
-    {
429
-        // find the migration script that sets the database to be compatible with the code
430
-        $current_dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms($this->name());
431
-        if ($current_dms_name) {
432
-            $current_data_migration_script = EE_Registry::instance()->load_dms($current_dms_name);
433
-            $current_data_migration_script->set_migrating(false);
434
-            $current_data_migration_script->schema_changes_before_migration();
435
-            $current_data_migration_script->schema_changes_after_migration();
436
-            if ($current_data_migration_script->get_errors()) {
437
-                foreach ($current_data_migration_script->get_errors() as $error) {
438
-                    EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
439
-                }
440
-            }
441
-        }
442
-        // if not DMS was found that should be ok. This addon just doesn't require any database changes
443
-        EE_Data_Migration_Manager::instance()->update_current_database_state_to(
444
-            array(
445
-                'slug'    => $this->name(),
446
-                'version' => $this->version(),
447
-            )
448
-        );
449
-    }
450
-
451
-
452
-    /**
453
-     * If you want to setup default data for the addon, override this method, and call
454
-     * parent::initialize_default_data() from within it. This is normally called
455
-     * from EE_Addon::initialize_db_if_no_migrations_required(), just after EE_Addon::initialize_db()
456
-     * and should verify default data is present (but this is also called
457
-     * on reactivations and just after migrations, so please verify you actually want
458
-     * to ADD default data, because it may already be present).
459
-     * However, please call this parent (currently it just fires a hook which other
460
-     * addons may be depending on)
461
-     */
462
-    public function initialize_default_data()
463
-    {
464
-        /**
465
-         * Called when an addon is ensuring its default data is set (possibly called
466
-         * on a reactivation, so first check for the absence of other data before setting
467
-         * default data)
468
-         *
469
-         * @param EE_Addon $addon the addon that called this
470
-         */
471
-        do_action('AHEE__EE_Addon__initialize_default_data__begin', $this);
472
-        // override to insert default data. It is safe to use the models here
473
-        // because the site should not be in maintenance mode
474
-    }
475
-
476
-
477
-    /**
478
-     * EE Core detected that this addon has been upgraded. We should check if there
479
-     * are any new migration scripts, and if so put the site into maintenance mode until
480
-     * they're ran
481
-     *
482
-     * @return void
483
-     */
484
-    public function upgrade()
485
-    {
486
-        $classname = get_class($this);
487
-        do_action("AHEE__{$classname}__upgrade");
488
-        do_action('AHEE__EE_Addon__upgrade', $this);
489
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
490
-        // also it's possible there is new default data that needs to be added
491
-        add_action(
492
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
493
-            array($this, 'initialize_db_if_no_migrations_required')
494
-        );
495
-    }
496
-
497
-
498
-    /**
499
-     * If Core detects this addon has been downgraded, you may want to invoke some special logic here.
500
-     */
501
-    public function downgrade()
502
-    {
503
-        $classname = get_class($this);
504
-        do_action("AHEE__{$classname}__downgrade");
505
-        do_action('AHEE__EE_Addon__downgrade', $this);
506
-        // it's possible there's old default data that needs to be double-checked
507
-        add_action(
508
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
509
-            array($this, 'initialize_db_if_no_migrations_required')
510
-        );
511
-    }
512
-
513
-
514
-    /**
515
-     * set_db_update_option_name
516
-     * Until we do something better, we'll just check for migration scripts upon
517
-     * plugin activation only. In the future, we'll want to do it on plugin updates too
518
-     *
519
-     * @return bool
520
-     */
521
-    public function set_db_update_option_name()
522
-    {
523
-        EE_Error::doing_it_wrong(
524
-            __FUNCTION__,
525
-            esc_html__(
526
-                'EE_Addon::set_db_update_option_name was renamed to EE_Addon::set_activation_indicator_option',
527
-                'event_espresso'
528
-            ),
529
-            '4.3.0.alpha.016'
530
-        );
531
-        // let's just handle this on the next request, ok? right now we're just not really ready
532
-        return $this->set_activation_indicator_option();
533
-    }
534
-
535
-
536
-    /**
537
-     * Returns the name of the activation indicator option
538
-     * (an option which is set temporarily to indicate that this addon was just activated)
539
-     *
540
-     * @deprecated since version 4.3.0.alpha.016
541
-     * @return string
542
-     */
543
-    public function get_db_update_option_name()
544
-    {
545
-        EE_Error::doing_it_wrong(
546
-            __FUNCTION__,
547
-            esc_html__(
548
-                'EE_Addon::get_db_update_option was renamed to EE_Addon::get_activation_indicator_option_name',
549
-                'event_espresso'
550
-            ),
551
-            '4.3.0.alpha.016'
552
-        );
553
-        return $this->get_activation_indicator_option_name();
554
-    }
555
-
556
-
557
-    /**
558
-     * When the addon is activated, this should be called to set a wordpress option that
559
-     * indicates it was activated. This is especially useful for detecting reactivations.
560
-     *
561
-     * @return bool
562
-     */
563
-    public function set_activation_indicator_option()
564
-    {
565
-        // let's just handle this on the next request, ok? right now we're just not really ready
566
-        return update_option($this->get_activation_indicator_option_name(), true);
567
-    }
568
-
569
-
570
-    /**
571
-     * Gets the name of the wp option which is used to temporarily indicate that this addon was activated
572
-     *
573
-     * @return string
574
-     */
575
-    public function get_activation_indicator_option_name()
576
-    {
577
-        return 'ee_activation_' . $this->name();
578
-    }
579
-
580
-
581
-    /**
582
-     * Used by EE_System to set the request type of this addon. Should not be used by addon developers
583
-     *
584
-     * @param int $req_type
585
-     */
586
-    public function set_req_type($req_type)
587
-    {
588
-        $this->_req_type = $req_type;
589
-    }
590
-
591
-
592
-    /**
593
-     * Returns the request type of this addon (ie, EE_System::req_type_normal, EE_System::req_type_new_activation,
594
-     * EE_System::req_type_reactivation, EE_System::req_type_upgrade, or EE_System::req_type_downgrade). This is set by
595
-     * EE_System when it is checking for new install or upgrades of addons
596
-     */
597
-    public function detect_req_type($redetect = false)
598
-    {
599
-        if ($this->_req_type === null || $redetect) {
600
-            $this->detect_activation_or_upgrade();
601
-        }
602
-        return $this->_req_type;
603
-    }
604
-
605
-
606
-    /**
607
-     * Detects the request type for this addon (whether it was just activated, upgrades, a normal request, etc.)
608
-     * Should only be called once per request
609
-     *
610
-     * @return void
611
-     */
612
-    public function detect_activation_or_upgrade()
613
-    {
614
-        $activation_history_for_addon = $this->get_activation_history();
615
-        $request_type = EE_System::detect_req_type_given_activation_history(
616
-            $activation_history_for_addon,
617
-            $this->get_activation_indicator_option_name(),
618
-            $this->version()
619
-        );
620
-        $this->set_req_type($request_type);
621
-        $classname = get_class($this);
622
-        switch ($request_type) {
623
-            case EE_System::req_type_new_activation:
624
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__new_activation");
625
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__new_activation', $this);
626
-                $this->new_install();
627
-                $this->update_list_of_installed_versions($activation_history_for_addon);
628
-                break;
629
-            case EE_System::req_type_reactivation:
630
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__reactivation");
631
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__reactivation', $this);
632
-                $this->reactivation();
633
-                $this->update_list_of_installed_versions($activation_history_for_addon);
634
-                break;
635
-            case EE_System::req_type_upgrade:
636
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__upgrade");
637
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__upgrade', $this);
638
-                $this->upgrade();
639
-                $this->update_list_of_installed_versions($activation_history_for_addon);
640
-                break;
641
-            case EE_System::req_type_downgrade:
642
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__downgrade");
643
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__downgrade', $this);
644
-                $this->downgrade();
645
-                $this->update_list_of_installed_versions($activation_history_for_addon);
646
-                break;
647
-            case EE_System::req_type_normal:
648
-            default:
649
-                break;
650
-        }
651
-
652
-        do_action("AHEE__{$classname}__detect_if_activation_or_upgrade__complete");
653
-    }
654
-
655
-    /**
656
-     * Updates the version history for this addon
657
-     *
658
-     * @param array  $version_history
659
-     * @param string $current_version_to_add
660
-     * @return boolean success
661
-     */
662
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
663
-    {
664
-        if (! $version_history) {
665
-            $version_history = $this->get_activation_history();
666
-        }
667
-        if ($current_version_to_add === null) {
668
-            $current_version_to_add = $this->version();
669
-        }
670
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
671
-        // resave
672
-        return update_option($this->get_activation_history_option_name(), $version_history);
673
-    }
674
-
675
-    /**
676
-     * Gets the name of the wp option that stores the activation history
677
-     * of this addon
678
-     *
679
-     * @return string
680
-     */
681
-    public function get_activation_history_option_name()
682
-    {
683
-        return self::ee_addon_version_history_option_prefix . $this->name();
684
-    }
685
-
686
-
687
-    /**
688
-     * Gets the wp option which stores the activation history for this addon
689
-     *
690
-     * @return array
691
-     */
692
-    public function get_activation_history()
693
-    {
694
-        return get_option($this->get_activation_history_option_name(), null);
695
-    }
696
-
697
-
698
-    /**
699
-     * @param string $config_section
700
-     */
701
-    public function set_config_section($config_section = '')
702
-    {
703
-        $this->_config_section = ! empty($config_section) ? $config_section : 'addons';
704
-    }
705
-
706
-    /**
707
-     * Sets the filepath to the main plugin file
708
-     *
709
-     * @param string $filepath
710
-     */
711
-    public function set_main_plugin_file($filepath)
712
-    {
713
-        $this->_main_plugin_file = $filepath;
714
-    }
715
-
716
-    /**
717
-     * gets the filepath to teh main file
718
-     *
719
-     * @return string
720
-     */
721
-    public function get_main_plugin_file()
722
-    {
723
-        return $this->_main_plugin_file;
724
-    }
725
-
726
-    /**
727
-     * Gets the filename (no path) of the main file (the main file loaded
728
-     * by WP)
729
-     *
730
-     * @return string
731
-     */
732
-    public function get_main_plugin_file_basename()
733
-    {
734
-        return plugin_basename($this->get_main_plugin_file());
735
-    }
736
-
737
-    /**
738
-     * Gets the folder name which contains the main plugin file
739
-     *
740
-     * @return string
741
-     */
742
-    public function get_main_plugin_file_dirname()
743
-    {
744
-        return dirname($this->get_main_plugin_file());
745
-    }
746
-
747
-
748
-    /**
749
-     * sets hooks used in the admin
750
-     *
751
-     * @return void
752
-     */
753
-    public function admin_init()
754
-    {
755
-        // is admin and not in M-Mode ?
756
-        if (is_admin() && ! EE_Maintenance_Mode::instance()->level()) {
757
-            add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
758
-            add_filter('after_plugin_row_' . $this->_plugin_basename, array($this, 'after_plugin_row'), 10, 3);
759
-        }
760
-    }
761
-
762
-
763
-    /**
764
-     * plugin_actions
765
-     * Add a settings link to the Plugins page, so people can go straight from the plugin page to the settings page.
766
-     *
767
-     * @param $links
768
-     * @param $file
769
-     * @return array
770
-     */
771
-    public function plugin_action_links($links, $file)
772
-    {
773
-        if ($file === $this->plugin_basename() && $this->plugin_action_slug() !== '') {
774
-            // before other links
775
-            array_unshift(
776
-                $links,
777
-                '<a href="admin.php?page=' . $this->plugin_action_slug() . '">'
778
-                . esc_html__('Settings', 'event_espresso')
779
-                . '</a>'
780
-            );
781
-        }
782
-        return $links;
783
-    }
784
-
785
-
786
-    /**
787
-     * after_plugin_row
788
-     * Add additional content to the plugins page plugin row
789
-     * Inserts another row
790
-     *
791
-     * @param $plugin_file
792
-     * @param $plugin_data
793
-     * @param $status
794
-     * @return void
795
-     */
796
-    public function after_plugin_row($plugin_file, $plugin_data, $status)
797
-    {
798
-        $after_plugin_row = '';
799
-        $plugins_page_row = $this->get_plugins_page_row();
800
-        if (! empty($plugins_page_row) && $plugin_file === $this->plugin_basename()) {
801
-            $class = $status ? 'active' : 'inactive';
802
-            $link_text = isset($plugins_page_row['link_text']) ? $plugins_page_row['link_text'] : '';
803
-            $link_url = isset($plugins_page_row['link_url']) ? $plugins_page_row['link_url'] : '';
804
-            $description = isset($plugins_page_row['description'])
805
-                ? $plugins_page_row['description']
806
-                : '';
807
-            if (! empty($link_text) && ! empty($link_url) && ! empty($description)) {
808
-                $after_plugin_row .= '<tr id="' . sanitize_title($plugin_file) . '-ee-addon" class="' . $class . '">';
809
-                $after_plugin_row .= '<th class="check-column" scope="row"></th>';
810
-                $after_plugin_row .= '<td class="ee-addon-upsell-info-title-td plugin-title column-primary">';
811
-                $after_plugin_row .= '<style>
403
+			EEH_Activation::initialize_db_content();
404
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
405
+			$rewrite_rules = LoaderFactory::getLoader()->getShared(
406
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
407
+			);
408
+			$rewrite_rules->flushRewriteRules();
409
+			// in case there are lots of addons being activated at once, let's force garbage collection
410
+			// to help avoid memory limit errors
411
+			// EEH_Debug_Tools::instance()->measure_memory( 'db content initialized for ' . get_class( $this), true );
412
+			gc_collect_cycles();
413
+		} else {
414
+			// ask the data migration manager to init this addon's data
415
+			// when migrations are finished because we can't do it now
416
+			EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for($this->name());
417
+		}
418
+	}
419
+
420
+
421
+	/**
422
+	 * Used to setup this addon's database tables, but not necessarily any default
423
+	 * data in them. The default is to actually use the most up-to-date data migration script
424
+	 * for this addon, and just use its schema_changes_before_migration() and schema_changes_after_migration()
425
+	 * methods to setup the db.
426
+	 */
427
+	public function initialize_db()
428
+	{
429
+		// find the migration script that sets the database to be compatible with the code
430
+		$current_dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms($this->name());
431
+		if ($current_dms_name) {
432
+			$current_data_migration_script = EE_Registry::instance()->load_dms($current_dms_name);
433
+			$current_data_migration_script->set_migrating(false);
434
+			$current_data_migration_script->schema_changes_before_migration();
435
+			$current_data_migration_script->schema_changes_after_migration();
436
+			if ($current_data_migration_script->get_errors()) {
437
+				foreach ($current_data_migration_script->get_errors() as $error) {
438
+					EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
439
+				}
440
+			}
441
+		}
442
+		// if not DMS was found that should be ok. This addon just doesn't require any database changes
443
+		EE_Data_Migration_Manager::instance()->update_current_database_state_to(
444
+			array(
445
+				'slug'    => $this->name(),
446
+				'version' => $this->version(),
447
+			)
448
+		);
449
+	}
450
+
451
+
452
+	/**
453
+	 * If you want to setup default data for the addon, override this method, and call
454
+	 * parent::initialize_default_data() from within it. This is normally called
455
+	 * from EE_Addon::initialize_db_if_no_migrations_required(), just after EE_Addon::initialize_db()
456
+	 * and should verify default data is present (but this is also called
457
+	 * on reactivations and just after migrations, so please verify you actually want
458
+	 * to ADD default data, because it may already be present).
459
+	 * However, please call this parent (currently it just fires a hook which other
460
+	 * addons may be depending on)
461
+	 */
462
+	public function initialize_default_data()
463
+	{
464
+		/**
465
+		 * Called when an addon is ensuring its default data is set (possibly called
466
+		 * on a reactivation, so first check for the absence of other data before setting
467
+		 * default data)
468
+		 *
469
+		 * @param EE_Addon $addon the addon that called this
470
+		 */
471
+		do_action('AHEE__EE_Addon__initialize_default_data__begin', $this);
472
+		// override to insert default data. It is safe to use the models here
473
+		// because the site should not be in maintenance mode
474
+	}
475
+
476
+
477
+	/**
478
+	 * EE Core detected that this addon has been upgraded. We should check if there
479
+	 * are any new migration scripts, and if so put the site into maintenance mode until
480
+	 * they're ran
481
+	 *
482
+	 * @return void
483
+	 */
484
+	public function upgrade()
485
+	{
486
+		$classname = get_class($this);
487
+		do_action("AHEE__{$classname}__upgrade");
488
+		do_action('AHEE__EE_Addon__upgrade', $this);
489
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
490
+		// also it's possible there is new default data that needs to be added
491
+		add_action(
492
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
493
+			array($this, 'initialize_db_if_no_migrations_required')
494
+		);
495
+	}
496
+
497
+
498
+	/**
499
+	 * If Core detects this addon has been downgraded, you may want to invoke some special logic here.
500
+	 */
501
+	public function downgrade()
502
+	{
503
+		$classname = get_class($this);
504
+		do_action("AHEE__{$classname}__downgrade");
505
+		do_action('AHEE__EE_Addon__downgrade', $this);
506
+		// it's possible there's old default data that needs to be double-checked
507
+		add_action(
508
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
509
+			array($this, 'initialize_db_if_no_migrations_required')
510
+		);
511
+	}
512
+
513
+
514
+	/**
515
+	 * set_db_update_option_name
516
+	 * Until we do something better, we'll just check for migration scripts upon
517
+	 * plugin activation only. In the future, we'll want to do it on plugin updates too
518
+	 *
519
+	 * @return bool
520
+	 */
521
+	public function set_db_update_option_name()
522
+	{
523
+		EE_Error::doing_it_wrong(
524
+			__FUNCTION__,
525
+			esc_html__(
526
+				'EE_Addon::set_db_update_option_name was renamed to EE_Addon::set_activation_indicator_option',
527
+				'event_espresso'
528
+			),
529
+			'4.3.0.alpha.016'
530
+		);
531
+		// let's just handle this on the next request, ok? right now we're just not really ready
532
+		return $this->set_activation_indicator_option();
533
+	}
534
+
535
+
536
+	/**
537
+	 * Returns the name of the activation indicator option
538
+	 * (an option which is set temporarily to indicate that this addon was just activated)
539
+	 *
540
+	 * @deprecated since version 4.3.0.alpha.016
541
+	 * @return string
542
+	 */
543
+	public function get_db_update_option_name()
544
+	{
545
+		EE_Error::doing_it_wrong(
546
+			__FUNCTION__,
547
+			esc_html__(
548
+				'EE_Addon::get_db_update_option was renamed to EE_Addon::get_activation_indicator_option_name',
549
+				'event_espresso'
550
+			),
551
+			'4.3.0.alpha.016'
552
+		);
553
+		return $this->get_activation_indicator_option_name();
554
+	}
555
+
556
+
557
+	/**
558
+	 * When the addon is activated, this should be called to set a wordpress option that
559
+	 * indicates it was activated. This is especially useful for detecting reactivations.
560
+	 *
561
+	 * @return bool
562
+	 */
563
+	public function set_activation_indicator_option()
564
+	{
565
+		// let's just handle this on the next request, ok? right now we're just not really ready
566
+		return update_option($this->get_activation_indicator_option_name(), true);
567
+	}
568
+
569
+
570
+	/**
571
+	 * Gets the name of the wp option which is used to temporarily indicate that this addon was activated
572
+	 *
573
+	 * @return string
574
+	 */
575
+	public function get_activation_indicator_option_name()
576
+	{
577
+		return 'ee_activation_' . $this->name();
578
+	}
579
+
580
+
581
+	/**
582
+	 * Used by EE_System to set the request type of this addon. Should not be used by addon developers
583
+	 *
584
+	 * @param int $req_type
585
+	 */
586
+	public function set_req_type($req_type)
587
+	{
588
+		$this->_req_type = $req_type;
589
+	}
590
+
591
+
592
+	/**
593
+	 * Returns the request type of this addon (ie, EE_System::req_type_normal, EE_System::req_type_new_activation,
594
+	 * EE_System::req_type_reactivation, EE_System::req_type_upgrade, or EE_System::req_type_downgrade). This is set by
595
+	 * EE_System when it is checking for new install or upgrades of addons
596
+	 */
597
+	public function detect_req_type($redetect = false)
598
+	{
599
+		if ($this->_req_type === null || $redetect) {
600
+			$this->detect_activation_or_upgrade();
601
+		}
602
+		return $this->_req_type;
603
+	}
604
+
605
+
606
+	/**
607
+	 * Detects the request type for this addon (whether it was just activated, upgrades, a normal request, etc.)
608
+	 * Should only be called once per request
609
+	 *
610
+	 * @return void
611
+	 */
612
+	public function detect_activation_or_upgrade()
613
+	{
614
+		$activation_history_for_addon = $this->get_activation_history();
615
+		$request_type = EE_System::detect_req_type_given_activation_history(
616
+			$activation_history_for_addon,
617
+			$this->get_activation_indicator_option_name(),
618
+			$this->version()
619
+		);
620
+		$this->set_req_type($request_type);
621
+		$classname = get_class($this);
622
+		switch ($request_type) {
623
+			case EE_System::req_type_new_activation:
624
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__new_activation");
625
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__new_activation', $this);
626
+				$this->new_install();
627
+				$this->update_list_of_installed_versions($activation_history_for_addon);
628
+				break;
629
+			case EE_System::req_type_reactivation:
630
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__reactivation");
631
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__reactivation', $this);
632
+				$this->reactivation();
633
+				$this->update_list_of_installed_versions($activation_history_for_addon);
634
+				break;
635
+			case EE_System::req_type_upgrade:
636
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__upgrade");
637
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__upgrade', $this);
638
+				$this->upgrade();
639
+				$this->update_list_of_installed_versions($activation_history_for_addon);
640
+				break;
641
+			case EE_System::req_type_downgrade:
642
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__downgrade");
643
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__downgrade', $this);
644
+				$this->downgrade();
645
+				$this->update_list_of_installed_versions($activation_history_for_addon);
646
+				break;
647
+			case EE_System::req_type_normal:
648
+			default:
649
+				break;
650
+		}
651
+
652
+		do_action("AHEE__{$classname}__detect_if_activation_or_upgrade__complete");
653
+	}
654
+
655
+	/**
656
+	 * Updates the version history for this addon
657
+	 *
658
+	 * @param array  $version_history
659
+	 * @param string $current_version_to_add
660
+	 * @return boolean success
661
+	 */
662
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
663
+	{
664
+		if (! $version_history) {
665
+			$version_history = $this->get_activation_history();
666
+		}
667
+		if ($current_version_to_add === null) {
668
+			$current_version_to_add = $this->version();
669
+		}
670
+		$version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
671
+		// resave
672
+		return update_option($this->get_activation_history_option_name(), $version_history);
673
+	}
674
+
675
+	/**
676
+	 * Gets the name of the wp option that stores the activation history
677
+	 * of this addon
678
+	 *
679
+	 * @return string
680
+	 */
681
+	public function get_activation_history_option_name()
682
+	{
683
+		return self::ee_addon_version_history_option_prefix . $this->name();
684
+	}
685
+
686
+
687
+	/**
688
+	 * Gets the wp option which stores the activation history for this addon
689
+	 *
690
+	 * @return array
691
+	 */
692
+	public function get_activation_history()
693
+	{
694
+		return get_option($this->get_activation_history_option_name(), null);
695
+	}
696
+
697
+
698
+	/**
699
+	 * @param string $config_section
700
+	 */
701
+	public function set_config_section($config_section = '')
702
+	{
703
+		$this->_config_section = ! empty($config_section) ? $config_section : 'addons';
704
+	}
705
+
706
+	/**
707
+	 * Sets the filepath to the main plugin file
708
+	 *
709
+	 * @param string $filepath
710
+	 */
711
+	public function set_main_plugin_file($filepath)
712
+	{
713
+		$this->_main_plugin_file = $filepath;
714
+	}
715
+
716
+	/**
717
+	 * gets the filepath to teh main file
718
+	 *
719
+	 * @return string
720
+	 */
721
+	public function get_main_plugin_file()
722
+	{
723
+		return $this->_main_plugin_file;
724
+	}
725
+
726
+	/**
727
+	 * Gets the filename (no path) of the main file (the main file loaded
728
+	 * by WP)
729
+	 *
730
+	 * @return string
731
+	 */
732
+	public function get_main_plugin_file_basename()
733
+	{
734
+		return plugin_basename($this->get_main_plugin_file());
735
+	}
736
+
737
+	/**
738
+	 * Gets the folder name which contains the main plugin file
739
+	 *
740
+	 * @return string
741
+	 */
742
+	public function get_main_plugin_file_dirname()
743
+	{
744
+		return dirname($this->get_main_plugin_file());
745
+	}
746
+
747
+
748
+	/**
749
+	 * sets hooks used in the admin
750
+	 *
751
+	 * @return void
752
+	 */
753
+	public function admin_init()
754
+	{
755
+		// is admin and not in M-Mode ?
756
+		if (is_admin() && ! EE_Maintenance_Mode::instance()->level()) {
757
+			add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
758
+			add_filter('after_plugin_row_' . $this->_plugin_basename, array($this, 'after_plugin_row'), 10, 3);
759
+		}
760
+	}
761
+
762
+
763
+	/**
764
+	 * plugin_actions
765
+	 * Add a settings link to the Plugins page, so people can go straight from the plugin page to the settings page.
766
+	 *
767
+	 * @param $links
768
+	 * @param $file
769
+	 * @return array
770
+	 */
771
+	public function plugin_action_links($links, $file)
772
+	{
773
+		if ($file === $this->plugin_basename() && $this->plugin_action_slug() !== '') {
774
+			// before other links
775
+			array_unshift(
776
+				$links,
777
+				'<a href="admin.php?page=' . $this->plugin_action_slug() . '">'
778
+				. esc_html__('Settings', 'event_espresso')
779
+				. '</a>'
780
+			);
781
+		}
782
+		return $links;
783
+	}
784
+
785
+
786
+	/**
787
+	 * after_plugin_row
788
+	 * Add additional content to the plugins page plugin row
789
+	 * Inserts another row
790
+	 *
791
+	 * @param $plugin_file
792
+	 * @param $plugin_data
793
+	 * @param $status
794
+	 * @return void
795
+	 */
796
+	public function after_plugin_row($plugin_file, $plugin_data, $status)
797
+	{
798
+		$after_plugin_row = '';
799
+		$plugins_page_row = $this->get_plugins_page_row();
800
+		if (! empty($plugins_page_row) && $plugin_file === $this->plugin_basename()) {
801
+			$class = $status ? 'active' : 'inactive';
802
+			$link_text = isset($plugins_page_row['link_text']) ? $plugins_page_row['link_text'] : '';
803
+			$link_url = isset($plugins_page_row['link_url']) ? $plugins_page_row['link_url'] : '';
804
+			$description = isset($plugins_page_row['description'])
805
+				? $plugins_page_row['description']
806
+				: '';
807
+			if (! empty($link_text) && ! empty($link_url) && ! empty($description)) {
808
+				$after_plugin_row .= '<tr id="' . sanitize_title($plugin_file) . '-ee-addon" class="' . $class . '">';
809
+				$after_plugin_row .= '<th class="check-column" scope="row"></th>';
810
+				$after_plugin_row .= '<td class="ee-addon-upsell-info-title-td plugin-title column-primary">';
811
+				$after_plugin_row .= '<style>
812 812
 .ee-button,
813 813
 .ee-button:active,
814 814
 .ee-button:visited {
@@ -845,64 +845,64 @@  discard block
 block discarded – undo
845 845
 }
846 846
 .ee-button:active { top:0; }
847 847
 </style>';
848
-                $after_plugin_row .= '
848
+				$after_plugin_row .= '
849 849
 <p class="ee-addon-upsell-info-dv">
850 850
 	<a class="ee-button" href="' . $link_url . '">'
851
-                                     . $link_text
852
-                                     . ' &nbsp;<span class="dashicons dashicons-arrow-right-alt2" style="margin:0;"></span>'
853
-                                     . '</a>
851
+									 . $link_text
852
+									 . ' &nbsp;<span class="dashicons dashicons-arrow-right-alt2" style="margin:0;"></span>'
853
+									 . '</a>
854 854
 </p>';
855
-                $after_plugin_row .= '</td>';
856
-                $after_plugin_row .= '<td class="ee-addon-upsell-info-desc-td column-description desc">';
857
-                $after_plugin_row .= $description;
858
-                $after_plugin_row .= '</td>';
859
-                $after_plugin_row .= '</tr>';
860
-            } else {
861
-                $after_plugin_row .= $description;
862
-            }
863
-        }
864
-
865
-        echo $after_plugin_row;
866
-    }
867
-
868
-
869
-    /**
870
-     * A safe space for addons to add additional logic like setting hooks that need to be set early in the request.
871
-     * Child classes that have logic like that to run can override this method declaration.  This was not made abstract
872
-     * for back compat reasons.
873
-     *
874
-     * This will fire on the `AHEE__EE_System__load_espresso_addons__complete` hook at priority 999.
875
-     *
876
-     * It is recommended, if client code is `de-registering` an add-on, then do it on the
877
-     * `AHEE__EE_System__load_espresso_addons__complete` hook before priority 999 so as to ensure any code logic in this
878
-     * callback does not get run/set in that request.
879
-     *
880
-     * Also, keep in mind that if a registered add-on happens to be deactivated via
881
-     * EE_System::_deactivate_incompatible_addons() because its incompatible, any code executed in this method
882
-     * (including setting hooks etc) will have executed before the plugin was deactivated.  If you use
883
-     * `after_registration` to set any filter and/or action hooks and want to ensure they are removed on this add-on's
884
-     * deactivation, you can override `EE_Addon::deactivation` and unset your hooks and filters there.  Just remember
885
-     * to call `parent::deactivation`.
886
-     *
887
-     * @since 4.9.26
888
-     */
889
-    public function after_registration()
890
-    {
891
-        // cricket chirp... cricket chirp...
892
-    }
893
-
894
-    /**
895
-     * @return string
896
-     */
897
-    public function getPueSlug()
898
-    {
899
-        return $this->pue_slug;
900
-    }
901
-    /**
902
-     * @param string $pue_slug
903
-     */
904
-    public function setPueSlug($pue_slug)
905
-    {
906
-        $this->pue_slug = $pue_slug;
907
-    }
855
+				$after_plugin_row .= '</td>';
856
+				$after_plugin_row .= '<td class="ee-addon-upsell-info-desc-td column-description desc">';
857
+				$after_plugin_row .= $description;
858
+				$after_plugin_row .= '</td>';
859
+				$after_plugin_row .= '</tr>';
860
+			} else {
861
+				$after_plugin_row .= $description;
862
+			}
863
+		}
864
+
865
+		echo $after_plugin_row;
866
+	}
867
+
868
+
869
+	/**
870
+	 * A safe space for addons to add additional logic like setting hooks that need to be set early in the request.
871
+	 * Child classes that have logic like that to run can override this method declaration.  This was not made abstract
872
+	 * for back compat reasons.
873
+	 *
874
+	 * This will fire on the `AHEE__EE_System__load_espresso_addons__complete` hook at priority 999.
875
+	 *
876
+	 * It is recommended, if client code is `de-registering` an add-on, then do it on the
877
+	 * `AHEE__EE_System__load_espresso_addons__complete` hook before priority 999 so as to ensure any code logic in this
878
+	 * callback does not get run/set in that request.
879
+	 *
880
+	 * Also, keep in mind that if a registered add-on happens to be deactivated via
881
+	 * EE_System::_deactivate_incompatible_addons() because its incompatible, any code executed in this method
882
+	 * (including setting hooks etc) will have executed before the plugin was deactivated.  If you use
883
+	 * `after_registration` to set any filter and/or action hooks and want to ensure they are removed on this add-on's
884
+	 * deactivation, you can override `EE_Addon::deactivation` and unset your hooks and filters there.  Just remember
885
+	 * to call `parent::deactivation`.
886
+	 *
887
+	 * @since 4.9.26
888
+	 */
889
+	public function after_registration()
890
+	{
891
+		// cricket chirp... cricket chirp...
892
+	}
893
+
894
+	/**
895
+	 * @return string
896
+	 */
897
+	public function getPueSlug()
898
+	{
899
+		return $this->pue_slug;
900
+	}
901
+	/**
902
+	 * @param string $pue_slug
903
+	 */
904
+	public function setPueSlug($pue_slug)
905
+	{
906
+		$this->pue_slug = $pue_slug;
907
+	}
908 908
 }
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.