Completed
Pull Request — master (#881)
by
unknown
09:50
created
core/db_classes/EE_Event.class.php 2 patches
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -71,7 +71,7 @@  discard block
 block discarded – undo
71 71
      */
72 72
     public function getAvailableSpacesCalculator()
73 73
     {
74
-        if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
74
+        if ( ! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
75 75
             $this->available_spaces_calculator = new EventSpacesCalculator($this);
76 76
         }
77 77
         return $this->available_spaces_calculator;
@@ -213,7 +213,7 @@  discard block
 block discarded – undo
213 213
      */
214 214
     public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
215 215
     {
216
-        if (! empty($this->_Primary_Datetime)) {
216
+        if ( ! empty($this->_Primary_Datetime)) {
217 217
             return $this->_Primary_Datetime;
218 218
         }
219 219
         $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
     {
237 237
         // first get all datetimes
238 238
         $datetimes = $this->datetimes_ordered();
239
-        if (! $datetimes) {
239
+        if ( ! $datetimes) {
240 240
             return array();
241 241
         }
242 242
         $datetime_ids = array();
@@ -429,7 +429,7 @@  discard block
 block discarded – undo
429 429
     public function short_description($num_words = 55, $more = null, $not_full_desc = false)
430 430
     {
431 431
         $short_desc = $this->get('EVT_short_desc');
432
-        if (! empty($short_desc) || $not_full_desc) {
432
+        if ( ! empty($short_desc) || $not_full_desc) {
433 433
             return $short_desc;
434 434
         }
435 435
         $full_desc = $this->get('EVT_desc');
@@ -883,7 +883,7 @@  discard block
 block discarded – undo
883 883
         );
884 884
         $all_expired = true;
885 885
         foreach ($tickets as $ticket) {
886
-            if (! $ticket->is_expired()) {
886
+            if ( ! $ticket->is_expired()) {
887 887
                 $all_expired = false;
888 888
                 break;
889 889
             }
@@ -972,7 +972,7 @@  discard block
 block discarded – undo
972 972
      */
973 973
     public function is_sold_out($actual = false)
974 974
     {
975
-        if (! $actual) {
975
+        if ( ! $actual) {
976 976
             return $this->status() === EEM_Event::sold_out;
977 977
         }
978 978
         return $this->perform_sold_out_status_check();
@@ -1017,11 +1017,11 @@  discard block
 block discarded – undo
1017 1017
     public function get_active_status($reset = false)
1018 1018
     {
1019 1019
         // if the active status has already been set, then just use that value (unless we are resetting it)
1020
-        if (! empty($this->_active_status) && ! $reset) {
1020
+        if ( ! empty($this->_active_status) && ! $reset) {
1021 1021
             return $this->_active_status;
1022 1022
         }
1023 1023
         // first check if event id is present on this object
1024
-        if (! $this->ID()) {
1024
+        if ( ! $this->ID()) {
1025 1025
             return false;
1026 1026
         }
1027 1027
         $where_params_for_event = array(array('EVT_ID' => $this->ID()));
@@ -1106,7 +1106,7 @@  discard block
 block discarded – undo
1106 1106
     public function get_number_of_tickets_sold()
1107 1107
     {
1108 1108
         $tkt_sold = 0;
1109
-        if (! $this->ID()) {
1109
+        if ( ! $this->ID()) {
1110 1110
             return 0;
1111 1111
         }
1112 1112
         $datetimes = $this->datetimes();
@@ -1290,7 +1290,7 @@  discard block
 block discarded – undo
1290 1290
             ]
1291 1291
         );
1292 1292
         $field_to_update = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1293
-        $other_field = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1293
+        $other_field = EEM_Event_Question_Group::instance()->fieldNameForContext( ! $for_primary);
1294 1294
         if ($existing_relation->get($other_field) === false) {
1295 1295
             // Delete it. It's now no longer for primary or additional question groups.
1296 1296
             return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
Please login to merge, or discard this patch.
Indentation   +1384 added lines, -1384 removed lines patch added patch discarded remove patch
@@ -15,1388 +15,1388 @@
 block discarded – undo
15 15
 class EE_Event extends EE_CPT_Base implements EEI_Line_Item_Object, EEI_Admin_Links, EEI_Has_Icon, EEI_Event
16 16
 {
17 17
 
18
-    /**
19
-     * cached value for the the logical active status for the event
20
-     *
21
-     * @see get_active_status()
22
-     * @var string
23
-     */
24
-    protected $_active_status = '';
25
-
26
-    /**
27
-     * This is just used for caching the Primary Datetime for the Event on initial retrieval
28
-     *
29
-     * @var EE_Datetime
30
-     */
31
-    protected $_Primary_Datetime;
32
-
33
-    /**
34
-     * @var EventSpacesCalculator $available_spaces_calculator
35
-     */
36
-    protected $available_spaces_calculator;
37
-
38
-
39
-    /**
40
-     * @param array  $props_n_values          incoming values
41
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
42
-     *                                        used.)
43
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
44
-     *                                        date_format and the second value is the time format
45
-     * @return EE_Event
46
-     * @throws EE_Error
47
-     */
48
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
49
-    {
50
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
51
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
52
-    }
53
-
54
-
55
-    /**
56
-     * @param array  $props_n_values  incoming values from the database
57
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
-     *                                the website will be used.
59
-     * @return EE_Event
60
-     * @throws EE_Error
61
-     */
62
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
63
-    {
64
-        return new self($props_n_values, true, $timezone);
65
-    }
66
-
67
-
68
-    /**
69
-     * @return EventSpacesCalculator
70
-     * @throws \EE_Error
71
-     */
72
-    public function getAvailableSpacesCalculator()
73
-    {
74
-        if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
75
-            $this->available_spaces_calculator = new EventSpacesCalculator($this);
76
-        }
77
-        return $this->available_spaces_calculator;
78
-    }
79
-
80
-
81
-    /**
82
-     * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
83
-     *
84
-     * @param string $field_name
85
-     * @param mixed  $field_value
86
-     * @param bool   $use_default
87
-     * @throws EE_Error
88
-     */
89
-    public function set($field_name, $field_value, $use_default = false)
90
-    {
91
-        switch ($field_name) {
92
-            case 'status':
93
-                $this->set_status($field_value, $use_default);
94
-                break;
95
-            default:
96
-                parent::set($field_name, $field_value, $use_default);
97
-        }
98
-    }
99
-
100
-
101
-    /**
102
-     *    set_status
103
-     * Checks if event status is being changed to SOLD OUT
104
-     * and updates event meta data with previous event status
105
-     * so that we can revert things if/when the event is no longer sold out
106
-     *
107
-     * @access public
108
-     * @param string $new_status
109
-     * @param bool   $use_default
110
-     * @return void
111
-     * @throws EE_Error
112
-     */
113
-    public function set_status($new_status = null, $use_default = false)
114
-    {
115
-        // if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
116
-        if (empty($new_status) && ! $use_default) {
117
-            return;
118
-        }
119
-        // get current Event status
120
-        $old_status = $this->status();
121
-        // if status has changed
122
-        if ($old_status !== $new_status) {
123
-            // TO sold_out
124
-            if ($new_status === EEM_Event::sold_out) {
125
-                // save the previous event status so that we can revert if the event is no longer sold out
126
-                $this->add_post_meta('_previous_event_status', $old_status);
127
-                do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $new_status);
128
-                // OR FROM  sold_out
129
-            } elseif ($old_status === EEM_Event::sold_out) {
130
-                $this->delete_post_meta('_previous_event_status');
131
-                do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $new_status);
132
-            }
133
-            // clear out the active status so that it gets reset the next time it is requested
134
-            $this->_active_status = null;
135
-            // update status
136
-            parent::set('status', $new_status, $use_default);
137
-            do_action('AHEE__EE_Event__set_status__after_update', $this);
138
-            return;
139
-        }
140
-        // even though the old value matches the new value, it's still good to
141
-        // allow the parent set method to have a say
142
-        parent::set('status', $new_status, $use_default);
143
-    }
144
-
145
-
146
-    /**
147
-     * Gets all the datetimes for this event
148
-     *
149
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
150
-     * @return EE_Base_Class[]|EE_Datetime[]
151
-     * @throws EE_Error
152
-     */
153
-    public function datetimes($query_params = array())
154
-    {
155
-        return $this->get_many_related('Datetime', $query_params);
156
-    }
157
-
158
-
159
-    /**
160
-     * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
161
-     *
162
-     * @return EE_Base_Class[]|EE_Datetime[]
163
-     * @throws EE_Error
164
-     */
165
-    public function datetimes_in_chronological_order()
166
-    {
167
-        return $this->get_many_related('Datetime', array('order_by' => array('DTT_EVT_start' => 'ASC')));
168
-    }
169
-
170
-
171
-    /**
172
-     * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
173
-     * @darren, we should probably UNSET timezone on the EEM_Datetime model
174
-     * after running our query, so that this timezone isn't set for EVERY query
175
-     * on EEM_Datetime for the rest of the request, no?
176
-     *
177
-     * @param boolean $show_expired whether or not to include expired events
178
-     * @param boolean $show_deleted whether or not to include deleted events
179
-     * @param null    $limit
180
-     * @return EE_Datetime[]
181
-     * @throws EE_Error
182
-     */
183
-    public function datetimes_ordered($show_expired = true, $show_deleted = false, $limit = null)
184
-    {
185
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
186
-            $this->ID(),
187
-            $show_expired,
188
-            $show_deleted,
189
-            $limit
190
-        );
191
-    }
192
-
193
-
194
-    /**
195
-     * Returns one related datetime. Mostly only used by some legacy code.
196
-     *
197
-     * @return EE_Base_Class|EE_Datetime
198
-     * @throws EE_Error
199
-     */
200
-    public function first_datetime()
201
-    {
202
-        return $this->get_first_related('Datetime');
203
-    }
204
-
205
-
206
-    /**
207
-     * Returns the 'primary' datetime for the event
208
-     *
209
-     * @param bool $try_to_exclude_expired
210
-     * @param bool $try_to_exclude_deleted
211
-     * @return EE_Datetime
212
-     * @throws EE_Error
213
-     */
214
-    public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
215
-    {
216
-        if (! empty($this->_Primary_Datetime)) {
217
-            return $this->_Primary_Datetime;
218
-        }
219
-        $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
220
-            $this->ID(),
221
-            $try_to_exclude_expired,
222
-            $try_to_exclude_deleted
223
-        );
224
-        return $this->_Primary_Datetime;
225
-    }
226
-
227
-
228
-    /**
229
-     * Gets all the tickets available for purchase of this event
230
-     *
231
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
232
-     * @return EE_Base_Class[]|EE_Ticket[]
233
-     * @throws EE_Error
234
-     */
235
-    public function tickets($query_params = array())
236
-    {
237
-        // first get all datetimes
238
-        $datetimes = $this->datetimes_ordered();
239
-        if (! $datetimes) {
240
-            return array();
241
-        }
242
-        $datetime_ids = array();
243
-        foreach ($datetimes as $datetime) {
244
-            $datetime_ids[] = $datetime->ID();
245
-        }
246
-        $where_params = array('Datetime.DTT_ID' => array('IN', $datetime_ids));
247
-        // if incoming $query_params has where conditions let's merge but not override existing.
248
-        if (is_array($query_params) && isset($query_params[0])) {
249
-            $where_params = array_merge($query_params[0], $where_params);
250
-            unset($query_params[0]);
251
-        }
252
-        // now add $where_params to $query_params
253
-        $query_params[0] = $where_params;
254
-        return EEM_Ticket::instance()->get_all($query_params);
255
-    }
256
-
257
-
258
-    /**
259
-     * get all unexpired untrashed tickets
260
-     *
261
-     * @return EE_Ticket[]
262
-     * @throws EE_Error
263
-     */
264
-    public function active_tickets()
265
-    {
266
-        return $this->tickets(
267
-            array(
268
-                array(
269
-                    'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
270
-                    'TKT_deleted'  => false,
271
-                ),
272
-            )
273
-        );
274
-    }
275
-
276
-
277
-    /**
278
-     * @return bool
279
-     * @throws EE_Error
280
-     */
281
-    public function additional_limit()
282
-    {
283
-        return $this->get('EVT_additional_limit');
284
-    }
285
-
286
-
287
-    /**
288
-     * @return bool
289
-     * @throws EE_Error
290
-     */
291
-    public function allow_overflow()
292
-    {
293
-        return $this->get('EVT_allow_overflow');
294
-    }
295
-
296
-
297
-    /**
298
-     * @return bool
299
-     * @throws EE_Error
300
-     */
301
-    public function created()
302
-    {
303
-        return $this->get('EVT_created');
304
-    }
305
-
306
-
307
-    /**
308
-     * @return bool
309
-     * @throws EE_Error
310
-     */
311
-    public function description()
312
-    {
313
-        return $this->get('EVT_desc');
314
-    }
315
-
316
-
317
-    /**
318
-     * Runs do_shortcode and wpautop on the description
319
-     *
320
-     * @return string of html
321
-     * @throws EE_Error
322
-     */
323
-    public function description_filtered()
324
-    {
325
-        return $this->get_pretty('EVT_desc');
326
-    }
327
-
328
-
329
-    /**
330
-     * @return bool
331
-     * @throws EE_Error
332
-     */
333
-    public function display_description()
334
-    {
335
-        return $this->get('EVT_display_desc');
336
-    }
337
-
338
-
339
-    /**
340
-     * @return bool
341
-     * @throws EE_Error
342
-     */
343
-    public function display_ticket_selector()
344
-    {
345
-        return (bool) $this->get('EVT_display_ticket_selector');
346
-    }
347
-
348
-
349
-    /**
350
-     * @return bool
351
-     * @throws EE_Error
352
-     */
353
-    public function external_url()
354
-    {
355
-        return $this->get('EVT_external_URL');
356
-    }
357
-
358
-
359
-    /**
360
-     * @return bool
361
-     * @throws EE_Error
362
-     */
363
-    public function member_only()
364
-    {
365
-        return $this->get('EVT_member_only');
366
-    }
367
-
368
-
369
-    /**
370
-     * @return bool
371
-     * @throws EE_Error
372
-     */
373
-    public function phone()
374
-    {
375
-        return $this->get('EVT_phone');
376
-    }
377
-
378
-
379
-    /**
380
-     * @return bool
381
-     * @throws EE_Error
382
-     */
383
-    public function modified()
384
-    {
385
-        return $this->get('EVT_modified');
386
-    }
387
-
388
-
389
-    /**
390
-     * @return bool
391
-     * @throws EE_Error
392
-     */
393
-    public function name()
394
-    {
395
-        return $this->get('EVT_name');
396
-    }
397
-
398
-
399
-    /**
400
-     * @return bool
401
-     * @throws EE_Error
402
-     */
403
-    public function order()
404
-    {
405
-        return $this->get('EVT_order');
406
-    }
407
-
408
-
409
-    /**
410
-     * @return bool|string
411
-     * @throws EE_Error
412
-     */
413
-    public function default_registration_status()
414
-    {
415
-        $event_default_registration_status = $this->get('EVT_default_registration_status');
416
-        return ! empty($event_default_registration_status)
417
-            ? $event_default_registration_status
418
-            : EE_Registry::instance()->CFG->registration->default_STS_ID;
419
-    }
420
-
421
-
422
-    /**
423
-     * @param int  $num_words
424
-     * @param null $more
425
-     * @param bool $not_full_desc
426
-     * @return bool|string
427
-     * @throws EE_Error
428
-     */
429
-    public function short_description($num_words = 55, $more = null, $not_full_desc = false)
430
-    {
431
-        $short_desc = $this->get('EVT_short_desc');
432
-        if (! empty($short_desc) || $not_full_desc) {
433
-            return $short_desc;
434
-        }
435
-        $full_desc = $this->get('EVT_desc');
436
-        return wp_trim_words($full_desc, $num_words, $more);
437
-    }
438
-
439
-
440
-    /**
441
-     * @return bool
442
-     * @throws EE_Error
443
-     */
444
-    public function slug()
445
-    {
446
-        return $this->get('EVT_slug');
447
-    }
448
-
449
-
450
-    /**
451
-     * @return bool
452
-     * @throws EE_Error
453
-     */
454
-    public function timezone_string()
455
-    {
456
-        return $this->get('EVT_timezone_string');
457
-    }
458
-
459
-
460
-    /**
461
-     * @return bool
462
-     * @throws EE_Error
463
-     */
464
-    public function visible_on()
465
-    {
466
-        return $this->get('EVT_visible_on');
467
-    }
468
-
469
-
470
-    /**
471
-     * @return int
472
-     * @throws EE_Error
473
-     */
474
-    public function wp_user()
475
-    {
476
-        return $this->get('EVT_wp_user');
477
-    }
478
-
479
-
480
-    /**
481
-     * @return bool
482
-     * @throws EE_Error
483
-     */
484
-    public function donations()
485
-    {
486
-        return $this->get('EVT_donations');
487
-    }
488
-
489
-
490
-    /**
491
-     * @param $limit
492
-     * @throws EE_Error
493
-     */
494
-    public function set_additional_limit($limit)
495
-    {
496
-        $this->set('EVT_additional_limit', $limit);
497
-    }
498
-
499
-
500
-    /**
501
-     * @param $created
502
-     * @throws EE_Error
503
-     */
504
-    public function set_created($created)
505
-    {
506
-        $this->set('EVT_created', $created);
507
-    }
508
-
509
-
510
-    /**
511
-     * @param $desc
512
-     * @throws EE_Error
513
-     */
514
-    public function set_description($desc)
515
-    {
516
-        $this->set('EVT_desc', $desc);
517
-    }
518
-
519
-
520
-    /**
521
-     * @param $display_desc
522
-     * @throws EE_Error
523
-     */
524
-    public function set_display_description($display_desc)
525
-    {
526
-        $this->set('EVT_display_desc', $display_desc);
527
-    }
528
-
529
-
530
-    /**
531
-     * @param $display_ticket_selector
532
-     * @throws EE_Error
533
-     */
534
-    public function set_display_ticket_selector($display_ticket_selector)
535
-    {
536
-        $this->set('EVT_display_ticket_selector', $display_ticket_selector);
537
-    }
538
-
539
-
540
-    /**
541
-     * @param $external_url
542
-     * @throws EE_Error
543
-     */
544
-    public function set_external_url($external_url)
545
-    {
546
-        $this->set('EVT_external_URL', $external_url);
547
-    }
548
-
549
-
550
-    /**
551
-     * @param $member_only
552
-     * @throws EE_Error
553
-     */
554
-    public function set_member_only($member_only)
555
-    {
556
-        $this->set('EVT_member_only', $member_only);
557
-    }
558
-
559
-
560
-    /**
561
-     * @param $event_phone
562
-     * @throws EE_Error
563
-     */
564
-    public function set_event_phone($event_phone)
565
-    {
566
-        $this->set('EVT_phone', $event_phone);
567
-    }
568
-
569
-
570
-    /**
571
-     * @param $modified
572
-     * @throws EE_Error
573
-     */
574
-    public function set_modified($modified)
575
-    {
576
-        $this->set('EVT_modified', $modified);
577
-    }
578
-
579
-
580
-    /**
581
-     * @param $name
582
-     * @throws EE_Error
583
-     */
584
-    public function set_name($name)
585
-    {
586
-        $this->set('EVT_name', $name);
587
-    }
588
-
589
-
590
-    /**
591
-     * @param $order
592
-     * @throws EE_Error
593
-     */
594
-    public function set_order($order)
595
-    {
596
-        $this->set('EVT_order', $order);
597
-    }
598
-
599
-
600
-    /**
601
-     * @param $short_desc
602
-     * @throws EE_Error
603
-     */
604
-    public function set_short_description($short_desc)
605
-    {
606
-        $this->set('EVT_short_desc', $short_desc);
607
-    }
608
-
609
-
610
-    /**
611
-     * @param $slug
612
-     * @throws EE_Error
613
-     */
614
-    public function set_slug($slug)
615
-    {
616
-        $this->set('EVT_slug', $slug);
617
-    }
618
-
619
-
620
-    /**
621
-     * @param $timezone_string
622
-     * @throws EE_Error
623
-     */
624
-    public function set_timezone_string($timezone_string)
625
-    {
626
-        $this->set('EVT_timezone_string', $timezone_string);
627
-    }
628
-
629
-
630
-    /**
631
-     * @param $visible_on
632
-     * @throws EE_Error
633
-     */
634
-    public function set_visible_on($visible_on)
635
-    {
636
-        $this->set('EVT_visible_on', $visible_on);
637
-    }
638
-
639
-
640
-    /**
641
-     * @param $wp_user
642
-     * @throws EE_Error
643
-     */
644
-    public function set_wp_user($wp_user)
645
-    {
646
-        $this->set('EVT_wp_user', $wp_user);
647
-    }
648
-
649
-
650
-    /**
651
-     * @param $default_registration_status
652
-     * @throws EE_Error
653
-     */
654
-    public function set_default_registration_status($default_registration_status)
655
-    {
656
-        $this->set('EVT_default_registration_status', $default_registration_status);
657
-    }
658
-
659
-
660
-    /**
661
-     * @param $donations
662
-     * @throws EE_Error
663
-     */
664
-    public function set_donations($donations)
665
-    {
666
-        $this->set('EVT_donations', $donations);
667
-    }
668
-
669
-
670
-    /**
671
-     * Adds a venue to this event
672
-     *
673
-     * @param EE_Venue /int $venue_id_or_obj
674
-     * @return EE_Base_Class|EE_Venue
675
-     * @throws EE_Error
676
-     */
677
-    public function add_venue($venue_id_or_obj)
678
-    {
679
-        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
680
-    }
681
-
682
-
683
-    /**
684
-     * Removes a venue from the event
685
-     *
686
-     * @param EE_Venue /int $venue_id_or_obj
687
-     * @return EE_Base_Class|EE_Venue
688
-     * @throws EE_Error
689
-     */
690
-    public function remove_venue($venue_id_or_obj)
691
-    {
692
-        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
693
-    }
694
-
695
-
696
-    /**
697
-     * Gets all the venues related ot the event. May provide additional $query_params if desired
698
-     *
699
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
700
-     * @return EE_Base_Class[]|EE_Venue[]
701
-     * @throws EE_Error
702
-     */
703
-    public function venues($query_params = array())
704
-    {
705
-        return $this->get_many_related('Venue', $query_params);
706
-    }
707
-
708
-
709
-    /**
710
-     * check if event id is present and if event is published
711
-     *
712
-     * @access public
713
-     * @return boolean true yes, false no
714
-     * @throws EE_Error
715
-     */
716
-    private function _has_ID_and_is_published()
717
-    {
718
-        // first check if event id is present and not NULL,
719
-        // then check if this event is published (or any of the equivalent "published" statuses)
720
-        return
721
-            $this->ID() && $this->ID() !== null
722
-            && (
723
-                $this->status() === 'publish'
724
-                || $this->status() === EEM_Event::sold_out
725
-                || $this->status() === EEM_Event::postponed
726
-                || $this->status() === EEM_Event::cancelled
727
-            );
728
-    }
729
-
730
-
731
-    /**
732
-     * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
733
-     *
734
-     * @access public
735
-     * @return boolean true yes, false no
736
-     * @throws EE_Error
737
-     */
738
-    public function is_upcoming()
739
-    {
740
-        // check if event id is present and if this event is published
741
-        if ($this->is_inactive()) {
742
-            return false;
743
-        }
744
-        // set initial value
745
-        $upcoming = false;
746
-        // next let's get all datetimes and loop through them
747
-        $datetimes = $this->datetimes_in_chronological_order();
748
-        foreach ($datetimes as $datetime) {
749
-            if ($datetime instanceof EE_Datetime) {
750
-                // if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
751
-                if ($datetime->is_expired()) {
752
-                    continue;
753
-                }
754
-                // if this dtt is active then we return false.
755
-                if ($datetime->is_active()) {
756
-                    return false;
757
-                }
758
-                // otherwise let's check upcoming status
759
-                $upcoming = $datetime->is_upcoming();
760
-            }
761
-        }
762
-        return $upcoming;
763
-    }
764
-
765
-
766
-    /**
767
-     * @return bool
768
-     * @throws EE_Error
769
-     */
770
-    public function is_active()
771
-    {
772
-        // check if event id is present and if this event is published
773
-        if ($this->is_inactive()) {
774
-            return false;
775
-        }
776
-        // set initial value
777
-        $active = false;
778
-        // next let's get all datetimes and loop through them
779
-        $datetimes = $this->datetimes_in_chronological_order();
780
-        foreach ($datetimes as $datetime) {
781
-            if ($datetime instanceof EE_Datetime) {
782
-                // if this dtt is expired then we continue cause one of the other datetimes might be active.
783
-                if ($datetime->is_expired()) {
784
-                    continue;
785
-                }
786
-                // if this dtt is upcoming then we return false.
787
-                if ($datetime->is_upcoming()) {
788
-                    return false;
789
-                }
790
-                // otherwise let's check active status
791
-                $active = $datetime->is_active();
792
-            }
793
-        }
794
-        return $active;
795
-    }
796
-
797
-
798
-    /**
799
-     * @return bool
800
-     * @throws EE_Error
801
-     */
802
-    public function is_expired()
803
-    {
804
-        // check if event id is present and if this event is published
805
-        if ($this->is_inactive()) {
806
-            return false;
807
-        }
808
-        // set initial value
809
-        $expired = false;
810
-        // first let's get all datetimes and loop through them
811
-        $datetimes = $this->datetimes_in_chronological_order();
812
-        foreach ($datetimes as $datetime) {
813
-            if ($datetime instanceof EE_Datetime) {
814
-                // if this dtt is upcoming or active then we return false.
815
-                if ($datetime->is_upcoming() || $datetime->is_active()) {
816
-                    return false;
817
-                }
818
-                // otherwise let's check active status
819
-                $expired = $datetime->is_expired();
820
-            }
821
-        }
822
-        return $expired;
823
-    }
824
-
825
-
826
-    /**
827
-     * @return bool
828
-     * @throws EE_Error
829
-     */
830
-    public function is_inactive()
831
-    {
832
-        // check if event id is present and if this event is published
833
-        if ($this->_has_ID_and_is_published()) {
834
-            return false;
835
-        }
836
-        return true;
837
-    }
838
-
839
-
840
-    /**
841
-     * calculate spaces remaining based on "saleable" tickets
842
-     *
843
-     * @param array $tickets
844
-     * @param bool  $filtered
845
-     * @return int|float
846
-     * @throws EE_Error
847
-     * @throws DomainException
848
-     * @throws UnexpectedEntityException
849
-     */
850
-    public function spaces_remaining($tickets = array(), $filtered = true)
851
-    {
852
-        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
853
-        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
854
-        return $filtered
855
-            ? apply_filters(
856
-                'FHEE_EE_Event__spaces_remaining',
857
-                $spaces_remaining,
858
-                $this,
859
-                $tickets
860
-            )
861
-            : $spaces_remaining;
862
-    }
863
-
864
-
865
-    /**
866
-     *    perform_sold_out_status_check
867
-     *    checks all of this events's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
868
-     *    available... if NOT, then the event status will get toggled to 'sold_out'
869
-     *
870
-     * @return bool    return the ACTUAL sold out state.
871
-     * @throws EE_Error
872
-     * @throws DomainException
873
-     * @throws UnexpectedEntityException
874
-     */
875
-    public function perform_sold_out_status_check()
876
-    {
877
-        // get all unexpired untrashed tickets
878
-        $tickets = $this->tickets(
879
-            array(
880
-                array('TKT_deleted' => false),
881
-                'order_by' => array('TKT_qty' => 'ASC'),
882
-            )
883
-        );
884
-        $all_expired = true;
885
-        foreach ($tickets as $ticket) {
886
-            if (! $ticket->is_expired()) {
887
-                $all_expired = false;
888
-                break;
889
-            }
890
-        }
891
-        // if all the tickets are just expired, then don't update the event status to sold out
892
-        if ($all_expired) {
893
-            return true;
894
-        }
895
-        $spaces_remaining = $this->spaces_remaining($tickets);
896
-        if ($spaces_remaining < 1) {
897
-            if ($this->status() !== EEM_Event::post_status_private) {
898
-                $this->set_status(EEM_Event::sold_out);
899
-                $this->save();
900
-            }
901
-            $sold_out = true;
902
-        } else {
903
-            $sold_out = false;
904
-            // was event previously marked as sold out ?
905
-            if ($this->status() === EEM_Event::sold_out) {
906
-                // revert status to previous value, if it was set
907
-                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
908
-                if ($previous_event_status) {
909
-                    $this->set_status($previous_event_status);
910
-                    $this->save();
911
-                }
912
-            }
913
-        }
914
-        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
915
-        return $sold_out;
916
-    }
917
-
918
-
919
-    /**
920
-     * This returns the total remaining spaces for sale on this event.
921
-     *
922
-     * @uses EE_Event::total_available_spaces()
923
-     * @return float|int
924
-     * @throws EE_Error
925
-     * @throws DomainException
926
-     * @throws UnexpectedEntityException
927
-     */
928
-    public function spaces_remaining_for_sale()
929
-    {
930
-        return $this->total_available_spaces(true);
931
-    }
932
-
933
-
934
-    /**
935
-     * This returns the total spaces available for an event
936
-     * while considering all the qtys on the tickets and the reg limits
937
-     * on the datetimes attached to this event.
938
-     *
939
-     * @param   bool $consider_sold Whether to consider any tickets that have already sold in our calculation.
940
-     *                              If this is false, then we return the most tickets that could ever be sold
941
-     *                              for this event with the datetime and tickets setup on the event under optimal
942
-     *                              selling conditions.  Otherwise we return a live calculation of spaces available
943
-     *                              based on tickets sold.  Depending on setup and stage of sales, this
944
-     *                              may appear to equal remaining tickets.  However, the more tickets are
945
-     *                              sold out, the more accurate the "live" total is.
946
-     * @return float|int
947
-     * @throws EE_Error
948
-     * @throws DomainException
949
-     * @throws UnexpectedEntityException
950
-     */
951
-    public function total_available_spaces($consider_sold = false)
952
-    {
953
-        $spaces_available = $consider_sold
954
-            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
955
-            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
956
-        return apply_filters(
957
-            'FHEE_EE_Event__total_available_spaces__spaces_available',
958
-            $spaces_available,
959
-            $this,
960
-            $this->getAvailableSpacesCalculator()->getDatetimes(),
961
-            $this->getAvailableSpacesCalculator()->getActiveTickets()
962
-        );
963
-    }
964
-
965
-
966
-    /**
967
-     * Checks if the event is set to sold out
968
-     *
969
-     * @param  bool $actual whether or not to perform calculations to not only figure the
970
-     *                      actual status but also to flip the status if necessary to sold
971
-     *                      out If false, we just check the existing status of the event
972
-     * @return boolean
973
-     * @throws EE_Error
974
-     */
975
-    public function is_sold_out($actual = false)
976
-    {
977
-        if (! $actual) {
978
-            return $this->status() === EEM_Event::sold_out;
979
-        }
980
-        return $this->perform_sold_out_status_check();
981
-    }
982
-
983
-
984
-    /**
985
-     * Checks if the event is marked as postponed
986
-     *
987
-     * @return boolean
988
-     */
989
-    public function is_postponed()
990
-    {
991
-        return $this->status() === EEM_Event::postponed;
992
-    }
993
-
994
-
995
-    /**
996
-     * Checks if the event is marked as cancelled
997
-     *
998
-     * @return boolean
999
-     */
1000
-    public function is_cancelled()
1001
-    {
1002
-        return $this->status() === EEM_Event::cancelled;
1003
-    }
1004
-
1005
-
1006
-    /**
1007
-     * Get the logical active status in a hierarchical order for all the datetimes.  Note
1008
-     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1009
-     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1010
-     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1011
-     * the event is considered expired.
1012
-     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1013
-     * status set on the EVENT when it is not published and thus is done
1014
-     *
1015
-     * @param bool $reset
1016
-     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1017
-     * @throws EE_Error
1018
-     */
1019
-    public function get_active_status($reset = false)
1020
-    {
1021
-        // if the active status has already been set, then just use that value (unless we are resetting it)
1022
-        if (! empty($this->_active_status) && ! $reset) {
1023
-            return $this->_active_status;
1024
-        }
1025
-        // first check if event id is present on this object
1026
-        if (! $this->ID()) {
1027
-            return false;
1028
-        }
1029
-        $where_params_for_event = array(array('EVT_ID' => $this->ID()));
1030
-        // if event is published:
1031
-        if ($this->status() === EEM_Event::post_status_publish || $this->status() === EEM_Event::post_status_private) {
1032
-            // active?
1033
-            if (EEM_Datetime::instance()->get_datetime_count_for_status(
1034
-                EE_Datetime::active,
1035
-                $where_params_for_event
1036
-            ) > 0) {
1037
-                $this->_active_status = EE_Datetime::active;
1038
-            } else {
1039
-                // upcoming?
1040
-                if (EEM_Datetime::instance()->get_datetime_count_for_status(
1041
-                    EE_Datetime::upcoming,
1042
-                    $where_params_for_event
1043
-                ) > 0) {
1044
-                    $this->_active_status = EE_Datetime::upcoming;
1045
-                } else {
1046
-                    // expired?
1047
-                    if (EEM_Datetime::instance()->get_datetime_count_for_status(
1048
-                        EE_Datetime::expired,
1049
-                        $where_params_for_event
1050
-                    ) > 0
1051
-                    ) {
1052
-                        $this->_active_status = EE_Datetime::expired;
1053
-                    } else {
1054
-                        // it would be odd if things make it this far because it basically means there are no datetime's
1055
-                        // attached to the event.  So in this case it will just be considered inactive.
1056
-                        $this->_active_status = EE_Datetime::inactive;
1057
-                    }
1058
-                }
1059
-            }
1060
-        } else {
1061
-            // the event is not published, so let's just set it's active status according to its' post status
1062
-            switch ($this->status()) {
1063
-                case EEM_Event::sold_out:
1064
-                    $this->_active_status = EE_Datetime::sold_out;
1065
-                    break;
1066
-                case EEM_Event::cancelled:
1067
-                    $this->_active_status = EE_Datetime::cancelled;
1068
-                    break;
1069
-                case EEM_Event::postponed:
1070
-                    $this->_active_status = EE_Datetime::postponed;
1071
-                    break;
1072
-                default:
1073
-                    $this->_active_status = EE_Datetime::inactive;
1074
-            }
1075
-        }
1076
-        return $this->_active_status;
1077
-    }
1078
-
1079
-
1080
-    /**
1081
-     *    pretty_active_status
1082
-     *
1083
-     * @access public
1084
-     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1085
-     * @return mixed void|string
1086
-     * @throws EE_Error
1087
-     */
1088
-    public function pretty_active_status($echo = true)
1089
-    {
1090
-        $active_status = $this->get_active_status();
1091
-        $status = '<span class="ee-status event-active-status-'
1092
-                  . $active_status
1093
-                  . '">'
1094
-                  . EEH_Template::pretty_status($active_status, false, 'sentence')
1095
-                  . '</span>';
1096
-        if ($echo) {
1097
-            echo $status;
1098
-            return '';
1099
-        }
1100
-        return $status;
1101
-    }
1102
-
1103
-
1104
-    /**
1105
-     * @return bool|int
1106
-     * @throws EE_Error
1107
-     */
1108
-    public function get_number_of_tickets_sold()
1109
-    {
1110
-        $tkt_sold = 0;
1111
-        if (! $this->ID()) {
1112
-            return 0;
1113
-        }
1114
-        $datetimes = $this->datetimes();
1115
-        foreach ($datetimes as $datetime) {
1116
-            if ($datetime instanceof EE_Datetime) {
1117
-                $tkt_sold += $datetime->sold();
1118
-            }
1119
-        }
1120
-        return $tkt_sold;
1121
-    }
1122
-
1123
-
1124
-    /**
1125
-     * This just returns a count of all the registrations for this event
1126
-     *
1127
-     * @access  public
1128
-     * @return int
1129
-     * @throws EE_Error
1130
-     */
1131
-    public function get_count_of_all_registrations()
1132
-    {
1133
-        return EEM_Event::instance()->count_related($this, 'Registration');
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * This returns the ticket with the earliest start time that is
1139
-     * available for this event (across all datetimes attached to the event)
1140
-     *
1141
-     * @return EE_Base_Class|EE_Ticket|null
1142
-     * @throws EE_Error
1143
-     */
1144
-    public function get_ticket_with_earliest_start_time()
1145
-    {
1146
-        $where['Datetime.EVT_ID'] = $this->ID();
1147
-        $query_params = array($where, 'order_by' => array('TKT_start_date' => 'ASC'));
1148
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1149
-    }
1150
-
1151
-
1152
-    /**
1153
-     * This returns the ticket with the latest end time that is available
1154
-     * for this event (across all datetimes attached to the event)
1155
-     *
1156
-     * @return EE_Base_Class|EE_Ticket|null
1157
-     * @throws EE_Error
1158
-     */
1159
-    public function get_ticket_with_latest_end_time()
1160
-    {
1161
-        $where['Datetime.EVT_ID'] = $this->ID();
1162
-        $query_params = array($where, 'order_by' => array('TKT_end_date' => 'DESC'));
1163
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1164
-    }
1165
-
1166
-
1167
-    /**
1168
-     * This returns the number of different ticket types currently on sale for this event.
1169
-     *
1170
-     * @return int
1171
-     * @throws EE_Error
1172
-     */
1173
-    public function countTicketsOnSale()
1174
-    {
1175
-        $where = array(
1176
-            'Datetime.EVT_ID' => $this->ID(),
1177
-            'TKT_start_date'  => array('<', time()),
1178
-            'TKT_end_date'    => array('>', time()),
1179
-        );
1180
-        return EEM_Ticket::instance()->count(array($where));
1181
-    }
1182
-
1183
-
1184
-    /**
1185
-     * This returns whether there are any tickets on sale for this event.
1186
-     *
1187
-     * @return bool true = YES tickets on sale.
1188
-     * @throws EE_Error
1189
-     */
1190
-    public function tickets_on_sale()
1191
-    {
1192
-        return $this->countTicketsOnSale() > 0;
1193
-    }
1194
-
1195
-
1196
-    /**
1197
-     * Gets the URL for viewing this event on the front-end. Overrides parent
1198
-     * to check for an external URL first
1199
-     *
1200
-     * @return string
1201
-     * @throws EE_Error
1202
-     */
1203
-    public function get_permalink()
1204
-    {
1205
-        if ($this->external_url()) {
1206
-            return $this->external_url();
1207
-        }
1208
-        return parent::get_permalink();
1209
-    }
1210
-
1211
-
1212
-    /**
1213
-     * Gets the first term for 'espresso_event_categories' we can find
1214
-     *
1215
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1216
-     * @return EE_Base_Class|EE_Term|null
1217
-     * @throws EE_Error
1218
-     */
1219
-    public function first_event_category($query_params = array())
1220
-    {
1221
-        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1222
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1223
-        return EEM_Term::instance()->get_one($query_params);
1224
-    }
1225
-
1226
-
1227
-    /**
1228
-     * Gets all terms for 'espresso_event_categories' we can find
1229
-     *
1230
-     * @param array $query_params
1231
-     * @return EE_Base_Class[]|EE_Term[]
1232
-     * @throws EE_Error
1233
-     */
1234
-    public function get_all_event_categories($query_params = array())
1235
-    {
1236
-        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1237
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1238
-        return EEM_Term::instance()->get_all($query_params);
1239
-    }
1240
-
1241
-
1242
-    /**
1243
-     * Adds a question group to this event
1244
-     *
1245
-     * @param EE_Question_Group|int $question_group_id_or_obj
1246
-     * @param bool $for_primary if true, the question group will be added for the primary
1247
-     *                                           registrant, if false will be added for others. default: false
1248
-     * @return EE_Base_Class|EE_Question_Group
1249
-     * @throws EE_Error
1250
-     * @throws InvalidArgumentException
1251
-     * @throws InvalidDataTypeException
1252
-     * @throws InvalidInterfaceException
1253
-     * @throws ReflectionException
1254
-     */
1255
-    public function add_question_group($question_group_id_or_obj, $for_primary = false)
1256
-    {
1257
-        // If the row already exists, it will be updated. If it doesn't, it will be inserted.
1258
-        // That's in EE_HABTM_Relation::add_relation_to().
1259
-        return $this->_add_relation_to(
1260
-            $question_group_id_or_obj,
1261
-            'Question_Group',
1262
-            [
1263
-                EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true
1264
-            ]
1265
-        );
1266
-    }
1267
-
1268
-
1269
-    /**
1270
-     * Removes a question group from the event
1271
-     *
1272
-     * @param EE_Question_Group|int $question_group_id_or_obj
1273
-     * @param bool $for_primary if true, the question group will be removed from the primary
1274
-     *                                           registrant, if false will be removed from others. default: false
1275
-     * @return EE_Base_Class|EE_Question_Group
1276
-     * @throws EE_Error
1277
-     * @throws InvalidArgumentException
1278
-     * @throws ReflectionException
1279
-     * @throws InvalidDataTypeException
1280
-     * @throws InvalidInterfaceException
1281
-     */
1282
-    public function remove_question_group($question_group_id_or_obj, $for_primary = false)
1283
-    {
1284
-        // If the question group is used for the other type (primary or additional)
1285
-        // then just update it. If not, delete it outright.
1286
-        $existing_relation = $this->get_first_related(
1287
-            'Event_Question_Group',
1288
-            [
1289
-                [
1290
-                    'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj)
1291
-                ]
1292
-            ]
1293
-        );
1294
-        $field_to_update = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1295
-        $other_field = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1296
-        if ($existing_relation->get($other_field) === false) {
1297
-            // Delete it. It's now no longer for primary or additional question groups.
1298
-            return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1299
-        }
1300
-        // Just update it. They'll still use this question group for the other category
1301
-        $existing_relation->save(
1302
-            [
1303
-                $field_to_update => false
1304
-            ]
1305
-        );
1306
-    }
1307
-
1308
-
1309
-    /**
1310
-     * Gets all the question groups, ordering them by QSG_order ascending
1311
-     *
1312
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1313
-     * @return EE_Base_Class[]|EE_Question_Group[]
1314
-     * @throws EE_Error
1315
-     */
1316
-    public function question_groups($query_params = array())
1317
-    {
1318
-        $query_params = ! empty($query_params) ? $query_params : array('order_by' => array('QSG_order' => 'ASC'));
1319
-        return $this->get_many_related('Question_Group', $query_params);
1320
-    }
1321
-
1322
-
1323
-    /**
1324
-     * Implementation for EEI_Has_Icon interface method.
1325
-     *
1326
-     * @see EEI_Visual_Representation for comments
1327
-     * @return string
1328
-     */
1329
-    public function get_icon()
1330
-    {
1331
-        return '<span class="dashicons dashicons-flag"></span>';
1332
-    }
1333
-
1334
-
1335
-    /**
1336
-     * Implementation for EEI_Admin_Links interface method.
1337
-     *
1338
-     * @see EEI_Admin_Links for comments
1339
-     * @return string
1340
-     * @throws EE_Error
1341
-     */
1342
-    public function get_admin_details_link()
1343
-    {
1344
-        return $this->get_admin_edit_link();
1345
-    }
1346
-
1347
-
1348
-    /**
1349
-     * Implementation for EEI_Admin_Links interface method.
1350
-     *
1351
-     * @see EEI_Admin_Links for comments
1352
-     * @return string
1353
-     * @throws EE_Error
1354
-     */
1355
-    public function get_admin_edit_link()
1356
-    {
1357
-        return EEH_URL::add_query_args_and_nonce(
1358
-            array(
1359
-                'page'   => 'espresso_events',
1360
-                'action' => 'edit',
1361
-                'post'   => $this->ID(),
1362
-            ),
1363
-            admin_url('admin.php')
1364
-        );
1365
-    }
1366
-
1367
-
1368
-    /**
1369
-     * Implementation for EEI_Admin_Links interface method.
1370
-     *
1371
-     * @see EEI_Admin_Links for comments
1372
-     * @return string
1373
-     */
1374
-    public function get_admin_settings_link()
1375
-    {
1376
-        return EEH_URL::add_query_args_and_nonce(
1377
-            array(
1378
-                'page'   => 'espresso_events',
1379
-                'action' => 'default_event_settings',
1380
-            ),
1381
-            admin_url('admin.php')
1382
-        );
1383
-    }
1384
-
1385
-
1386
-    /**
1387
-     * Implementation for EEI_Admin_Links interface method.
1388
-     *
1389
-     * @see EEI_Admin_Links for comments
1390
-     * @return string
1391
-     */
1392
-    public function get_admin_overview_link()
1393
-    {
1394
-        return EEH_URL::add_query_args_and_nonce(
1395
-            array(
1396
-                'page'   => 'espresso_events',
1397
-                'action' => 'default',
1398
-            ),
1399
-            admin_url('admin.php')
1400
-        );
1401
-    }
18
+	/**
19
+	 * cached value for the the logical active status for the event
20
+	 *
21
+	 * @see get_active_status()
22
+	 * @var string
23
+	 */
24
+	protected $_active_status = '';
25
+
26
+	/**
27
+	 * This is just used for caching the Primary Datetime for the Event on initial retrieval
28
+	 *
29
+	 * @var EE_Datetime
30
+	 */
31
+	protected $_Primary_Datetime;
32
+
33
+	/**
34
+	 * @var EventSpacesCalculator $available_spaces_calculator
35
+	 */
36
+	protected $available_spaces_calculator;
37
+
38
+
39
+	/**
40
+	 * @param array  $props_n_values          incoming values
41
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
42
+	 *                                        used.)
43
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
44
+	 *                                        date_format and the second value is the time format
45
+	 * @return EE_Event
46
+	 * @throws EE_Error
47
+	 */
48
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
49
+	{
50
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
51
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
52
+	}
53
+
54
+
55
+	/**
56
+	 * @param array  $props_n_values  incoming values from the database
57
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
+	 *                                the website will be used.
59
+	 * @return EE_Event
60
+	 * @throws EE_Error
61
+	 */
62
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
63
+	{
64
+		return new self($props_n_values, true, $timezone);
65
+	}
66
+
67
+
68
+	/**
69
+	 * @return EventSpacesCalculator
70
+	 * @throws \EE_Error
71
+	 */
72
+	public function getAvailableSpacesCalculator()
73
+	{
74
+		if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
75
+			$this->available_spaces_calculator = new EventSpacesCalculator($this);
76
+		}
77
+		return $this->available_spaces_calculator;
78
+	}
79
+
80
+
81
+	/**
82
+	 * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
83
+	 *
84
+	 * @param string $field_name
85
+	 * @param mixed  $field_value
86
+	 * @param bool   $use_default
87
+	 * @throws EE_Error
88
+	 */
89
+	public function set($field_name, $field_value, $use_default = false)
90
+	{
91
+		switch ($field_name) {
92
+			case 'status':
93
+				$this->set_status($field_value, $use_default);
94
+				break;
95
+			default:
96
+				parent::set($field_name, $field_value, $use_default);
97
+		}
98
+	}
99
+
100
+
101
+	/**
102
+	 *    set_status
103
+	 * Checks if event status is being changed to SOLD OUT
104
+	 * and updates event meta data with previous event status
105
+	 * so that we can revert things if/when the event is no longer sold out
106
+	 *
107
+	 * @access public
108
+	 * @param string $new_status
109
+	 * @param bool   $use_default
110
+	 * @return void
111
+	 * @throws EE_Error
112
+	 */
113
+	public function set_status($new_status = null, $use_default = false)
114
+	{
115
+		// if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
116
+		if (empty($new_status) && ! $use_default) {
117
+			return;
118
+		}
119
+		// get current Event status
120
+		$old_status = $this->status();
121
+		// if status has changed
122
+		if ($old_status !== $new_status) {
123
+			// TO sold_out
124
+			if ($new_status === EEM_Event::sold_out) {
125
+				// save the previous event status so that we can revert if the event is no longer sold out
126
+				$this->add_post_meta('_previous_event_status', $old_status);
127
+				do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $new_status);
128
+				// OR FROM  sold_out
129
+			} elseif ($old_status === EEM_Event::sold_out) {
130
+				$this->delete_post_meta('_previous_event_status');
131
+				do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $new_status);
132
+			}
133
+			// clear out the active status so that it gets reset the next time it is requested
134
+			$this->_active_status = null;
135
+			// update status
136
+			parent::set('status', $new_status, $use_default);
137
+			do_action('AHEE__EE_Event__set_status__after_update', $this);
138
+			return;
139
+		}
140
+		// even though the old value matches the new value, it's still good to
141
+		// allow the parent set method to have a say
142
+		parent::set('status', $new_status, $use_default);
143
+	}
144
+
145
+
146
+	/**
147
+	 * Gets all the datetimes for this event
148
+	 *
149
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
150
+	 * @return EE_Base_Class[]|EE_Datetime[]
151
+	 * @throws EE_Error
152
+	 */
153
+	public function datetimes($query_params = array())
154
+	{
155
+		return $this->get_many_related('Datetime', $query_params);
156
+	}
157
+
158
+
159
+	/**
160
+	 * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
161
+	 *
162
+	 * @return EE_Base_Class[]|EE_Datetime[]
163
+	 * @throws EE_Error
164
+	 */
165
+	public function datetimes_in_chronological_order()
166
+	{
167
+		return $this->get_many_related('Datetime', array('order_by' => array('DTT_EVT_start' => 'ASC')));
168
+	}
169
+
170
+
171
+	/**
172
+	 * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
173
+	 * @darren, we should probably UNSET timezone on the EEM_Datetime model
174
+	 * after running our query, so that this timezone isn't set for EVERY query
175
+	 * on EEM_Datetime for the rest of the request, no?
176
+	 *
177
+	 * @param boolean $show_expired whether or not to include expired events
178
+	 * @param boolean $show_deleted whether or not to include deleted events
179
+	 * @param null    $limit
180
+	 * @return EE_Datetime[]
181
+	 * @throws EE_Error
182
+	 */
183
+	public function datetimes_ordered($show_expired = true, $show_deleted = false, $limit = null)
184
+	{
185
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
186
+			$this->ID(),
187
+			$show_expired,
188
+			$show_deleted,
189
+			$limit
190
+		);
191
+	}
192
+
193
+
194
+	/**
195
+	 * Returns one related datetime. Mostly only used by some legacy code.
196
+	 *
197
+	 * @return EE_Base_Class|EE_Datetime
198
+	 * @throws EE_Error
199
+	 */
200
+	public function first_datetime()
201
+	{
202
+		return $this->get_first_related('Datetime');
203
+	}
204
+
205
+
206
+	/**
207
+	 * Returns the 'primary' datetime for the event
208
+	 *
209
+	 * @param bool $try_to_exclude_expired
210
+	 * @param bool $try_to_exclude_deleted
211
+	 * @return EE_Datetime
212
+	 * @throws EE_Error
213
+	 */
214
+	public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
215
+	{
216
+		if (! empty($this->_Primary_Datetime)) {
217
+			return $this->_Primary_Datetime;
218
+		}
219
+		$this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
220
+			$this->ID(),
221
+			$try_to_exclude_expired,
222
+			$try_to_exclude_deleted
223
+		);
224
+		return $this->_Primary_Datetime;
225
+	}
226
+
227
+
228
+	/**
229
+	 * Gets all the tickets available for purchase of this event
230
+	 *
231
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
232
+	 * @return EE_Base_Class[]|EE_Ticket[]
233
+	 * @throws EE_Error
234
+	 */
235
+	public function tickets($query_params = array())
236
+	{
237
+		// first get all datetimes
238
+		$datetimes = $this->datetimes_ordered();
239
+		if (! $datetimes) {
240
+			return array();
241
+		}
242
+		$datetime_ids = array();
243
+		foreach ($datetimes as $datetime) {
244
+			$datetime_ids[] = $datetime->ID();
245
+		}
246
+		$where_params = array('Datetime.DTT_ID' => array('IN', $datetime_ids));
247
+		// if incoming $query_params has where conditions let's merge but not override existing.
248
+		if (is_array($query_params) && isset($query_params[0])) {
249
+			$where_params = array_merge($query_params[0], $where_params);
250
+			unset($query_params[0]);
251
+		}
252
+		// now add $where_params to $query_params
253
+		$query_params[0] = $where_params;
254
+		return EEM_Ticket::instance()->get_all($query_params);
255
+	}
256
+
257
+
258
+	/**
259
+	 * get all unexpired untrashed tickets
260
+	 *
261
+	 * @return EE_Ticket[]
262
+	 * @throws EE_Error
263
+	 */
264
+	public function active_tickets()
265
+	{
266
+		return $this->tickets(
267
+			array(
268
+				array(
269
+					'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
270
+					'TKT_deleted'  => false,
271
+				),
272
+			)
273
+		);
274
+	}
275
+
276
+
277
+	/**
278
+	 * @return bool
279
+	 * @throws EE_Error
280
+	 */
281
+	public function additional_limit()
282
+	{
283
+		return $this->get('EVT_additional_limit');
284
+	}
285
+
286
+
287
+	/**
288
+	 * @return bool
289
+	 * @throws EE_Error
290
+	 */
291
+	public function allow_overflow()
292
+	{
293
+		return $this->get('EVT_allow_overflow');
294
+	}
295
+
296
+
297
+	/**
298
+	 * @return bool
299
+	 * @throws EE_Error
300
+	 */
301
+	public function created()
302
+	{
303
+		return $this->get('EVT_created');
304
+	}
305
+
306
+
307
+	/**
308
+	 * @return bool
309
+	 * @throws EE_Error
310
+	 */
311
+	public function description()
312
+	{
313
+		return $this->get('EVT_desc');
314
+	}
315
+
316
+
317
+	/**
318
+	 * Runs do_shortcode and wpautop on the description
319
+	 *
320
+	 * @return string of html
321
+	 * @throws EE_Error
322
+	 */
323
+	public function description_filtered()
324
+	{
325
+		return $this->get_pretty('EVT_desc');
326
+	}
327
+
328
+
329
+	/**
330
+	 * @return bool
331
+	 * @throws EE_Error
332
+	 */
333
+	public function display_description()
334
+	{
335
+		return $this->get('EVT_display_desc');
336
+	}
337
+
338
+
339
+	/**
340
+	 * @return bool
341
+	 * @throws EE_Error
342
+	 */
343
+	public function display_ticket_selector()
344
+	{
345
+		return (bool) $this->get('EVT_display_ticket_selector');
346
+	}
347
+
348
+
349
+	/**
350
+	 * @return bool
351
+	 * @throws EE_Error
352
+	 */
353
+	public function external_url()
354
+	{
355
+		return $this->get('EVT_external_URL');
356
+	}
357
+
358
+
359
+	/**
360
+	 * @return bool
361
+	 * @throws EE_Error
362
+	 */
363
+	public function member_only()
364
+	{
365
+		return $this->get('EVT_member_only');
366
+	}
367
+
368
+
369
+	/**
370
+	 * @return bool
371
+	 * @throws EE_Error
372
+	 */
373
+	public function phone()
374
+	{
375
+		return $this->get('EVT_phone');
376
+	}
377
+
378
+
379
+	/**
380
+	 * @return bool
381
+	 * @throws EE_Error
382
+	 */
383
+	public function modified()
384
+	{
385
+		return $this->get('EVT_modified');
386
+	}
387
+
388
+
389
+	/**
390
+	 * @return bool
391
+	 * @throws EE_Error
392
+	 */
393
+	public function name()
394
+	{
395
+		return $this->get('EVT_name');
396
+	}
397
+
398
+
399
+	/**
400
+	 * @return bool
401
+	 * @throws EE_Error
402
+	 */
403
+	public function order()
404
+	{
405
+		return $this->get('EVT_order');
406
+	}
407
+
408
+
409
+	/**
410
+	 * @return bool|string
411
+	 * @throws EE_Error
412
+	 */
413
+	public function default_registration_status()
414
+	{
415
+		$event_default_registration_status = $this->get('EVT_default_registration_status');
416
+		return ! empty($event_default_registration_status)
417
+			? $event_default_registration_status
418
+			: EE_Registry::instance()->CFG->registration->default_STS_ID;
419
+	}
420
+
421
+
422
+	/**
423
+	 * @param int  $num_words
424
+	 * @param null $more
425
+	 * @param bool $not_full_desc
426
+	 * @return bool|string
427
+	 * @throws EE_Error
428
+	 */
429
+	public function short_description($num_words = 55, $more = null, $not_full_desc = false)
430
+	{
431
+		$short_desc = $this->get('EVT_short_desc');
432
+		if (! empty($short_desc) || $not_full_desc) {
433
+			return $short_desc;
434
+		}
435
+		$full_desc = $this->get('EVT_desc');
436
+		return wp_trim_words($full_desc, $num_words, $more);
437
+	}
438
+
439
+
440
+	/**
441
+	 * @return bool
442
+	 * @throws EE_Error
443
+	 */
444
+	public function slug()
445
+	{
446
+		return $this->get('EVT_slug');
447
+	}
448
+
449
+
450
+	/**
451
+	 * @return bool
452
+	 * @throws EE_Error
453
+	 */
454
+	public function timezone_string()
455
+	{
456
+		return $this->get('EVT_timezone_string');
457
+	}
458
+
459
+
460
+	/**
461
+	 * @return bool
462
+	 * @throws EE_Error
463
+	 */
464
+	public function visible_on()
465
+	{
466
+		return $this->get('EVT_visible_on');
467
+	}
468
+
469
+
470
+	/**
471
+	 * @return int
472
+	 * @throws EE_Error
473
+	 */
474
+	public function wp_user()
475
+	{
476
+		return $this->get('EVT_wp_user');
477
+	}
478
+
479
+
480
+	/**
481
+	 * @return bool
482
+	 * @throws EE_Error
483
+	 */
484
+	public function donations()
485
+	{
486
+		return $this->get('EVT_donations');
487
+	}
488
+
489
+
490
+	/**
491
+	 * @param $limit
492
+	 * @throws EE_Error
493
+	 */
494
+	public function set_additional_limit($limit)
495
+	{
496
+		$this->set('EVT_additional_limit', $limit);
497
+	}
498
+
499
+
500
+	/**
501
+	 * @param $created
502
+	 * @throws EE_Error
503
+	 */
504
+	public function set_created($created)
505
+	{
506
+		$this->set('EVT_created', $created);
507
+	}
508
+
509
+
510
+	/**
511
+	 * @param $desc
512
+	 * @throws EE_Error
513
+	 */
514
+	public function set_description($desc)
515
+	{
516
+		$this->set('EVT_desc', $desc);
517
+	}
518
+
519
+
520
+	/**
521
+	 * @param $display_desc
522
+	 * @throws EE_Error
523
+	 */
524
+	public function set_display_description($display_desc)
525
+	{
526
+		$this->set('EVT_display_desc', $display_desc);
527
+	}
528
+
529
+
530
+	/**
531
+	 * @param $display_ticket_selector
532
+	 * @throws EE_Error
533
+	 */
534
+	public function set_display_ticket_selector($display_ticket_selector)
535
+	{
536
+		$this->set('EVT_display_ticket_selector', $display_ticket_selector);
537
+	}
538
+
539
+
540
+	/**
541
+	 * @param $external_url
542
+	 * @throws EE_Error
543
+	 */
544
+	public function set_external_url($external_url)
545
+	{
546
+		$this->set('EVT_external_URL', $external_url);
547
+	}
548
+
549
+
550
+	/**
551
+	 * @param $member_only
552
+	 * @throws EE_Error
553
+	 */
554
+	public function set_member_only($member_only)
555
+	{
556
+		$this->set('EVT_member_only', $member_only);
557
+	}
558
+
559
+
560
+	/**
561
+	 * @param $event_phone
562
+	 * @throws EE_Error
563
+	 */
564
+	public function set_event_phone($event_phone)
565
+	{
566
+		$this->set('EVT_phone', $event_phone);
567
+	}
568
+
569
+
570
+	/**
571
+	 * @param $modified
572
+	 * @throws EE_Error
573
+	 */
574
+	public function set_modified($modified)
575
+	{
576
+		$this->set('EVT_modified', $modified);
577
+	}
578
+
579
+
580
+	/**
581
+	 * @param $name
582
+	 * @throws EE_Error
583
+	 */
584
+	public function set_name($name)
585
+	{
586
+		$this->set('EVT_name', $name);
587
+	}
588
+
589
+
590
+	/**
591
+	 * @param $order
592
+	 * @throws EE_Error
593
+	 */
594
+	public function set_order($order)
595
+	{
596
+		$this->set('EVT_order', $order);
597
+	}
598
+
599
+
600
+	/**
601
+	 * @param $short_desc
602
+	 * @throws EE_Error
603
+	 */
604
+	public function set_short_description($short_desc)
605
+	{
606
+		$this->set('EVT_short_desc', $short_desc);
607
+	}
608
+
609
+
610
+	/**
611
+	 * @param $slug
612
+	 * @throws EE_Error
613
+	 */
614
+	public function set_slug($slug)
615
+	{
616
+		$this->set('EVT_slug', $slug);
617
+	}
618
+
619
+
620
+	/**
621
+	 * @param $timezone_string
622
+	 * @throws EE_Error
623
+	 */
624
+	public function set_timezone_string($timezone_string)
625
+	{
626
+		$this->set('EVT_timezone_string', $timezone_string);
627
+	}
628
+
629
+
630
+	/**
631
+	 * @param $visible_on
632
+	 * @throws EE_Error
633
+	 */
634
+	public function set_visible_on($visible_on)
635
+	{
636
+		$this->set('EVT_visible_on', $visible_on);
637
+	}
638
+
639
+
640
+	/**
641
+	 * @param $wp_user
642
+	 * @throws EE_Error
643
+	 */
644
+	public function set_wp_user($wp_user)
645
+	{
646
+		$this->set('EVT_wp_user', $wp_user);
647
+	}
648
+
649
+
650
+	/**
651
+	 * @param $default_registration_status
652
+	 * @throws EE_Error
653
+	 */
654
+	public function set_default_registration_status($default_registration_status)
655
+	{
656
+		$this->set('EVT_default_registration_status', $default_registration_status);
657
+	}
658
+
659
+
660
+	/**
661
+	 * @param $donations
662
+	 * @throws EE_Error
663
+	 */
664
+	public function set_donations($donations)
665
+	{
666
+		$this->set('EVT_donations', $donations);
667
+	}
668
+
669
+
670
+	/**
671
+	 * Adds a venue to this event
672
+	 *
673
+	 * @param EE_Venue /int $venue_id_or_obj
674
+	 * @return EE_Base_Class|EE_Venue
675
+	 * @throws EE_Error
676
+	 */
677
+	public function add_venue($venue_id_or_obj)
678
+	{
679
+		return $this->_add_relation_to($venue_id_or_obj, 'Venue');
680
+	}
681
+
682
+
683
+	/**
684
+	 * Removes a venue from the event
685
+	 *
686
+	 * @param EE_Venue /int $venue_id_or_obj
687
+	 * @return EE_Base_Class|EE_Venue
688
+	 * @throws EE_Error
689
+	 */
690
+	public function remove_venue($venue_id_or_obj)
691
+	{
692
+		return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
693
+	}
694
+
695
+
696
+	/**
697
+	 * Gets all the venues related ot the event. May provide additional $query_params if desired
698
+	 *
699
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
700
+	 * @return EE_Base_Class[]|EE_Venue[]
701
+	 * @throws EE_Error
702
+	 */
703
+	public function venues($query_params = array())
704
+	{
705
+		return $this->get_many_related('Venue', $query_params);
706
+	}
707
+
708
+
709
+	/**
710
+	 * check if event id is present and if event is published
711
+	 *
712
+	 * @access public
713
+	 * @return boolean true yes, false no
714
+	 * @throws EE_Error
715
+	 */
716
+	private function _has_ID_and_is_published()
717
+	{
718
+		// first check if event id is present and not NULL,
719
+		// then check if this event is published (or any of the equivalent "published" statuses)
720
+		return
721
+			$this->ID() && $this->ID() !== null
722
+			&& (
723
+				$this->status() === 'publish'
724
+				|| $this->status() === EEM_Event::sold_out
725
+				|| $this->status() === EEM_Event::postponed
726
+				|| $this->status() === EEM_Event::cancelled
727
+			);
728
+	}
729
+
730
+
731
+	/**
732
+	 * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
733
+	 *
734
+	 * @access public
735
+	 * @return boolean true yes, false no
736
+	 * @throws EE_Error
737
+	 */
738
+	public function is_upcoming()
739
+	{
740
+		// check if event id is present and if this event is published
741
+		if ($this->is_inactive()) {
742
+			return false;
743
+		}
744
+		// set initial value
745
+		$upcoming = false;
746
+		// next let's get all datetimes and loop through them
747
+		$datetimes = $this->datetimes_in_chronological_order();
748
+		foreach ($datetimes as $datetime) {
749
+			if ($datetime instanceof EE_Datetime) {
750
+				// if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
751
+				if ($datetime->is_expired()) {
752
+					continue;
753
+				}
754
+				// if this dtt is active then we return false.
755
+				if ($datetime->is_active()) {
756
+					return false;
757
+				}
758
+				// otherwise let's check upcoming status
759
+				$upcoming = $datetime->is_upcoming();
760
+			}
761
+		}
762
+		return $upcoming;
763
+	}
764
+
765
+
766
+	/**
767
+	 * @return bool
768
+	 * @throws EE_Error
769
+	 */
770
+	public function is_active()
771
+	{
772
+		// check if event id is present and if this event is published
773
+		if ($this->is_inactive()) {
774
+			return false;
775
+		}
776
+		// set initial value
777
+		$active = false;
778
+		// next let's get all datetimes and loop through them
779
+		$datetimes = $this->datetimes_in_chronological_order();
780
+		foreach ($datetimes as $datetime) {
781
+			if ($datetime instanceof EE_Datetime) {
782
+				// if this dtt is expired then we continue cause one of the other datetimes might be active.
783
+				if ($datetime->is_expired()) {
784
+					continue;
785
+				}
786
+				// if this dtt is upcoming then we return false.
787
+				if ($datetime->is_upcoming()) {
788
+					return false;
789
+				}
790
+				// otherwise let's check active status
791
+				$active = $datetime->is_active();
792
+			}
793
+		}
794
+		return $active;
795
+	}
796
+
797
+
798
+	/**
799
+	 * @return bool
800
+	 * @throws EE_Error
801
+	 */
802
+	public function is_expired()
803
+	{
804
+		// check if event id is present and if this event is published
805
+		if ($this->is_inactive()) {
806
+			return false;
807
+		}
808
+		// set initial value
809
+		$expired = false;
810
+		// first let's get all datetimes and loop through them
811
+		$datetimes = $this->datetimes_in_chronological_order();
812
+		foreach ($datetimes as $datetime) {
813
+			if ($datetime instanceof EE_Datetime) {
814
+				// if this dtt is upcoming or active then we return false.
815
+				if ($datetime->is_upcoming() || $datetime->is_active()) {
816
+					return false;
817
+				}
818
+				// otherwise let's check active status
819
+				$expired = $datetime->is_expired();
820
+			}
821
+		}
822
+		return $expired;
823
+	}
824
+
825
+
826
+	/**
827
+	 * @return bool
828
+	 * @throws EE_Error
829
+	 */
830
+	public function is_inactive()
831
+	{
832
+		// check if event id is present and if this event is published
833
+		if ($this->_has_ID_and_is_published()) {
834
+			return false;
835
+		}
836
+		return true;
837
+	}
838
+
839
+
840
+	/**
841
+	 * calculate spaces remaining based on "saleable" tickets
842
+	 *
843
+	 * @param array $tickets
844
+	 * @param bool  $filtered
845
+	 * @return int|float
846
+	 * @throws EE_Error
847
+	 * @throws DomainException
848
+	 * @throws UnexpectedEntityException
849
+	 */
850
+	public function spaces_remaining($tickets = array(), $filtered = true)
851
+	{
852
+		$this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
853
+		$spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
854
+		return $filtered
855
+			? apply_filters(
856
+				'FHEE_EE_Event__spaces_remaining',
857
+				$spaces_remaining,
858
+				$this,
859
+				$tickets
860
+			)
861
+			: $spaces_remaining;
862
+	}
863
+
864
+
865
+	/**
866
+	 *    perform_sold_out_status_check
867
+	 *    checks all of this events's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
868
+	 *    available... if NOT, then the event status will get toggled to 'sold_out'
869
+	 *
870
+	 * @return bool    return the ACTUAL sold out state.
871
+	 * @throws EE_Error
872
+	 * @throws DomainException
873
+	 * @throws UnexpectedEntityException
874
+	 */
875
+	public function perform_sold_out_status_check()
876
+	{
877
+		// get all unexpired untrashed tickets
878
+		$tickets = $this->tickets(
879
+			array(
880
+				array('TKT_deleted' => false),
881
+				'order_by' => array('TKT_qty' => 'ASC'),
882
+			)
883
+		);
884
+		$all_expired = true;
885
+		foreach ($tickets as $ticket) {
886
+			if (! $ticket->is_expired()) {
887
+				$all_expired = false;
888
+				break;
889
+			}
890
+		}
891
+		// if all the tickets are just expired, then don't update the event status to sold out
892
+		if ($all_expired) {
893
+			return true;
894
+		}
895
+		$spaces_remaining = $this->spaces_remaining($tickets);
896
+		if ($spaces_remaining < 1) {
897
+			if ($this->status() !== EEM_Event::post_status_private) {
898
+				$this->set_status(EEM_Event::sold_out);
899
+				$this->save();
900
+			}
901
+			$sold_out = true;
902
+		} else {
903
+			$sold_out = false;
904
+			// was event previously marked as sold out ?
905
+			if ($this->status() === EEM_Event::sold_out) {
906
+				// revert status to previous value, if it was set
907
+				$previous_event_status = $this->get_post_meta('_previous_event_status', true);
908
+				if ($previous_event_status) {
909
+					$this->set_status($previous_event_status);
910
+					$this->save();
911
+				}
912
+			}
913
+		}
914
+		do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
915
+		return $sold_out;
916
+	}
917
+
918
+
919
+	/**
920
+	 * This returns the total remaining spaces for sale on this event.
921
+	 *
922
+	 * @uses EE_Event::total_available_spaces()
923
+	 * @return float|int
924
+	 * @throws EE_Error
925
+	 * @throws DomainException
926
+	 * @throws UnexpectedEntityException
927
+	 */
928
+	public function spaces_remaining_for_sale()
929
+	{
930
+		return $this->total_available_spaces(true);
931
+	}
932
+
933
+
934
+	/**
935
+	 * This returns the total spaces available for an event
936
+	 * while considering all the qtys on the tickets and the reg limits
937
+	 * on the datetimes attached to this event.
938
+	 *
939
+	 * @param   bool $consider_sold Whether to consider any tickets that have already sold in our calculation.
940
+	 *                              If this is false, then we return the most tickets that could ever be sold
941
+	 *                              for this event with the datetime and tickets setup on the event under optimal
942
+	 *                              selling conditions.  Otherwise we return a live calculation of spaces available
943
+	 *                              based on tickets sold.  Depending on setup and stage of sales, this
944
+	 *                              may appear to equal remaining tickets.  However, the more tickets are
945
+	 *                              sold out, the more accurate the "live" total is.
946
+	 * @return float|int
947
+	 * @throws EE_Error
948
+	 * @throws DomainException
949
+	 * @throws UnexpectedEntityException
950
+	 */
951
+	public function total_available_spaces($consider_sold = false)
952
+	{
953
+		$spaces_available = $consider_sold
954
+			? $this->getAvailableSpacesCalculator()->spacesRemaining()
955
+			: $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
956
+		return apply_filters(
957
+			'FHEE_EE_Event__total_available_spaces__spaces_available',
958
+			$spaces_available,
959
+			$this,
960
+			$this->getAvailableSpacesCalculator()->getDatetimes(),
961
+			$this->getAvailableSpacesCalculator()->getActiveTickets()
962
+		);
963
+	}
964
+
965
+
966
+	/**
967
+	 * Checks if the event is set to sold out
968
+	 *
969
+	 * @param  bool $actual whether or not to perform calculations to not only figure the
970
+	 *                      actual status but also to flip the status if necessary to sold
971
+	 *                      out If false, we just check the existing status of the event
972
+	 * @return boolean
973
+	 * @throws EE_Error
974
+	 */
975
+	public function is_sold_out($actual = false)
976
+	{
977
+		if (! $actual) {
978
+			return $this->status() === EEM_Event::sold_out;
979
+		}
980
+		return $this->perform_sold_out_status_check();
981
+	}
982
+
983
+
984
+	/**
985
+	 * Checks if the event is marked as postponed
986
+	 *
987
+	 * @return boolean
988
+	 */
989
+	public function is_postponed()
990
+	{
991
+		return $this->status() === EEM_Event::postponed;
992
+	}
993
+
994
+
995
+	/**
996
+	 * Checks if the event is marked as cancelled
997
+	 *
998
+	 * @return boolean
999
+	 */
1000
+	public function is_cancelled()
1001
+	{
1002
+		return $this->status() === EEM_Event::cancelled;
1003
+	}
1004
+
1005
+
1006
+	/**
1007
+	 * Get the logical active status in a hierarchical order for all the datetimes.  Note
1008
+	 * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1009
+	 * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1010
+	 * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1011
+	 * the event is considered expired.
1012
+	 * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1013
+	 * status set on the EVENT when it is not published and thus is done
1014
+	 *
1015
+	 * @param bool $reset
1016
+	 * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1017
+	 * @throws EE_Error
1018
+	 */
1019
+	public function get_active_status($reset = false)
1020
+	{
1021
+		// if the active status has already been set, then just use that value (unless we are resetting it)
1022
+		if (! empty($this->_active_status) && ! $reset) {
1023
+			return $this->_active_status;
1024
+		}
1025
+		// first check if event id is present on this object
1026
+		if (! $this->ID()) {
1027
+			return false;
1028
+		}
1029
+		$where_params_for_event = array(array('EVT_ID' => $this->ID()));
1030
+		// if event is published:
1031
+		if ($this->status() === EEM_Event::post_status_publish || $this->status() === EEM_Event::post_status_private) {
1032
+			// active?
1033
+			if (EEM_Datetime::instance()->get_datetime_count_for_status(
1034
+				EE_Datetime::active,
1035
+				$where_params_for_event
1036
+			) > 0) {
1037
+				$this->_active_status = EE_Datetime::active;
1038
+			} else {
1039
+				// upcoming?
1040
+				if (EEM_Datetime::instance()->get_datetime_count_for_status(
1041
+					EE_Datetime::upcoming,
1042
+					$where_params_for_event
1043
+				) > 0) {
1044
+					$this->_active_status = EE_Datetime::upcoming;
1045
+				} else {
1046
+					// expired?
1047
+					if (EEM_Datetime::instance()->get_datetime_count_for_status(
1048
+						EE_Datetime::expired,
1049
+						$where_params_for_event
1050
+					) > 0
1051
+					) {
1052
+						$this->_active_status = EE_Datetime::expired;
1053
+					} else {
1054
+						// it would be odd if things make it this far because it basically means there are no datetime's
1055
+						// attached to the event.  So in this case it will just be considered inactive.
1056
+						$this->_active_status = EE_Datetime::inactive;
1057
+					}
1058
+				}
1059
+			}
1060
+		} else {
1061
+			// the event is not published, so let's just set it's active status according to its' post status
1062
+			switch ($this->status()) {
1063
+				case EEM_Event::sold_out:
1064
+					$this->_active_status = EE_Datetime::sold_out;
1065
+					break;
1066
+				case EEM_Event::cancelled:
1067
+					$this->_active_status = EE_Datetime::cancelled;
1068
+					break;
1069
+				case EEM_Event::postponed:
1070
+					$this->_active_status = EE_Datetime::postponed;
1071
+					break;
1072
+				default:
1073
+					$this->_active_status = EE_Datetime::inactive;
1074
+			}
1075
+		}
1076
+		return $this->_active_status;
1077
+	}
1078
+
1079
+
1080
+	/**
1081
+	 *    pretty_active_status
1082
+	 *
1083
+	 * @access public
1084
+	 * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1085
+	 * @return mixed void|string
1086
+	 * @throws EE_Error
1087
+	 */
1088
+	public function pretty_active_status($echo = true)
1089
+	{
1090
+		$active_status = $this->get_active_status();
1091
+		$status = '<span class="ee-status event-active-status-'
1092
+				  . $active_status
1093
+				  . '">'
1094
+				  . EEH_Template::pretty_status($active_status, false, 'sentence')
1095
+				  . '</span>';
1096
+		if ($echo) {
1097
+			echo $status;
1098
+			return '';
1099
+		}
1100
+		return $status;
1101
+	}
1102
+
1103
+
1104
+	/**
1105
+	 * @return bool|int
1106
+	 * @throws EE_Error
1107
+	 */
1108
+	public function get_number_of_tickets_sold()
1109
+	{
1110
+		$tkt_sold = 0;
1111
+		if (! $this->ID()) {
1112
+			return 0;
1113
+		}
1114
+		$datetimes = $this->datetimes();
1115
+		foreach ($datetimes as $datetime) {
1116
+			if ($datetime instanceof EE_Datetime) {
1117
+				$tkt_sold += $datetime->sold();
1118
+			}
1119
+		}
1120
+		return $tkt_sold;
1121
+	}
1122
+
1123
+
1124
+	/**
1125
+	 * This just returns a count of all the registrations for this event
1126
+	 *
1127
+	 * @access  public
1128
+	 * @return int
1129
+	 * @throws EE_Error
1130
+	 */
1131
+	public function get_count_of_all_registrations()
1132
+	{
1133
+		return EEM_Event::instance()->count_related($this, 'Registration');
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * This returns the ticket with the earliest start time that is
1139
+	 * available for this event (across all datetimes attached to the event)
1140
+	 *
1141
+	 * @return EE_Base_Class|EE_Ticket|null
1142
+	 * @throws EE_Error
1143
+	 */
1144
+	public function get_ticket_with_earliest_start_time()
1145
+	{
1146
+		$where['Datetime.EVT_ID'] = $this->ID();
1147
+		$query_params = array($where, 'order_by' => array('TKT_start_date' => 'ASC'));
1148
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1149
+	}
1150
+
1151
+
1152
+	/**
1153
+	 * This returns the ticket with the latest end time that is available
1154
+	 * for this event (across all datetimes attached to the event)
1155
+	 *
1156
+	 * @return EE_Base_Class|EE_Ticket|null
1157
+	 * @throws EE_Error
1158
+	 */
1159
+	public function get_ticket_with_latest_end_time()
1160
+	{
1161
+		$where['Datetime.EVT_ID'] = $this->ID();
1162
+		$query_params = array($where, 'order_by' => array('TKT_end_date' => 'DESC'));
1163
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1164
+	}
1165
+
1166
+
1167
+	/**
1168
+	 * This returns the number of different ticket types currently on sale for this event.
1169
+	 *
1170
+	 * @return int
1171
+	 * @throws EE_Error
1172
+	 */
1173
+	public function countTicketsOnSale()
1174
+	{
1175
+		$where = array(
1176
+			'Datetime.EVT_ID' => $this->ID(),
1177
+			'TKT_start_date'  => array('<', time()),
1178
+			'TKT_end_date'    => array('>', time()),
1179
+		);
1180
+		return EEM_Ticket::instance()->count(array($where));
1181
+	}
1182
+
1183
+
1184
+	/**
1185
+	 * This returns whether there are any tickets on sale for this event.
1186
+	 *
1187
+	 * @return bool true = YES tickets on sale.
1188
+	 * @throws EE_Error
1189
+	 */
1190
+	public function tickets_on_sale()
1191
+	{
1192
+		return $this->countTicketsOnSale() > 0;
1193
+	}
1194
+
1195
+
1196
+	/**
1197
+	 * Gets the URL for viewing this event on the front-end. Overrides parent
1198
+	 * to check for an external URL first
1199
+	 *
1200
+	 * @return string
1201
+	 * @throws EE_Error
1202
+	 */
1203
+	public function get_permalink()
1204
+	{
1205
+		if ($this->external_url()) {
1206
+			return $this->external_url();
1207
+		}
1208
+		return parent::get_permalink();
1209
+	}
1210
+
1211
+
1212
+	/**
1213
+	 * Gets the first term for 'espresso_event_categories' we can find
1214
+	 *
1215
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1216
+	 * @return EE_Base_Class|EE_Term|null
1217
+	 * @throws EE_Error
1218
+	 */
1219
+	public function first_event_category($query_params = array())
1220
+	{
1221
+		$query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1222
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1223
+		return EEM_Term::instance()->get_one($query_params);
1224
+	}
1225
+
1226
+
1227
+	/**
1228
+	 * Gets all terms for 'espresso_event_categories' we can find
1229
+	 *
1230
+	 * @param array $query_params
1231
+	 * @return EE_Base_Class[]|EE_Term[]
1232
+	 * @throws EE_Error
1233
+	 */
1234
+	public function get_all_event_categories($query_params = array())
1235
+	{
1236
+		$query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1237
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1238
+		return EEM_Term::instance()->get_all($query_params);
1239
+	}
1240
+
1241
+
1242
+	/**
1243
+	 * Adds a question group to this event
1244
+	 *
1245
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1246
+	 * @param bool $for_primary if true, the question group will be added for the primary
1247
+	 *                                           registrant, if false will be added for others. default: false
1248
+	 * @return EE_Base_Class|EE_Question_Group
1249
+	 * @throws EE_Error
1250
+	 * @throws InvalidArgumentException
1251
+	 * @throws InvalidDataTypeException
1252
+	 * @throws InvalidInterfaceException
1253
+	 * @throws ReflectionException
1254
+	 */
1255
+	public function add_question_group($question_group_id_or_obj, $for_primary = false)
1256
+	{
1257
+		// If the row already exists, it will be updated. If it doesn't, it will be inserted.
1258
+		// That's in EE_HABTM_Relation::add_relation_to().
1259
+		return $this->_add_relation_to(
1260
+			$question_group_id_or_obj,
1261
+			'Question_Group',
1262
+			[
1263
+				EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true
1264
+			]
1265
+		);
1266
+	}
1267
+
1268
+
1269
+	/**
1270
+	 * Removes a question group from the event
1271
+	 *
1272
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1273
+	 * @param bool $for_primary if true, the question group will be removed from the primary
1274
+	 *                                           registrant, if false will be removed from others. default: false
1275
+	 * @return EE_Base_Class|EE_Question_Group
1276
+	 * @throws EE_Error
1277
+	 * @throws InvalidArgumentException
1278
+	 * @throws ReflectionException
1279
+	 * @throws InvalidDataTypeException
1280
+	 * @throws InvalidInterfaceException
1281
+	 */
1282
+	public function remove_question_group($question_group_id_or_obj, $for_primary = false)
1283
+	{
1284
+		// If the question group is used for the other type (primary or additional)
1285
+		// then just update it. If not, delete it outright.
1286
+		$existing_relation = $this->get_first_related(
1287
+			'Event_Question_Group',
1288
+			[
1289
+				[
1290
+					'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj)
1291
+				]
1292
+			]
1293
+		);
1294
+		$field_to_update = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1295
+		$other_field = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1296
+		if ($existing_relation->get($other_field) === false) {
1297
+			// Delete it. It's now no longer for primary or additional question groups.
1298
+			return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1299
+		}
1300
+		// Just update it. They'll still use this question group for the other category
1301
+		$existing_relation->save(
1302
+			[
1303
+				$field_to_update => false
1304
+			]
1305
+		);
1306
+	}
1307
+
1308
+
1309
+	/**
1310
+	 * Gets all the question groups, ordering them by QSG_order ascending
1311
+	 *
1312
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1313
+	 * @return EE_Base_Class[]|EE_Question_Group[]
1314
+	 * @throws EE_Error
1315
+	 */
1316
+	public function question_groups($query_params = array())
1317
+	{
1318
+		$query_params = ! empty($query_params) ? $query_params : array('order_by' => array('QSG_order' => 'ASC'));
1319
+		return $this->get_many_related('Question_Group', $query_params);
1320
+	}
1321
+
1322
+
1323
+	/**
1324
+	 * Implementation for EEI_Has_Icon interface method.
1325
+	 *
1326
+	 * @see EEI_Visual_Representation for comments
1327
+	 * @return string
1328
+	 */
1329
+	public function get_icon()
1330
+	{
1331
+		return '<span class="dashicons dashicons-flag"></span>';
1332
+	}
1333
+
1334
+
1335
+	/**
1336
+	 * Implementation for EEI_Admin_Links interface method.
1337
+	 *
1338
+	 * @see EEI_Admin_Links for comments
1339
+	 * @return string
1340
+	 * @throws EE_Error
1341
+	 */
1342
+	public function get_admin_details_link()
1343
+	{
1344
+		return $this->get_admin_edit_link();
1345
+	}
1346
+
1347
+
1348
+	/**
1349
+	 * Implementation for EEI_Admin_Links interface method.
1350
+	 *
1351
+	 * @see EEI_Admin_Links for comments
1352
+	 * @return string
1353
+	 * @throws EE_Error
1354
+	 */
1355
+	public function get_admin_edit_link()
1356
+	{
1357
+		return EEH_URL::add_query_args_and_nonce(
1358
+			array(
1359
+				'page'   => 'espresso_events',
1360
+				'action' => 'edit',
1361
+				'post'   => $this->ID(),
1362
+			),
1363
+			admin_url('admin.php')
1364
+		);
1365
+	}
1366
+
1367
+
1368
+	/**
1369
+	 * Implementation for EEI_Admin_Links interface method.
1370
+	 *
1371
+	 * @see EEI_Admin_Links for comments
1372
+	 * @return string
1373
+	 */
1374
+	public function get_admin_settings_link()
1375
+	{
1376
+		return EEH_URL::add_query_args_and_nonce(
1377
+			array(
1378
+				'page'   => 'espresso_events',
1379
+				'action' => 'default_event_settings',
1380
+			),
1381
+			admin_url('admin.php')
1382
+		);
1383
+	}
1384
+
1385
+
1386
+	/**
1387
+	 * Implementation for EEI_Admin_Links interface method.
1388
+	 *
1389
+	 * @see EEI_Admin_Links for comments
1390
+	 * @return string
1391
+	 */
1392
+	public function get_admin_overview_link()
1393
+	{
1394
+		return EEH_URL::add_query_args_and_nonce(
1395
+			array(
1396
+				'page'   => 'espresso_events',
1397
+				'action' => 'default',
1398
+			),
1399
+			admin_url('admin.php')
1400
+		);
1401
+	}
1402 1402
 }
Please login to merge, or discard this patch.
attendee_information/EE_SPCO_Reg_Step_Attendee_Information.class.php 1 patch
Indentation   +1422 added lines, -1422 removed lines patch added patch discarded remove patch
@@ -18,1429 +18,1429 @@
 block discarded – undo
18 18
 class EE_SPCO_Reg_Step_Attendee_Information extends EE_SPCO_Reg_Step
19 19
 {
20 20
 
21
-    /**
22
-     * @type bool $_print_copy_info
23
-     */
24
-    private $_print_copy_info = false;
25
-
26
-    /**
27
-     * @type array $_attendee_data
28
-     */
29
-    private $_attendee_data = array();
30
-
31
-    /**
32
-     * @type array $_required_questions
33
-     */
34
-    private $_required_questions = array();
35
-
36
-    /**
37
-     * @type array $_registration_answers
38
-     */
39
-    private $_registration_answers = array();
40
-
41
-
42
-    /**
43
-     *    class constructor
44
-     *
45
-     * @access    public
46
-     * @param    EE_Checkout $checkout
47
-     */
48
-    public function __construct(EE_Checkout $checkout)
49
-    {
50
-        $this->_slug = 'attendee_information';
51
-        $this->_name = esc_html__('Attendee Information', 'event_espresso');
52
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
53
-        $this->checkout = $checkout;
54
-        $this->_reset_success_message();
55
-        $this->set_instructions(
56
-            esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
57
-        );
58
-    }
59
-
60
-
61
-    public function translate_js_strings()
62
-    {
63
-        EE_Registry::$i18n_js_strings['required_field'] = esc_html__(
64
-            ' is a required question.',
65
-            'event_espresso'
66
-        );
67
-        EE_Registry::$i18n_js_strings['required_multi_field'] = esc_html__(
68
-            ' is a required question. Please enter a value for at least one of the options.',
69
-            'event_espresso'
70
-        );
71
-        EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
72
-            'Please answer all required questions correctly before proceeding.',
73
-            'event_espresso'
74
-        );
75
-        EE_Registry::$i18n_js_strings['attendee_info_copied'] = sprintf(
76
-            esc_html_x(
77
-                'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
78
-                'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
79
-                'event_espresso'
80
-            ),
81
-            '<br/>'
82
-        );
83
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error'] = esc_html__(
84
-            'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
85
-            'event_espresso'
86
-        );
87
-        EE_Registry::$i18n_js_strings['enter_valid_email'] = esc_html__(
88
-            'You must enter a valid email address.',
89
-            'event_espresso'
90
-        );
91
-        EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
92
-            'You must enter a valid email address and answer all other required questions before you can proceed.',
93
-            'event_espresso'
94
-        );
95
-    }
96
-
97
-
98
-    public function enqueue_styles_and_scripts()
99
-    {
100
-    }
101
-
102
-
103
-    /**
104
-     * @return boolean
105
-     */
106
-    public function initialize_reg_step()
107
-    {
108
-        return true;
109
-    }
110
-
111
-
112
-    /**
113
-     * @return EE_Form_Section_Proper
114
-     * @throws DomainException
115
-     * @throws EE_Error
116
-     * @throws InvalidArgumentException
117
-     * @throws ReflectionException
118
-     * @throws EntityNotFoundException
119
-     * @throws InvalidDataTypeException
120
-     * @throws InvalidInterfaceException
121
-     */
122
-    public function generate_reg_form()
123
-    {
124
-        $this->_print_copy_info = false;
125
-        $primary_registrant = null;
126
-        // autoload Line_Item_Display classes
127
-        EEH_Autoloader::register_line_item_display_autoloaders();
128
-        $Line_Item_Display = new EE_Line_Item_Display();
129
-        // calculate taxes
130
-        $Line_Item_Display->display_line_item(
131
-            $this->checkout->cart->get_grand_total(),
132
-            array('set_tax_rate' => true)
133
-        );
134
-        /** @var $subsections EE_Form_Section_Proper[] */
135
-        $extra_inputs_section = $this->reg_step_hidden_inputs();
136
-        $subsections = array(
137
-            'default_hidden_inputs' => $extra_inputs_section,
138
-        );
139
-
140
-        /**
141
-         * @var $reg_config EE_Registration_Config
142
-         */
143
-        $reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
144
-        // if this isn't a revisit, and they have the privacy consent box enalbed, add it
145
-        if (! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
146
-            $extra_inputs_section->add_subsections(
147
-                array(
148
-                    'consent_box' => new EE_Form_Section_Proper(
149
-                        array(
150
-                            'layout_strategy' =>
151
-                                new EE_Template_Layout(
152
-                                    array(
153
-                                        'input_template_file' => SPCO_REG_STEPS_PATH . $this->_slug . DS . 'privacy_consent.template.php',
154
-                                    )
155
-                                ),
156
-                            'subsections'     => array(
157
-                                'consent' => new EE_Checkbox_Multi_Input(
158
-                                    array(
159
-                                        'consent' => $reg_config->getConsentCheckboxLabelText(),
160
-                                    ),
161
-                                    array(
162
-                                        'required'                          => true,
163
-                                        'required_validation_error_message' => esc_html__(
164
-                                            'You must consent to these terms in order to register.',
165
-                                            'event_espresso'
166
-                                        ),
167
-                                        'html_label_text'                   => '',
168
-                                    )
169
-                                ),
170
-                            ),
171
-                        )
172
-                    ),
173
-                ),
174
-                null,
175
-                false
176
-            );
177
-        }
178
-        $template_args = array(
179
-            'revisit'       => $this->checkout->revisit,
180
-            'registrations' => array(),
181
-            'ticket_count'  => array(),
182
-        );
183
-        // grab the saved registrations from the transaction
184
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
185
-        if ($registrations) {
186
-            foreach ($registrations as $registration) {
187
-                // can this registration be processed during this visit ?
188
-                if ($registration instanceof EE_Registration
189
-                    && $this->checkout->visit_allows_processing_of_this_registration($registration)
190
-                ) {
191
-                    $subsections[ $registration->reg_url_link() ] = $this->_registrations_reg_form($registration);
192
-                    if (! $this->checkout->admin_request) {
193
-                        $template_args['registrations'][ $registration->reg_url_link() ] = $registration;
194
-                        $template_args['ticket_count'][ $registration->ticket()->ID() ] = isset(
195
-                            $template_args['ticket_count'][ $registration->ticket()->ID() ]
196
-                        )
197
-                            ? $template_args['ticket_count'][ $registration->ticket()->ID() ] + 1
198
-                            : 1;
199
-                        $ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
200
-                            $this->checkout->cart->get_grand_total(),
201
-                            'Ticket',
202
-                            array($registration->ticket()->ID())
203
-                        );
204
-                        $ticket_line_item = is_array($ticket_line_item)
205
-                            ? reset($ticket_line_item)
206
-                            : $ticket_line_item;
207
-                        $template_args['ticket_line_item'][ $registration->ticket()->ID() ] =
208
-                            $Line_Item_Display->display_line_item($ticket_line_item);
209
-                    }
210
-                    if ($registration->is_primary_registrant()) {
211
-                        $primary_registrant = $registration->reg_url_link();
212
-                    }
213
-                }
214
-            }
215
-            // print_copy_info ?
216
-            if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
217
-                // TODO: add admin option for toggling copy attendee info,
218
-                // then use that value to change $this->_print_copy_info
219
-                $copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
220
-                    ? $this->_copy_attendee_info_form()
221
-                    : $this->_auto_copy_attendee_info();
222
-                // generate hidden input
223
-                if (isset($subsections[ $primary_registrant ])
224
-                    && $subsections[ $primary_registrant ] instanceof EE_Form_Section_Proper
225
-                ) {
226
-                    $subsections[ $primary_registrant ]->add_subsections(
227
-                        $copy_options,
228
-                        'primary_registrant',
229
-                        false
230
-                    );
231
-                }
232
-            }
233
-        }
234
-        return new EE_Form_Section_Proper(
235
-            array(
236
-                'name'            => $this->reg_form_name(),
237
-                'html_id'         => $this->reg_form_name(),
238
-                'subsections'     => $subsections,
239
-                'layout_strategy' => $this->checkout->admin_request
240
-                    ?
241
-                    new EE_Div_Per_Section_Layout()
242
-                    :
243
-                    new EE_Template_Layout(
244
-                        array(
245
-                            'layout_template_file' => $this->_template, // layout_template
246
-                            'template_args'        => $template_args,
247
-                        )
248
-                    ),
249
-            )
250
-        );
251
-    }
252
-
253
-
254
-    /**
255
-     * @param EE_Registration $registration
256
-     * @return EE_Form_Section_Base
257
-     * @throws EE_Error
258
-     * @throws InvalidArgumentException
259
-     * @throws EntityNotFoundException
260
-     * @throws InvalidDataTypeException
261
-     * @throws InvalidInterfaceException
262
-     * @throws ReflectionException
263
-     */
264
-    private function _registrations_reg_form(EE_Registration $registration)
265
-    {
266
-        static $attendee_nmbr = 1;
267
-        $form_args = array();
268
-        // verify that registration has valid event
269
-        if ($registration->event() instanceof EE_Event) {
270
-            $field_name = 'Event_Question_Group.'
271
-                . EEM_Event_Question_Group::instance()->fieldNameForContext(
272
-                    $registration->is_primary_registrant()
273
-                );
274
-            $question_groups = $registration->event()->question_groups(
275
-                apply_filters(
276
-                    // @codingStandardsIgnoreStart
277
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
278
-                    // @codingStandardsIgnoreEnd
279
-                    [
280
-                        [
281
-                            'Event.EVT_ID'                     => $registration->event()->ID(),
282
-                            $field_name => true,
283
-                        ],
284
-                        'order_by' => ['QSG_order' => 'ASC'],
285
-                    ],
286
-                    $registration,
287
-                    $this
288
-                )
289
-            );
290
-            if ($question_groups) {
291
-                // array of params to pass to parent constructor
292
-                $form_args = array(
293
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
294
-                    'html_class'      => 'ee-reg-form-attendee-dv',
295
-                    'html_style'      => $this->checkout->admin_request
296
-                        ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
297
-                        : '',
298
-                    'subsections'     => array(),
299
-                    'layout_strategy' => new EE_Fieldset_Section_Layout(
300
-                        array(
301
-                            'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
302
-                            'legend_text'  => sprintf(
303
-                                esc_html_x(
304
-                                    'Attendee %d',
305
-                                    'Attendee 123',
306
-                                    'event_espresso'
307
-                                ),
308
-                                $attendee_nmbr
309
-                            ),
310
-                        )
311
-                    ),
312
-                );
313
-                foreach ($question_groups as $question_group) {
314
-                    if ($question_group instanceof EE_Question_Group) {
315
-                        $form_args['subsections'][ $question_group->identifier() ] = $this->_question_group_reg_form(
316
-                            $registration,
317
-                            $question_group
318
-                        );
319
-                    }
320
-                }
321
-                // add hidden input
322
-                $form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
323
-                    $registration
324
-                );
325
-                // if we have question groups for additional attendees, then display the copy options
326
-                $this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
327
-                if ($registration->is_primary_registrant()) {
328
-                    // generate hidden input
329
-                    $form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
330
-                        $registration
331
-                    );
332
-                }
333
-            }
334
-        }
335
-        $attendee_nmbr++;
336
-        return ! empty($form_args)
337
-            ? new EE_Form_Section_Proper($form_args)
338
-            : new EE_Form_Section_HTML();
339
-    }
340
-
341
-
342
-    /**
343
-     * @param EE_Registration $registration
344
-     * @param bool            $additional_attendee_reg_info
345
-     * @return EE_Form_Input_Base
346
-     * @throws EE_Error
347
-     */
348
-    private function _additional_attendee_reg_info_input(
349
-        EE_Registration $registration,
350
-        $additional_attendee_reg_info = true
351
-    ) {
352
-        // generate hidden input
353
-        return new EE_Hidden_Input(
354
-            array(
355
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
356
-                'default' => $additional_attendee_reg_info,
357
-            )
358
-        );
359
-    }
360
-
361
-
362
-    /**
363
-     * @param EE_Registration   $registration
364
-     * @param EE_Question_Group $question_group
365
-     * @return EE_Form_Section_Proper
366
-     * @throws EE_Error
367
-     * @throws InvalidArgumentException
368
-     * @throws InvalidDataTypeException
369
-     * @throws InvalidInterfaceException
370
-     * @throws ReflectionException
371
-     */
372
-    private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
373
-    {
374
-        // array of params to pass to parent constructor
375
-        $form_args = array(
376
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
377
-            'html_class'      => $this->checkout->admin_request
378
-                ? 'form-table ee-reg-form-qstn-grp-dv'
379
-                : 'ee-reg-form-qstn-grp-dv',
380
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-'
381
-                                 . $registration->ID() . '-lbl',
382
-            'subsections'     => array(
383
-                'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
384
-            ),
385
-            'layout_strategy' => $this->checkout->admin_request
386
-                ? new EE_Admin_Two_Column_Layout()
387
-                : new EE_Div_Per_Section_Layout(),
388
-        );
389
-        // where params
390
-        $query_params = array('QST_deleted' => 0);
391
-        // don't load admin only questions on the frontend
392
-        if (! $this->checkout->admin_request) {
393
-            $query_params['QST_admin_only'] = array('!=', true);
394
-        }
395
-        $questions = $question_group->get_many_related(
396
-            'Question',
397
-            apply_filters(
398
-                'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
399
-                array(
400
-                    $query_params,
401
-                    'order_by' => array(
402
-                        'Question_Group_Question.QGQ_order' => 'ASC',
403
-                    ),
404
-                ),
405
-                $question_group,
406
-                $registration,
407
-                $this
408
-            )
409
-        );
410
-        // filter for additional content before questions
411
-        $form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
412
-            apply_filters(
413
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
414
-                '',
415
-                $registration,
416
-                $question_group,
417
-                $this
418
-            )
419
-        );
420
-        // loop thru questions
421
-        foreach ($questions as $question) {
422
-            if ($question instanceof EE_Question) {
423
-                $identifier = $question->is_system_question()
424
-                    ? $question->system_ID()
425
-                    : $question->ID();
426
-                $form_args['subsections'][ $identifier ] = $this->reg_form_question($registration, $question);
427
-            }
428
-        }
429
-        $form_args['subsections'] = apply_filters(
430
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
431
-            $form_args['subsections'],
432
-            $registration,
433
-            $question_group,
434
-            $this
435
-        );
436
-        // filter for additional content after questions
437
-        $form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
438
-            apply_filters(
439
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
440
-                '',
441
-                $registration,
442
-                $question_group,
443
-                $this
444
-            )
445
-        );
446
-        // d($form_args);
447
-        $question_group_reg_form = new EE_Form_Section_Proper($form_args);
448
-        return apply_filters(
449
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
450
-            $question_group_reg_form,
451
-            $registration,
452
-            $question_group,
453
-            $this
454
-        );
455
-    }
456
-
457
-
458
-    /**
459
-     * @param EE_Question_Group $question_group
460
-     * @return    EE_Form_Section_HTML
461
-     */
462
-    private function _question_group_header(EE_Question_Group $question_group)
463
-    {
464
-        $html = '';
465
-        // group_name
466
-        if ($question_group->show_group_name() && $question_group->name() !== '') {
467
-            if ($this->checkout->admin_request) {
468
-                $html .= EEH_HTML::br();
469
-                $html .= EEH_HTML::h3(
470
-                    $question_group->name(),
471
-                    '',
472
-                    'ee-reg-form-qstn-grp-title title',
473
-                    'font-size: 1.3em; padding-left:0;'
474
-                );
475
-            } else {
476
-                $html .= EEH_HTML::h4(
477
-                    $question_group->name(),
478
-                    '',
479
-                    'ee-reg-form-qstn-grp-title section-title'
480
-                );
481
-            }
482
-        }
483
-        // group_desc
484
-        if ($question_group->show_group_desc() && $question_group->desc() !== '') {
485
-            $html .= EEH_HTML::p(
486
-                $question_group->desc(),
487
-                '',
488
-                $this->checkout->admin_request
489
-                    ? 'ee-reg-form-qstn-grp-desc-pg'
490
-                    : 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
491
-            );
492
-        }
493
-        return new EE_Form_Section_HTML($html);
494
-    }
495
-
496
-
497
-    /**
498
-     * @return    EE_Form_Section_Proper
499
-     * @throws EE_Error
500
-     * @throws InvalidArgumentException
501
-     * @throws ReflectionException
502
-     * @throws InvalidDataTypeException
503
-     * @throws InvalidInterfaceException
504
-     */
505
-    private function _copy_attendee_info_form()
506
-    {
507
-        // array of params to pass to parent constructor
508
-        return new EE_Form_Section_Proper(
509
-            array(
510
-                'subsections'     => $this->_copy_attendee_info_inputs(),
511
-                'layout_strategy' => new EE_Template_Layout(
512
-                    array(
513
-                        'layout_template_file'     => SPCO_REG_STEPS_PATH
514
-                                                      . $this->_slug
515
-                                                      . DS
516
-                                                      . 'copy_attendee_info.template.php',
517
-                        'begin_template_file'      => null,
518
-                        'input_template_file'      => null,
519
-                        'subsection_template_file' => null,
520
-                        'end_template_file'        => null,
521
-                    )
522
-                ),
523
-            )
524
-        );
525
-    }
526
-
527
-
528
-    /**
529
-     * @return EE_Form_Section_HTML
530
-     * @throws DomainException
531
-     * @throws InvalidArgumentException
532
-     * @throws InvalidDataTypeException
533
-     * @throws InvalidInterfaceException
534
-     */
535
-    private function _auto_copy_attendee_info()
536
-    {
537
-        return new EE_Form_Section_HTML(
538
-            EEH_Template::locate_template(
539
-                SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
540
-                apply_filters(
541
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
542
-                    array()
543
-                ),
544
-                true,
545
-                true
546
-            )
547
-        );
548
-    }
549
-
550
-
551
-    /**
552
-     * @return array
553
-     * @throws EE_Error
554
-     * @throws InvalidArgumentException
555
-     * @throws ReflectionException
556
-     * @throws InvalidDataTypeException
557
-     * @throws InvalidInterfaceException
558
-     */
559
-    private function _copy_attendee_info_inputs()
560
-    {
561
-        $copy_attendee_info_inputs = array();
562
-        $prev_ticket = null;
563
-        // grab the saved registrations from the transaction
564
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
565
-        foreach ($registrations as $registration) {
566
-            // for all  attendees other than the primary attendee
567
-            if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
568
-                // if this is a new ticket OR if this is the very first additional attendee after the primary attendee
569
-                if ($registration->ticket()->ID() !== $prev_ticket) {
570
-                    $item_name = $registration->ticket()->name();
571
-                    $item_name .= $registration->ticket()->description() !== ''
572
-                        ? ' - ' . $registration->ticket()->description()
573
-                        : '';
574
-                    $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID(
575
-                    ) . ']' ] =
576
-                        new EE_Form_Section_HTML(
577
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
578
-                        );
579
-                    $prev_ticket = $registration->ticket()->ID();
580
-                }
581
-
582
-                $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[' . $registration->ID() . ']' ] =
583
-                    new EE_Checkbox_Multi_Input(
584
-                        array(
585
-                            $registration->ID() => sprintf(
586
-                                esc_html_x('Attendee #%s', 'Attendee #123', 'event_espresso'),
587
-                                $registration->count()
588
-                            ),
589
-                        ),
590
-                        array(
591
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
592
-                            'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
593
-                            'display_html_label_text' => false,
594
-                        )
595
-                    );
596
-            }
597
-        }
598
-        return $copy_attendee_info_inputs;
599
-    }
600
-
601
-
602
-    /**
603
-     * @param EE_Registration $registration
604
-     * @return    EE_Form_Input_Base
605
-     * @throws EE_Error
606
-     */
607
-    private function _additional_primary_registrant_inputs(EE_Registration $registration)
608
-    {
609
-        // generate hidden input
610
-        return new EE_Hidden_Input(
611
-            array(
612
-                'html_id' => 'primary_registrant',
613
-                'default' => $registration->reg_url_link(),
614
-            )
615
-        );
616
-    }
617
-
618
-
619
-    /**
620
-     * @param EE_Registration $registration
621
-     * @param EE_Question     $question
622
-     * @return EE_Form_Input_Base
623
-     * @throws EE_Error
624
-     * @throws InvalidArgumentException
625
-     * @throws InvalidDataTypeException
626
-     * @throws InvalidInterfaceException
627
-     * @throws ReflectionException
628
-     */
629
-    public function reg_form_question(EE_Registration $registration, EE_Question $question)
630
-    {
631
-
632
-        // if this question was for an attendee detail, then check for that answer
633
-        $answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
634
-            $registration,
635
-            $question->system_ID()
636
-        );
637
-        $answer = $answer_value === null
638
-            ? EEM_Answer::instance()->get_one(
639
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
640
-            )
641
-            : null;
642
-        // if NOT returning to edit an existing registration
643
-        // OR if this question is for an attendee property
644
-        // OR we still don't have an EE_Answer object
645
-        if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
646
-            // create an EE_Answer object for storing everything in
647
-            $answer = EE_Answer::new_instance(
648
-                array(
649
-                    'QST_ID' => $question->ID(),
650
-                    'REG_ID' => $registration->ID(),
651
-                )
652
-            );
653
-        }
654
-        // verify instance
655
-        if ($answer instanceof EE_Answer) {
656
-            if (! empty($answer_value)) {
657
-                $answer->set('ANS_value', $answer_value);
658
-            }
659
-            $answer->cache('Question', $question);
660
-            // remember system ID had a bug where sometimes it could be null
661
-            $answer_cache_id = $question->is_system_question()
662
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
663
-                : $question->ID() . '-' . $registration->reg_url_link();
664
-            $registration->cache('Answer', $answer, $answer_cache_id);
665
-        }
666
-        return $this->_generate_question_input($registration, $question, $answer);
667
-    }
668
-
669
-
670
-    /**
671
-     * @param EE_Registration $registration
672
-     * @param EE_Question     $question
673
-     * @param                 $answer
674
-     * @return EE_Form_Input_Base
675
-     * @throws EE_Error
676
-     * @throws InvalidArgumentException
677
-     * @throws ReflectionException
678
-     * @throws InvalidDataTypeException
679
-     * @throws InvalidInterfaceException
680
-     */
681
-    private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
682
-    {
683
-        $identifier = $question->is_system_question()
684
-            ? $question->system_ID()
685
-            : $question->ID();
686
-        $this->_required_questions[ $identifier ] = $question->required() ? true : false;
687
-        add_filter(
688
-            'FHEE__EE_Question__generate_form_input__country_options',
689
-            array($this, 'use_cached_countries_for_form_input'),
690
-            10,
691
-            4
692
-        );
693
-        add_filter(
694
-            'FHEE__EE_Question__generate_form_input__state_options',
695
-            array($this, 'use_cached_states_for_form_input'),
696
-            10,
697
-            4
698
-        );
699
-        $input_constructor_args = array(
700
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
701
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
702
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
703
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
704
-            'html_label_class' => 'ee-reg-qstn',
705
-        );
706
-        $input_constructor_args['html_label_id'] .= '-lbl';
707
-        if ($answer instanceof EE_Answer && $answer->ID()) {
708
-            $input_constructor_args['html_name'] .= '[' . $answer->ID() . ']';
709
-            $input_constructor_args['html_id'] .= '-' . $answer->ID();
710
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
711
-        }
712
-        $form_input = $question->generate_form_input(
713
-            $registration,
714
-            $answer,
715
-            $input_constructor_args
716
-        );
717
-        remove_filter(
718
-            'FHEE__EE_Question__generate_form_input__country_options',
719
-            array($this, 'use_cached_countries_for_form_input')
720
-        );
721
-        remove_filter(
722
-            'FHEE__EE_Question__generate_form_input__state_options',
723
-            array($this, 'use_cached_states_for_form_input')
724
-        );
725
-        return $form_input;
726
-    }
727
-
728
-
729
-    /**
730
-     * Gets the list of countries for the form input
731
-     *
732
-     * @param array|null      $countries_list
733
-     * @param EE_Question     $question
734
-     * @param EE_Registration $registration
735
-     * @param EE_Answer       $answer
736
-     * @return array 2d keys are country IDs, values are their names
737
-     * @throws EE_Error
738
-     * @throws InvalidArgumentException
739
-     * @throws InvalidDataTypeException
740
-     * @throws InvalidInterfaceException
741
-     * @throws ReflectionException
742
-     */
743
-    public function use_cached_countries_for_form_input(
744
-        $countries_list,
745
-        EE_Question $question = null,
746
-        EE_Registration $registration = null,
747
-        EE_Answer $answer = null
748
-    ) {
749
-        $country_options = array('' => '');
750
-        // get possibly cached list of countries
751
-        $countries = $this->checkout->action === 'process_reg_step'
752
-            ? EEM_Country::instance()->get_all_countries()
753
-            : EEM_Country::instance()->get_all_active_countries();
754
-        if (! empty($countries)) {
755
-            foreach ($countries as $country) {
756
-                if ($country instanceof EE_Country) {
757
-                    $country_options[ $country->ID() ] = $country->name();
758
-                }
759
-            }
760
-        }
761
-        if ($question instanceof EE_Question && $registration instanceof EE_Registration) {
762
-            $answer = EEM_Answer::instance()->get_one(
763
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
764
-            );
765
-        } else {
766
-            $answer = EE_Answer::new_instance();
767
-        }
768
-        $country_options = apply_filters(
769
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
770
-            $country_options,
771
-            $this,
772
-            $registration,
773
-            $question,
774
-            $answer
775
-        );
776
-        return $country_options;
777
-    }
778
-
779
-
780
-    /**
781
-     * Gets the list of states for the form input
782
-     *
783
-     * @param array|null      $states_list
784
-     * @param EE_Question     $question
785
-     * @param EE_Registration $registration
786
-     * @param EE_Answer       $answer
787
-     * @return array 2d keys are state IDs, values are their names
788
-     * @throws EE_Error
789
-     * @throws InvalidArgumentException
790
-     * @throws InvalidDataTypeException
791
-     * @throws InvalidInterfaceException
792
-     * @throws ReflectionException
793
-     */
794
-    public function use_cached_states_for_form_input(
795
-        $states_list,
796
-        EE_Question $question = null,
797
-        EE_Registration $registration = null,
798
-        EE_Answer $answer = null
799
-    ) {
800
-        $state_options = array('' => array('' => ''));
801
-        $states = $this->checkout->action === 'process_reg_step'
802
-            ? EEM_State::instance()->get_all_states()
803
-            : EEM_State::instance()->get_all_active_states();
804
-        if (! empty($states)) {
805
-            foreach ($states as $state) {
806
-                if ($state instanceof EE_State) {
807
-                    $state_options[ $state->country()->name() ][ $state->ID() ] = $state->name();
808
-                }
809
-            }
810
-        }
811
-        $state_options = apply_filters(
812
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
813
-            $state_options,
814
-            $this,
815
-            $registration,
816
-            $question,
817
-            $answer
818
-        );
819
-        return $state_options;
820
-    }
821
-
822
-
823
-    /********************************************************************************************************/
824
-    /****************************************  PROCESS REG STEP  ****************************************/
825
-    /********************************************************************************************************/
826
-
827
-
828
-    /**
829
-     * @return bool
830
-     * @throws EE_Error
831
-     * @throws InvalidArgumentException
832
-     * @throws ReflectionException
833
-     * @throws RuntimeException
834
-     * @throws InvalidDataTypeException
835
-     * @throws InvalidInterfaceException
836
-     */
837
-    public function process_reg_step()
838
-    {
839
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
840
-        // grab validated data from form
841
-        $valid_data = $this->checkout->current_step->valid_data();
842
-        // EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
843
-        // EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
844
-        // if we don't have any $valid_data then something went TERRIBLY WRONG !!!
845
-        if (empty($valid_data)) {
846
-            EE_Error::add_error(
847
-                esc_html__('No valid question responses were received.', 'event_espresso'),
848
-                __FILE__,
849
-                __FUNCTION__,
850
-                __LINE__
851
-            );
852
-            return false;
853
-        }
854
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
855
-            EE_Error::add_error(
856
-                esc_html__(
857
-                    'A valid transaction could not be initiated for processing your registrations.',
858
-                    'event_espresso'
859
-                ),
860
-                __FILE__,
861
-                __FUNCTION__,
862
-                __LINE__
863
-            );
864
-            return false;
865
-        }
866
-        // get cached registrations
867
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
868
-        // verify we got the goods
869
-        if (empty($registrations)) {
870
-            // combine the old translated string with a new one, in order to not break translations
871
-            $error_message = esc_html__(
872
-                'Your form data could not be applied to any valid registrations.',
873
-                'event_espresso'
874
-            )
875
-            . sprintf(
876
-                esc_html_x(
877
-                    '%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.',
878
-                    '(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
879
-                    'event_espresso'
880
-                ),
881
-                '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
882
-                '</a>',
883
-                '<br />'
884
-            );
885
-            EE_Error::add_error(
886
-                $error_message,
887
-                __FILE__,
888
-                __FUNCTION__,
889
-                __LINE__
890
-            );
891
-            return false;
892
-        }
893
-        // extract attendee info from form data and save to model objects
894
-        $registrations_processed = $this->_process_registrations($registrations, $valid_data);
895
-        // if first pass thru SPCO,
896
-        // then let's check processed registrations against the total number of tickets in the cart
897
-        if ($registrations_processed === false) {
898
-            // but return immediately if the previous step exited early due to errors
899
-            return false;
900
-        }
901
-        if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
902
-            // generate a correctly translated string for all possible singular/plural combinations
903
-            if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
904
-                $error_msg = sprintf(
905
-                    esc_html_x(
906
-                        'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
907
-                        'There was 1 ticket in the Event Queue, but 2 registrations were processed',
908
-                        'event_espresso'
909
-                    ),
910
-                    $this->checkout->total_ticket_count,
911
-                    $registrations_processed
912
-                );
913
-            } elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
914
-                $error_msg = sprintf(
915
-                    esc_html_x(
916
-                        'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
917
-                        'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
918
-                        'event_espresso'
919
-                    ),
920
-                    $this->checkout->total_ticket_count,
921
-                    $registrations_processed
922
-                );
923
-            } else {
924
-                $error_msg = sprintf(
925
-                    esc_html__(
926
-                        'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
927
-                        'event_espresso'
928
-                    ),
929
-                    $this->checkout->total_ticket_count,
930
-                    $registrations_processed
931
-                );
932
-            }
933
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
934
-            return false;
935
-        }
936
-        // mark this reg step as completed
937
-        $this->set_completed();
938
-        $this->_set_success_message(
939
-            esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
940
-        );
941
-        // do action in case a plugin wants to do something with the data submitted in step 1.
942
-        // passes EE_Single_Page_Checkout, and it's posted data
943
-        do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
944
-        return true;
945
-    }
946
-
947
-
948
-    /**
949
-     *    _process_registrations
950
-     *
951
-     * @param EE_Registration[] $registrations
952
-     * @param array[][]         $valid_data
953
-     * @return bool|int
954
-     * @throws EntityNotFoundException
955
-     * @throws EE_Error
956
-     * @throws InvalidArgumentException
957
-     * @throws ReflectionException
958
-     * @throws RuntimeException
959
-     * @throws InvalidDataTypeException
960
-     * @throws InvalidInterfaceException
961
-     */
962
-    private function _process_registrations($registrations = array(), $valid_data = array())
963
-    {
964
-        // load resources and set some defaults
965
-        EE_Registry::instance()->load_model('Attendee');
966
-        // holder for primary registrant attendee object
967
-        $this->checkout->primary_attendee_obj = null;
968
-        // array for tracking reg form data for the primary registrant
969
-        $primary_registrant = array(
970
-            'line_item_id' => null,
971
-        );
972
-        $copy_primary = false;
973
-        // reg form sections that do not contain inputs
974
-        $non_input_form_sections = array(
975
-            'primary_registrant',
976
-            'additional_attendee_reg_info',
977
-            'spco_copy_attendee_chk',
978
-        );
979
-        // attendee counter
980
-        $att_nmbr = 0;
981
-        // grab the saved registrations from the transaction
982
-        foreach ($registrations as $registration) {
983
-            // verify EE_Registration object
984
-            if (! $registration instanceof EE_Registration) {
985
-                EE_Error::add_error(
986
-                    esc_html__(
987
-                        'An invalid Registration object was discovered when attempting to process your registration information.',
988
-                        'event_espresso'
989
-                    ),
990
-                    __FILE__,
991
-                    __FUNCTION__,
992
-                    __LINE__
993
-                );
994
-                return false;
995
-            }
996
-            /** @var string $reg_url_link */
997
-            $reg_url_link = $registration->reg_url_link();
998
-            // reg_url_link exists ?
999
-            if (! empty($reg_url_link)) {
1000
-                // should this registration be processed during this visit ?
1001
-                if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
1002
-                    // if NOT revisiting, then let's save the registration now,
1003
-                    // so that we have a REG_ID to use when generating other objects
1004
-                    if (! $this->checkout->revisit) {
1005
-                        $registration->save();
1006
-                    }
1007
-                    /**
1008
-                     * This allows plugins to trigger a fail on processing of a
1009
-                     * registration for any conditions they may have for it to pass.
1010
-                     *
1011
-                     * @var bool   if true is returned by the plugin then the
1012
-                     *            registration processing is halted.
1013
-                     */
1014
-                    if (apply_filters(
1015
-                        'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
1016
-                        false,
1017
-                        $att_nmbr,
1018
-                        $registration,
1019
-                        $registrations,
1020
-                        $valid_data,
1021
-                        $this
1022
-                    )) {
1023
-                        return false;
1024
-                    }
1025
-
1026
-                    // Houston, we have a registration!
1027
-                    $att_nmbr++;
1028
-                    $this->_attendee_data[ $reg_url_link ] = array();
1029
-                    // grab any existing related answer objects
1030
-                    $this->_registration_answers = $registration->answers();
1031
-                    // unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
1032
-                    if (isset($valid_data[ $reg_url_link ])) {
1033
-                        // do we need to copy basic info from primary attendee ?
1034
-                        $copy_primary = isset($valid_data[ $reg_url_link ]['additional_attendee_reg_info'])
1035
-                                        && absint($valid_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
1036
-                        // filter form input data for this registration
1037
-                        $valid_data[ $reg_url_link ] = (array) apply_filters(
1038
-                            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
1039
-                            $valid_data[ $reg_url_link ]
1040
-                        );
1041
-                        if (isset($valid_data['primary_attendee'])) {
1042
-                            $primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
1043
-                                ? $valid_data['primary_attendee']
1044
-                                : false;
1045
-                            unset($valid_data['primary_attendee']);
1046
-                        }
1047
-                        // now loop through our array of valid post data && process attendee reg forms
1048
-                        foreach ($valid_data[ $reg_url_link ] as $form_section => $form_inputs) {
1049
-                            if (! in_array($form_section, $non_input_form_sections, true)) {
1050
-                                foreach ($form_inputs as $form_input => $input_value) {
1051
-                                    // \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
1052
-                                    // check for critical inputs
1053
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1054
-                                        $form_input,
1055
-                                        $input_value
1056
-                                    )
1057
-                                    ) {
1058
-                                        return false;
1059
-                                    }
1060
-                                    // store a bit of data about the primary attendee
1061
-                                    if ($att_nmbr === 1
1062
-                                        && ! empty($input_value)
1063
-                                        && $reg_url_link === $primary_registrant['line_item_id']
1064
-                                    ) {
1065
-                                        $primary_registrant[ $form_input ] = $input_value;
1066
-                                    } elseif ($copy_primary
1067
-                                              && $input_value === null
1068
-                                              && isset($primary_registrant[ $form_input ])
1069
-                                    ) {
1070
-                                        $input_value = $primary_registrant[ $form_input ];
1071
-                                    }
1072
-                                    // now attempt to save the input data
1073
-                                    if (! $this->_save_registration_form_input(
1074
-                                        $registration,
1075
-                                        $form_input,
1076
-                                        $input_value
1077
-                                    )
1078
-                                    ) {
1079
-                                        EE_Error::add_error(
1080
-                                            sprintf(
1081
-                                                esc_html_x(
1082
-                                                    'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1083
-                                                    'Unable to save registration form data for the form input: "form input name" with the submitted value: "form input value"',
1084
-                                                    'event_espresso'
1085
-                                                ),
1086
-                                                $form_input,
1087
-                                                $input_value
1088
-                                            ),
1089
-                                            __FILE__,
1090
-                                            __FUNCTION__,
1091
-                                            __LINE__
1092
-                                        );
1093
-                                        return false;
1094
-                                    }
1095
-                                }
1096
-                            }
1097
-                        }  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1098
-                    }
1099
-                    // EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1100
-                    // this registration does not require additional attendee information ?
1101
-                    if ($copy_primary
1102
-                        && $att_nmbr > 1
1103
-                        && $this->checkout->primary_attendee_obj instanceof EE_Attendee
1104
-                    ) {
1105
-                        // just copy the primary registrant
1106
-                        $attendee = $this->checkout->primary_attendee_obj;
1107
-                    } else {
1108
-                        // ensure critical details are set for additional attendees
1109
-                        $this->_attendee_data[ $reg_url_link ] = $att_nmbr > 1
1110
-                            ? $this->_copy_critical_attendee_details_from_primary_registrant(
1111
-                                $this->_attendee_data[ $reg_url_link ]
1112
-                            )
1113
-                            : $this->_attendee_data[ $reg_url_link ];
1114
-                        // execute create attendee command (which may return an existing attendee)
1115
-                        $attendee = EE_Registry::instance()->BUS->execute(
1116
-                            new CreateAttendeeCommand(
1117
-                                $this->_attendee_data[ $reg_url_link ],
1118
-                                $registration
1119
-                            )
1120
-                        );
1121
-                        // who's #1 ?
1122
-                        if ($att_nmbr === 1) {
1123
-                            $this->checkout->primary_attendee_obj = $attendee;
1124
-                        }
1125
-                    }
1126
-                    // EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1127
-                    // add relation to registration, set attendee ID, and cache attendee
1128
-                    $this->_associate_attendee_with_registration($registration, $attendee);
1129
-                    // \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1130
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1131
-                        EE_Error::add_error(
1132
-                            sprintf(
1133
-                                esc_html_x(
1134
-                                    'Registration %s has an invalid or missing Attendee object.',
1135
-                                    'Registration 123-456-789 has an invalid or missing Attendee object.',
1136
-                                    'event_espresso'
1137
-                                ),
1138
-                                $reg_url_link
1139
-                            ),
1140
-                            __FILE__,
1141
-                            __FUNCTION__,
1142
-                            __LINE__
1143
-                        );
1144
-                        return false;
1145
-                    }
1146
-                    /** @type EE_Registration_Processor $registration_processor */
1147
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1148
-                    // at this point, we should have enough details about the registrant to consider the registration
1149
-                    // NOT incomplete
1150
-                    $registration_processor->toggle_incomplete_registration_status_to_default(
1151
-                        $registration,
1152
-                        false,
1153
-                        new Context(
1154
-                            'spco_reg_step_attendee_information_process_registrations',
1155
-                            esc_html__(
1156
-                                'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1157
-                                'event_espresso'
1158
-                            )
1159
-                        )
1160
-                    );
1161
-                    // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1162
-                    // abandoned
1163
-                    $this->checkout->transaction->toggle_failed_transaction_status();
1164
-                    // if we've gotten this far, then let's save what we have
1165
-                    $registration->save();
1166
-                    // add relation between TXN and registration
1167
-                    $this->_associate_registration_with_transaction($registration);
1168
-                }
1169
-            } else {
1170
-                EE_Error::add_error(
1171
-                    esc_html__(
1172
-                        'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1173
-                        'event_espresso'
1174
-                    ),
1175
-                    __FILE__,
1176
-                    __FUNCTION__,
1177
-                    __LINE__
1178
-                );
1179
-                // remove malformed data
1180
-                unset($valid_data[ $reg_url_link ]);
1181
-                return false;
1182
-            }
1183
-        } // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1184
-        return $att_nmbr;
1185
-    }
1186
-
1187
-
1188
-    /**
1189
-     *    _save_registration_form_input
1190
-     *
1191
-     * @param EE_Registration $registration
1192
-     * @param string          $form_input
1193
-     * @param string          $input_value
1194
-     * @return bool
1195
-     * @throws EE_Error
1196
-     * @throws InvalidArgumentException
1197
-     * @throws InvalidDataTypeException
1198
-     * @throws InvalidInterfaceException
1199
-     * @throws ReflectionException
1200
-     */
1201
-    private function _save_registration_form_input(
1202
-        EE_Registration $registration,
1203
-        $form_input = '',
1204
-        $input_value = ''
1205
-    ) {
1206
-        // \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1207
-        // \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1208
-        // \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1209
-        // allow for plugins to hook in and do their own processing of the form input.
1210
-        // For plugins to bypass normal processing here, they just need to return a boolean value.
1211
-        if (apply_filters(
1212
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1213
-            false,
1214
-            $registration,
1215
-            $form_input,
1216
-            $input_value,
1217
-            $this
1218
-        )) {
1219
-            return true;
1220
-        }
1221
-        /*
21
+	/**
22
+	 * @type bool $_print_copy_info
23
+	 */
24
+	private $_print_copy_info = false;
25
+
26
+	/**
27
+	 * @type array $_attendee_data
28
+	 */
29
+	private $_attendee_data = array();
30
+
31
+	/**
32
+	 * @type array $_required_questions
33
+	 */
34
+	private $_required_questions = array();
35
+
36
+	/**
37
+	 * @type array $_registration_answers
38
+	 */
39
+	private $_registration_answers = array();
40
+
41
+
42
+	/**
43
+	 *    class constructor
44
+	 *
45
+	 * @access    public
46
+	 * @param    EE_Checkout $checkout
47
+	 */
48
+	public function __construct(EE_Checkout $checkout)
49
+	{
50
+		$this->_slug = 'attendee_information';
51
+		$this->_name = esc_html__('Attendee Information', 'event_espresso');
52
+		$this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
53
+		$this->checkout = $checkout;
54
+		$this->_reset_success_message();
55
+		$this->set_instructions(
56
+			esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
57
+		);
58
+	}
59
+
60
+
61
+	public function translate_js_strings()
62
+	{
63
+		EE_Registry::$i18n_js_strings['required_field'] = esc_html__(
64
+			' is a required question.',
65
+			'event_espresso'
66
+		);
67
+		EE_Registry::$i18n_js_strings['required_multi_field'] = esc_html__(
68
+			' is a required question. Please enter a value for at least one of the options.',
69
+			'event_espresso'
70
+		);
71
+		EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
72
+			'Please answer all required questions correctly before proceeding.',
73
+			'event_espresso'
74
+		);
75
+		EE_Registry::$i18n_js_strings['attendee_info_copied'] = sprintf(
76
+			esc_html_x(
77
+				'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
78
+				'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
79
+				'event_espresso'
80
+			),
81
+			'<br/>'
82
+		);
83
+		EE_Registry::$i18n_js_strings['attendee_info_copy_error'] = esc_html__(
84
+			'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
85
+			'event_espresso'
86
+		);
87
+		EE_Registry::$i18n_js_strings['enter_valid_email'] = esc_html__(
88
+			'You must enter a valid email address.',
89
+			'event_espresso'
90
+		);
91
+		EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
92
+			'You must enter a valid email address and answer all other required questions before you can proceed.',
93
+			'event_espresso'
94
+		);
95
+	}
96
+
97
+
98
+	public function enqueue_styles_and_scripts()
99
+	{
100
+	}
101
+
102
+
103
+	/**
104
+	 * @return boolean
105
+	 */
106
+	public function initialize_reg_step()
107
+	{
108
+		return true;
109
+	}
110
+
111
+
112
+	/**
113
+	 * @return EE_Form_Section_Proper
114
+	 * @throws DomainException
115
+	 * @throws EE_Error
116
+	 * @throws InvalidArgumentException
117
+	 * @throws ReflectionException
118
+	 * @throws EntityNotFoundException
119
+	 * @throws InvalidDataTypeException
120
+	 * @throws InvalidInterfaceException
121
+	 */
122
+	public function generate_reg_form()
123
+	{
124
+		$this->_print_copy_info = false;
125
+		$primary_registrant = null;
126
+		// autoload Line_Item_Display classes
127
+		EEH_Autoloader::register_line_item_display_autoloaders();
128
+		$Line_Item_Display = new EE_Line_Item_Display();
129
+		// calculate taxes
130
+		$Line_Item_Display->display_line_item(
131
+			$this->checkout->cart->get_grand_total(),
132
+			array('set_tax_rate' => true)
133
+		);
134
+		/** @var $subsections EE_Form_Section_Proper[] */
135
+		$extra_inputs_section = $this->reg_step_hidden_inputs();
136
+		$subsections = array(
137
+			'default_hidden_inputs' => $extra_inputs_section,
138
+		);
139
+
140
+		/**
141
+		 * @var $reg_config EE_Registration_Config
142
+		 */
143
+		$reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
144
+		// if this isn't a revisit, and they have the privacy consent box enalbed, add it
145
+		if (! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
146
+			$extra_inputs_section->add_subsections(
147
+				array(
148
+					'consent_box' => new EE_Form_Section_Proper(
149
+						array(
150
+							'layout_strategy' =>
151
+								new EE_Template_Layout(
152
+									array(
153
+										'input_template_file' => SPCO_REG_STEPS_PATH . $this->_slug . DS . 'privacy_consent.template.php',
154
+									)
155
+								),
156
+							'subsections'     => array(
157
+								'consent' => new EE_Checkbox_Multi_Input(
158
+									array(
159
+										'consent' => $reg_config->getConsentCheckboxLabelText(),
160
+									),
161
+									array(
162
+										'required'                          => true,
163
+										'required_validation_error_message' => esc_html__(
164
+											'You must consent to these terms in order to register.',
165
+											'event_espresso'
166
+										),
167
+										'html_label_text'                   => '',
168
+									)
169
+								),
170
+							),
171
+						)
172
+					),
173
+				),
174
+				null,
175
+				false
176
+			);
177
+		}
178
+		$template_args = array(
179
+			'revisit'       => $this->checkout->revisit,
180
+			'registrations' => array(),
181
+			'ticket_count'  => array(),
182
+		);
183
+		// grab the saved registrations from the transaction
184
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
185
+		if ($registrations) {
186
+			foreach ($registrations as $registration) {
187
+				// can this registration be processed during this visit ?
188
+				if ($registration instanceof EE_Registration
189
+					&& $this->checkout->visit_allows_processing_of_this_registration($registration)
190
+				) {
191
+					$subsections[ $registration->reg_url_link() ] = $this->_registrations_reg_form($registration);
192
+					if (! $this->checkout->admin_request) {
193
+						$template_args['registrations'][ $registration->reg_url_link() ] = $registration;
194
+						$template_args['ticket_count'][ $registration->ticket()->ID() ] = isset(
195
+							$template_args['ticket_count'][ $registration->ticket()->ID() ]
196
+						)
197
+							? $template_args['ticket_count'][ $registration->ticket()->ID() ] + 1
198
+							: 1;
199
+						$ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
200
+							$this->checkout->cart->get_grand_total(),
201
+							'Ticket',
202
+							array($registration->ticket()->ID())
203
+						);
204
+						$ticket_line_item = is_array($ticket_line_item)
205
+							? reset($ticket_line_item)
206
+							: $ticket_line_item;
207
+						$template_args['ticket_line_item'][ $registration->ticket()->ID() ] =
208
+							$Line_Item_Display->display_line_item($ticket_line_item);
209
+					}
210
+					if ($registration->is_primary_registrant()) {
211
+						$primary_registrant = $registration->reg_url_link();
212
+					}
213
+				}
214
+			}
215
+			// print_copy_info ?
216
+			if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
217
+				// TODO: add admin option for toggling copy attendee info,
218
+				// then use that value to change $this->_print_copy_info
219
+				$copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
220
+					? $this->_copy_attendee_info_form()
221
+					: $this->_auto_copy_attendee_info();
222
+				// generate hidden input
223
+				if (isset($subsections[ $primary_registrant ])
224
+					&& $subsections[ $primary_registrant ] instanceof EE_Form_Section_Proper
225
+				) {
226
+					$subsections[ $primary_registrant ]->add_subsections(
227
+						$copy_options,
228
+						'primary_registrant',
229
+						false
230
+					);
231
+				}
232
+			}
233
+		}
234
+		return new EE_Form_Section_Proper(
235
+			array(
236
+				'name'            => $this->reg_form_name(),
237
+				'html_id'         => $this->reg_form_name(),
238
+				'subsections'     => $subsections,
239
+				'layout_strategy' => $this->checkout->admin_request
240
+					?
241
+					new EE_Div_Per_Section_Layout()
242
+					:
243
+					new EE_Template_Layout(
244
+						array(
245
+							'layout_template_file' => $this->_template, // layout_template
246
+							'template_args'        => $template_args,
247
+						)
248
+					),
249
+			)
250
+		);
251
+	}
252
+
253
+
254
+	/**
255
+	 * @param EE_Registration $registration
256
+	 * @return EE_Form_Section_Base
257
+	 * @throws EE_Error
258
+	 * @throws InvalidArgumentException
259
+	 * @throws EntityNotFoundException
260
+	 * @throws InvalidDataTypeException
261
+	 * @throws InvalidInterfaceException
262
+	 * @throws ReflectionException
263
+	 */
264
+	private function _registrations_reg_form(EE_Registration $registration)
265
+	{
266
+		static $attendee_nmbr = 1;
267
+		$form_args = array();
268
+		// verify that registration has valid event
269
+		if ($registration->event() instanceof EE_Event) {
270
+			$field_name = 'Event_Question_Group.'
271
+				. EEM_Event_Question_Group::instance()->fieldNameForContext(
272
+					$registration->is_primary_registrant()
273
+				);
274
+			$question_groups = $registration->event()->question_groups(
275
+				apply_filters(
276
+					// @codingStandardsIgnoreStart
277
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
278
+					// @codingStandardsIgnoreEnd
279
+					[
280
+						[
281
+							'Event.EVT_ID'                     => $registration->event()->ID(),
282
+							$field_name => true,
283
+						],
284
+						'order_by' => ['QSG_order' => 'ASC'],
285
+					],
286
+					$registration,
287
+					$this
288
+				)
289
+			);
290
+			if ($question_groups) {
291
+				// array of params to pass to parent constructor
292
+				$form_args = array(
293
+					'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
294
+					'html_class'      => 'ee-reg-form-attendee-dv',
295
+					'html_style'      => $this->checkout->admin_request
296
+						? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
297
+						: '',
298
+					'subsections'     => array(),
299
+					'layout_strategy' => new EE_Fieldset_Section_Layout(
300
+						array(
301
+							'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
302
+							'legend_text'  => sprintf(
303
+								esc_html_x(
304
+									'Attendee %d',
305
+									'Attendee 123',
306
+									'event_espresso'
307
+								),
308
+								$attendee_nmbr
309
+							),
310
+						)
311
+					),
312
+				);
313
+				foreach ($question_groups as $question_group) {
314
+					if ($question_group instanceof EE_Question_Group) {
315
+						$form_args['subsections'][ $question_group->identifier() ] = $this->_question_group_reg_form(
316
+							$registration,
317
+							$question_group
318
+						);
319
+					}
320
+				}
321
+				// add hidden input
322
+				$form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
323
+					$registration
324
+				);
325
+				// if we have question groups for additional attendees, then display the copy options
326
+				$this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
327
+				if ($registration->is_primary_registrant()) {
328
+					// generate hidden input
329
+					$form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
330
+						$registration
331
+					);
332
+				}
333
+			}
334
+		}
335
+		$attendee_nmbr++;
336
+		return ! empty($form_args)
337
+			? new EE_Form_Section_Proper($form_args)
338
+			: new EE_Form_Section_HTML();
339
+	}
340
+
341
+
342
+	/**
343
+	 * @param EE_Registration $registration
344
+	 * @param bool            $additional_attendee_reg_info
345
+	 * @return EE_Form_Input_Base
346
+	 * @throws EE_Error
347
+	 */
348
+	private function _additional_attendee_reg_info_input(
349
+		EE_Registration $registration,
350
+		$additional_attendee_reg_info = true
351
+	) {
352
+		// generate hidden input
353
+		return new EE_Hidden_Input(
354
+			array(
355
+				'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
356
+				'default' => $additional_attendee_reg_info,
357
+			)
358
+		);
359
+	}
360
+
361
+
362
+	/**
363
+	 * @param EE_Registration   $registration
364
+	 * @param EE_Question_Group $question_group
365
+	 * @return EE_Form_Section_Proper
366
+	 * @throws EE_Error
367
+	 * @throws InvalidArgumentException
368
+	 * @throws InvalidDataTypeException
369
+	 * @throws InvalidInterfaceException
370
+	 * @throws ReflectionException
371
+	 */
372
+	private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
373
+	{
374
+		// array of params to pass to parent constructor
375
+		$form_args = array(
376
+			'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
377
+			'html_class'      => $this->checkout->admin_request
378
+				? 'form-table ee-reg-form-qstn-grp-dv'
379
+				: 'ee-reg-form-qstn-grp-dv',
380
+			'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-'
381
+								 . $registration->ID() . '-lbl',
382
+			'subsections'     => array(
383
+				'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
384
+			),
385
+			'layout_strategy' => $this->checkout->admin_request
386
+				? new EE_Admin_Two_Column_Layout()
387
+				: new EE_Div_Per_Section_Layout(),
388
+		);
389
+		// where params
390
+		$query_params = array('QST_deleted' => 0);
391
+		// don't load admin only questions on the frontend
392
+		if (! $this->checkout->admin_request) {
393
+			$query_params['QST_admin_only'] = array('!=', true);
394
+		}
395
+		$questions = $question_group->get_many_related(
396
+			'Question',
397
+			apply_filters(
398
+				'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
399
+				array(
400
+					$query_params,
401
+					'order_by' => array(
402
+						'Question_Group_Question.QGQ_order' => 'ASC',
403
+					),
404
+				),
405
+				$question_group,
406
+				$registration,
407
+				$this
408
+			)
409
+		);
410
+		// filter for additional content before questions
411
+		$form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
412
+			apply_filters(
413
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
414
+				'',
415
+				$registration,
416
+				$question_group,
417
+				$this
418
+			)
419
+		);
420
+		// loop thru questions
421
+		foreach ($questions as $question) {
422
+			if ($question instanceof EE_Question) {
423
+				$identifier = $question->is_system_question()
424
+					? $question->system_ID()
425
+					: $question->ID();
426
+				$form_args['subsections'][ $identifier ] = $this->reg_form_question($registration, $question);
427
+			}
428
+		}
429
+		$form_args['subsections'] = apply_filters(
430
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
431
+			$form_args['subsections'],
432
+			$registration,
433
+			$question_group,
434
+			$this
435
+		);
436
+		// filter for additional content after questions
437
+		$form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
438
+			apply_filters(
439
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
440
+				'',
441
+				$registration,
442
+				$question_group,
443
+				$this
444
+			)
445
+		);
446
+		// d($form_args);
447
+		$question_group_reg_form = new EE_Form_Section_Proper($form_args);
448
+		return apply_filters(
449
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
450
+			$question_group_reg_form,
451
+			$registration,
452
+			$question_group,
453
+			$this
454
+		);
455
+	}
456
+
457
+
458
+	/**
459
+	 * @param EE_Question_Group $question_group
460
+	 * @return    EE_Form_Section_HTML
461
+	 */
462
+	private function _question_group_header(EE_Question_Group $question_group)
463
+	{
464
+		$html = '';
465
+		// group_name
466
+		if ($question_group->show_group_name() && $question_group->name() !== '') {
467
+			if ($this->checkout->admin_request) {
468
+				$html .= EEH_HTML::br();
469
+				$html .= EEH_HTML::h3(
470
+					$question_group->name(),
471
+					'',
472
+					'ee-reg-form-qstn-grp-title title',
473
+					'font-size: 1.3em; padding-left:0;'
474
+				);
475
+			} else {
476
+				$html .= EEH_HTML::h4(
477
+					$question_group->name(),
478
+					'',
479
+					'ee-reg-form-qstn-grp-title section-title'
480
+				);
481
+			}
482
+		}
483
+		// group_desc
484
+		if ($question_group->show_group_desc() && $question_group->desc() !== '') {
485
+			$html .= EEH_HTML::p(
486
+				$question_group->desc(),
487
+				'',
488
+				$this->checkout->admin_request
489
+					? 'ee-reg-form-qstn-grp-desc-pg'
490
+					: 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
491
+			);
492
+		}
493
+		return new EE_Form_Section_HTML($html);
494
+	}
495
+
496
+
497
+	/**
498
+	 * @return    EE_Form_Section_Proper
499
+	 * @throws EE_Error
500
+	 * @throws InvalidArgumentException
501
+	 * @throws ReflectionException
502
+	 * @throws InvalidDataTypeException
503
+	 * @throws InvalidInterfaceException
504
+	 */
505
+	private function _copy_attendee_info_form()
506
+	{
507
+		// array of params to pass to parent constructor
508
+		return new EE_Form_Section_Proper(
509
+			array(
510
+				'subsections'     => $this->_copy_attendee_info_inputs(),
511
+				'layout_strategy' => new EE_Template_Layout(
512
+					array(
513
+						'layout_template_file'     => SPCO_REG_STEPS_PATH
514
+													  . $this->_slug
515
+													  . DS
516
+													  . 'copy_attendee_info.template.php',
517
+						'begin_template_file'      => null,
518
+						'input_template_file'      => null,
519
+						'subsection_template_file' => null,
520
+						'end_template_file'        => null,
521
+					)
522
+				),
523
+			)
524
+		);
525
+	}
526
+
527
+
528
+	/**
529
+	 * @return EE_Form_Section_HTML
530
+	 * @throws DomainException
531
+	 * @throws InvalidArgumentException
532
+	 * @throws InvalidDataTypeException
533
+	 * @throws InvalidInterfaceException
534
+	 */
535
+	private function _auto_copy_attendee_info()
536
+	{
537
+		return new EE_Form_Section_HTML(
538
+			EEH_Template::locate_template(
539
+				SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
540
+				apply_filters(
541
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
542
+					array()
543
+				),
544
+				true,
545
+				true
546
+			)
547
+		);
548
+	}
549
+
550
+
551
+	/**
552
+	 * @return array
553
+	 * @throws EE_Error
554
+	 * @throws InvalidArgumentException
555
+	 * @throws ReflectionException
556
+	 * @throws InvalidDataTypeException
557
+	 * @throws InvalidInterfaceException
558
+	 */
559
+	private function _copy_attendee_info_inputs()
560
+	{
561
+		$copy_attendee_info_inputs = array();
562
+		$prev_ticket = null;
563
+		// grab the saved registrations from the transaction
564
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
565
+		foreach ($registrations as $registration) {
566
+			// for all  attendees other than the primary attendee
567
+			if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
568
+				// if this is a new ticket OR if this is the very first additional attendee after the primary attendee
569
+				if ($registration->ticket()->ID() !== $prev_ticket) {
570
+					$item_name = $registration->ticket()->name();
571
+					$item_name .= $registration->ticket()->description() !== ''
572
+						? ' - ' . $registration->ticket()->description()
573
+						: '';
574
+					$copy_attendee_info_inputs[ 'spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID(
575
+					) . ']' ] =
576
+						new EE_Form_Section_HTML(
577
+							'<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
578
+						);
579
+					$prev_ticket = $registration->ticket()->ID();
580
+				}
581
+
582
+				$copy_attendee_info_inputs[ 'spco_copy_attendee_chk[' . $registration->ID() . ']' ] =
583
+					new EE_Checkbox_Multi_Input(
584
+						array(
585
+							$registration->ID() => sprintf(
586
+								esc_html_x('Attendee #%s', 'Attendee #123', 'event_espresso'),
587
+								$registration->count()
588
+							),
589
+						),
590
+						array(
591
+							'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
592
+							'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
593
+							'display_html_label_text' => false,
594
+						)
595
+					);
596
+			}
597
+		}
598
+		return $copy_attendee_info_inputs;
599
+	}
600
+
601
+
602
+	/**
603
+	 * @param EE_Registration $registration
604
+	 * @return    EE_Form_Input_Base
605
+	 * @throws EE_Error
606
+	 */
607
+	private function _additional_primary_registrant_inputs(EE_Registration $registration)
608
+	{
609
+		// generate hidden input
610
+		return new EE_Hidden_Input(
611
+			array(
612
+				'html_id' => 'primary_registrant',
613
+				'default' => $registration->reg_url_link(),
614
+			)
615
+		);
616
+	}
617
+
618
+
619
+	/**
620
+	 * @param EE_Registration $registration
621
+	 * @param EE_Question     $question
622
+	 * @return EE_Form_Input_Base
623
+	 * @throws EE_Error
624
+	 * @throws InvalidArgumentException
625
+	 * @throws InvalidDataTypeException
626
+	 * @throws InvalidInterfaceException
627
+	 * @throws ReflectionException
628
+	 */
629
+	public function reg_form_question(EE_Registration $registration, EE_Question $question)
630
+	{
631
+
632
+		// if this question was for an attendee detail, then check for that answer
633
+		$answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
634
+			$registration,
635
+			$question->system_ID()
636
+		);
637
+		$answer = $answer_value === null
638
+			? EEM_Answer::instance()->get_one(
639
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
640
+			)
641
+			: null;
642
+		// if NOT returning to edit an existing registration
643
+		// OR if this question is for an attendee property
644
+		// OR we still don't have an EE_Answer object
645
+		if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
646
+			// create an EE_Answer object for storing everything in
647
+			$answer = EE_Answer::new_instance(
648
+				array(
649
+					'QST_ID' => $question->ID(),
650
+					'REG_ID' => $registration->ID(),
651
+				)
652
+			);
653
+		}
654
+		// verify instance
655
+		if ($answer instanceof EE_Answer) {
656
+			if (! empty($answer_value)) {
657
+				$answer->set('ANS_value', $answer_value);
658
+			}
659
+			$answer->cache('Question', $question);
660
+			// remember system ID had a bug where sometimes it could be null
661
+			$answer_cache_id = $question->is_system_question()
662
+				? $question->system_ID() . '-' . $registration->reg_url_link()
663
+				: $question->ID() . '-' . $registration->reg_url_link();
664
+			$registration->cache('Answer', $answer, $answer_cache_id);
665
+		}
666
+		return $this->_generate_question_input($registration, $question, $answer);
667
+	}
668
+
669
+
670
+	/**
671
+	 * @param EE_Registration $registration
672
+	 * @param EE_Question     $question
673
+	 * @param                 $answer
674
+	 * @return EE_Form_Input_Base
675
+	 * @throws EE_Error
676
+	 * @throws InvalidArgumentException
677
+	 * @throws ReflectionException
678
+	 * @throws InvalidDataTypeException
679
+	 * @throws InvalidInterfaceException
680
+	 */
681
+	private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
682
+	{
683
+		$identifier = $question->is_system_question()
684
+			? $question->system_ID()
685
+			: $question->ID();
686
+		$this->_required_questions[ $identifier ] = $question->required() ? true : false;
687
+		add_filter(
688
+			'FHEE__EE_Question__generate_form_input__country_options',
689
+			array($this, 'use_cached_countries_for_form_input'),
690
+			10,
691
+			4
692
+		);
693
+		add_filter(
694
+			'FHEE__EE_Question__generate_form_input__state_options',
695
+			array($this, 'use_cached_states_for_form_input'),
696
+			10,
697
+			4
698
+		);
699
+		$input_constructor_args = array(
700
+			'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
701
+			'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
702
+			'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
703
+			'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
704
+			'html_label_class' => 'ee-reg-qstn',
705
+		);
706
+		$input_constructor_args['html_label_id'] .= '-lbl';
707
+		if ($answer instanceof EE_Answer && $answer->ID()) {
708
+			$input_constructor_args['html_name'] .= '[' . $answer->ID() . ']';
709
+			$input_constructor_args['html_id'] .= '-' . $answer->ID();
710
+			$input_constructor_args['html_label_id'] .= '-' . $answer->ID();
711
+		}
712
+		$form_input = $question->generate_form_input(
713
+			$registration,
714
+			$answer,
715
+			$input_constructor_args
716
+		);
717
+		remove_filter(
718
+			'FHEE__EE_Question__generate_form_input__country_options',
719
+			array($this, 'use_cached_countries_for_form_input')
720
+		);
721
+		remove_filter(
722
+			'FHEE__EE_Question__generate_form_input__state_options',
723
+			array($this, 'use_cached_states_for_form_input')
724
+		);
725
+		return $form_input;
726
+	}
727
+
728
+
729
+	/**
730
+	 * Gets the list of countries for the form input
731
+	 *
732
+	 * @param array|null      $countries_list
733
+	 * @param EE_Question     $question
734
+	 * @param EE_Registration $registration
735
+	 * @param EE_Answer       $answer
736
+	 * @return array 2d keys are country IDs, values are their names
737
+	 * @throws EE_Error
738
+	 * @throws InvalidArgumentException
739
+	 * @throws InvalidDataTypeException
740
+	 * @throws InvalidInterfaceException
741
+	 * @throws ReflectionException
742
+	 */
743
+	public function use_cached_countries_for_form_input(
744
+		$countries_list,
745
+		EE_Question $question = null,
746
+		EE_Registration $registration = null,
747
+		EE_Answer $answer = null
748
+	) {
749
+		$country_options = array('' => '');
750
+		// get possibly cached list of countries
751
+		$countries = $this->checkout->action === 'process_reg_step'
752
+			? EEM_Country::instance()->get_all_countries()
753
+			: EEM_Country::instance()->get_all_active_countries();
754
+		if (! empty($countries)) {
755
+			foreach ($countries as $country) {
756
+				if ($country instanceof EE_Country) {
757
+					$country_options[ $country->ID() ] = $country->name();
758
+				}
759
+			}
760
+		}
761
+		if ($question instanceof EE_Question && $registration instanceof EE_Registration) {
762
+			$answer = EEM_Answer::instance()->get_one(
763
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
764
+			);
765
+		} else {
766
+			$answer = EE_Answer::new_instance();
767
+		}
768
+		$country_options = apply_filters(
769
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
770
+			$country_options,
771
+			$this,
772
+			$registration,
773
+			$question,
774
+			$answer
775
+		);
776
+		return $country_options;
777
+	}
778
+
779
+
780
+	/**
781
+	 * Gets the list of states for the form input
782
+	 *
783
+	 * @param array|null      $states_list
784
+	 * @param EE_Question     $question
785
+	 * @param EE_Registration $registration
786
+	 * @param EE_Answer       $answer
787
+	 * @return array 2d keys are state IDs, values are their names
788
+	 * @throws EE_Error
789
+	 * @throws InvalidArgumentException
790
+	 * @throws InvalidDataTypeException
791
+	 * @throws InvalidInterfaceException
792
+	 * @throws ReflectionException
793
+	 */
794
+	public function use_cached_states_for_form_input(
795
+		$states_list,
796
+		EE_Question $question = null,
797
+		EE_Registration $registration = null,
798
+		EE_Answer $answer = null
799
+	) {
800
+		$state_options = array('' => array('' => ''));
801
+		$states = $this->checkout->action === 'process_reg_step'
802
+			? EEM_State::instance()->get_all_states()
803
+			: EEM_State::instance()->get_all_active_states();
804
+		if (! empty($states)) {
805
+			foreach ($states as $state) {
806
+				if ($state instanceof EE_State) {
807
+					$state_options[ $state->country()->name() ][ $state->ID() ] = $state->name();
808
+				}
809
+			}
810
+		}
811
+		$state_options = apply_filters(
812
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
813
+			$state_options,
814
+			$this,
815
+			$registration,
816
+			$question,
817
+			$answer
818
+		);
819
+		return $state_options;
820
+	}
821
+
822
+
823
+	/********************************************************************************************************/
824
+	/****************************************  PROCESS REG STEP  ****************************************/
825
+	/********************************************************************************************************/
826
+
827
+
828
+	/**
829
+	 * @return bool
830
+	 * @throws EE_Error
831
+	 * @throws InvalidArgumentException
832
+	 * @throws ReflectionException
833
+	 * @throws RuntimeException
834
+	 * @throws InvalidDataTypeException
835
+	 * @throws InvalidInterfaceException
836
+	 */
837
+	public function process_reg_step()
838
+	{
839
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
840
+		// grab validated data from form
841
+		$valid_data = $this->checkout->current_step->valid_data();
842
+		// EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
843
+		// EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
844
+		// if we don't have any $valid_data then something went TERRIBLY WRONG !!!
845
+		if (empty($valid_data)) {
846
+			EE_Error::add_error(
847
+				esc_html__('No valid question responses were received.', 'event_espresso'),
848
+				__FILE__,
849
+				__FUNCTION__,
850
+				__LINE__
851
+			);
852
+			return false;
853
+		}
854
+		if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
855
+			EE_Error::add_error(
856
+				esc_html__(
857
+					'A valid transaction could not be initiated for processing your registrations.',
858
+					'event_espresso'
859
+				),
860
+				__FILE__,
861
+				__FUNCTION__,
862
+				__LINE__
863
+			);
864
+			return false;
865
+		}
866
+		// get cached registrations
867
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
868
+		// verify we got the goods
869
+		if (empty($registrations)) {
870
+			// combine the old translated string with a new one, in order to not break translations
871
+			$error_message = esc_html__(
872
+				'Your form data could not be applied to any valid registrations.',
873
+				'event_espresso'
874
+			)
875
+			. sprintf(
876
+				esc_html_x(
877
+					'%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.',
878
+					'(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
879
+					'event_espresso'
880
+				),
881
+				'<a href="' . get_post_type_archive_link('espresso_events') . '" >',
882
+				'</a>',
883
+				'<br />'
884
+			);
885
+			EE_Error::add_error(
886
+				$error_message,
887
+				__FILE__,
888
+				__FUNCTION__,
889
+				__LINE__
890
+			);
891
+			return false;
892
+		}
893
+		// extract attendee info from form data and save to model objects
894
+		$registrations_processed = $this->_process_registrations($registrations, $valid_data);
895
+		// if first pass thru SPCO,
896
+		// then let's check processed registrations against the total number of tickets in the cart
897
+		if ($registrations_processed === false) {
898
+			// but return immediately if the previous step exited early due to errors
899
+			return false;
900
+		}
901
+		if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
902
+			// generate a correctly translated string for all possible singular/plural combinations
903
+			if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
904
+				$error_msg = sprintf(
905
+					esc_html_x(
906
+						'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
907
+						'There was 1 ticket in the Event Queue, but 2 registrations were processed',
908
+						'event_espresso'
909
+					),
910
+					$this->checkout->total_ticket_count,
911
+					$registrations_processed
912
+				);
913
+			} elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
914
+				$error_msg = sprintf(
915
+					esc_html_x(
916
+						'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
917
+						'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
918
+						'event_espresso'
919
+					),
920
+					$this->checkout->total_ticket_count,
921
+					$registrations_processed
922
+				);
923
+			} else {
924
+				$error_msg = sprintf(
925
+					esc_html__(
926
+						'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
927
+						'event_espresso'
928
+					),
929
+					$this->checkout->total_ticket_count,
930
+					$registrations_processed
931
+				);
932
+			}
933
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
934
+			return false;
935
+		}
936
+		// mark this reg step as completed
937
+		$this->set_completed();
938
+		$this->_set_success_message(
939
+			esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
940
+		);
941
+		// do action in case a plugin wants to do something with the data submitted in step 1.
942
+		// passes EE_Single_Page_Checkout, and it's posted data
943
+		do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
944
+		return true;
945
+	}
946
+
947
+
948
+	/**
949
+	 *    _process_registrations
950
+	 *
951
+	 * @param EE_Registration[] $registrations
952
+	 * @param array[][]         $valid_data
953
+	 * @return bool|int
954
+	 * @throws EntityNotFoundException
955
+	 * @throws EE_Error
956
+	 * @throws InvalidArgumentException
957
+	 * @throws ReflectionException
958
+	 * @throws RuntimeException
959
+	 * @throws InvalidDataTypeException
960
+	 * @throws InvalidInterfaceException
961
+	 */
962
+	private function _process_registrations($registrations = array(), $valid_data = array())
963
+	{
964
+		// load resources and set some defaults
965
+		EE_Registry::instance()->load_model('Attendee');
966
+		// holder for primary registrant attendee object
967
+		$this->checkout->primary_attendee_obj = null;
968
+		// array for tracking reg form data for the primary registrant
969
+		$primary_registrant = array(
970
+			'line_item_id' => null,
971
+		);
972
+		$copy_primary = false;
973
+		// reg form sections that do not contain inputs
974
+		$non_input_form_sections = array(
975
+			'primary_registrant',
976
+			'additional_attendee_reg_info',
977
+			'spco_copy_attendee_chk',
978
+		);
979
+		// attendee counter
980
+		$att_nmbr = 0;
981
+		// grab the saved registrations from the transaction
982
+		foreach ($registrations as $registration) {
983
+			// verify EE_Registration object
984
+			if (! $registration instanceof EE_Registration) {
985
+				EE_Error::add_error(
986
+					esc_html__(
987
+						'An invalid Registration object was discovered when attempting to process your registration information.',
988
+						'event_espresso'
989
+					),
990
+					__FILE__,
991
+					__FUNCTION__,
992
+					__LINE__
993
+				);
994
+				return false;
995
+			}
996
+			/** @var string $reg_url_link */
997
+			$reg_url_link = $registration->reg_url_link();
998
+			// reg_url_link exists ?
999
+			if (! empty($reg_url_link)) {
1000
+				// should this registration be processed during this visit ?
1001
+				if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
1002
+					// if NOT revisiting, then let's save the registration now,
1003
+					// so that we have a REG_ID to use when generating other objects
1004
+					if (! $this->checkout->revisit) {
1005
+						$registration->save();
1006
+					}
1007
+					/**
1008
+					 * This allows plugins to trigger a fail on processing of a
1009
+					 * registration for any conditions they may have for it to pass.
1010
+					 *
1011
+					 * @var bool   if true is returned by the plugin then the
1012
+					 *            registration processing is halted.
1013
+					 */
1014
+					if (apply_filters(
1015
+						'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
1016
+						false,
1017
+						$att_nmbr,
1018
+						$registration,
1019
+						$registrations,
1020
+						$valid_data,
1021
+						$this
1022
+					)) {
1023
+						return false;
1024
+					}
1025
+
1026
+					// Houston, we have a registration!
1027
+					$att_nmbr++;
1028
+					$this->_attendee_data[ $reg_url_link ] = array();
1029
+					// grab any existing related answer objects
1030
+					$this->_registration_answers = $registration->answers();
1031
+					// unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
1032
+					if (isset($valid_data[ $reg_url_link ])) {
1033
+						// do we need to copy basic info from primary attendee ?
1034
+						$copy_primary = isset($valid_data[ $reg_url_link ]['additional_attendee_reg_info'])
1035
+										&& absint($valid_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
1036
+						// filter form input data for this registration
1037
+						$valid_data[ $reg_url_link ] = (array) apply_filters(
1038
+							'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
1039
+							$valid_data[ $reg_url_link ]
1040
+						);
1041
+						if (isset($valid_data['primary_attendee'])) {
1042
+							$primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
1043
+								? $valid_data['primary_attendee']
1044
+								: false;
1045
+							unset($valid_data['primary_attendee']);
1046
+						}
1047
+						// now loop through our array of valid post data && process attendee reg forms
1048
+						foreach ($valid_data[ $reg_url_link ] as $form_section => $form_inputs) {
1049
+							if (! in_array($form_section, $non_input_form_sections, true)) {
1050
+								foreach ($form_inputs as $form_input => $input_value) {
1051
+									// \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
1052
+									// check for critical inputs
1053
+									if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1054
+										$form_input,
1055
+										$input_value
1056
+									)
1057
+									) {
1058
+										return false;
1059
+									}
1060
+									// store a bit of data about the primary attendee
1061
+									if ($att_nmbr === 1
1062
+										&& ! empty($input_value)
1063
+										&& $reg_url_link === $primary_registrant['line_item_id']
1064
+									) {
1065
+										$primary_registrant[ $form_input ] = $input_value;
1066
+									} elseif ($copy_primary
1067
+											  && $input_value === null
1068
+											  && isset($primary_registrant[ $form_input ])
1069
+									) {
1070
+										$input_value = $primary_registrant[ $form_input ];
1071
+									}
1072
+									// now attempt to save the input data
1073
+									if (! $this->_save_registration_form_input(
1074
+										$registration,
1075
+										$form_input,
1076
+										$input_value
1077
+									)
1078
+									) {
1079
+										EE_Error::add_error(
1080
+											sprintf(
1081
+												esc_html_x(
1082
+													'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1083
+													'Unable to save registration form data for the form input: "form input name" with the submitted value: "form input value"',
1084
+													'event_espresso'
1085
+												),
1086
+												$form_input,
1087
+												$input_value
1088
+											),
1089
+											__FILE__,
1090
+											__FUNCTION__,
1091
+											__LINE__
1092
+										);
1093
+										return false;
1094
+									}
1095
+								}
1096
+							}
1097
+						}  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1098
+					}
1099
+					// EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1100
+					// this registration does not require additional attendee information ?
1101
+					if ($copy_primary
1102
+						&& $att_nmbr > 1
1103
+						&& $this->checkout->primary_attendee_obj instanceof EE_Attendee
1104
+					) {
1105
+						// just copy the primary registrant
1106
+						$attendee = $this->checkout->primary_attendee_obj;
1107
+					} else {
1108
+						// ensure critical details are set for additional attendees
1109
+						$this->_attendee_data[ $reg_url_link ] = $att_nmbr > 1
1110
+							? $this->_copy_critical_attendee_details_from_primary_registrant(
1111
+								$this->_attendee_data[ $reg_url_link ]
1112
+							)
1113
+							: $this->_attendee_data[ $reg_url_link ];
1114
+						// execute create attendee command (which may return an existing attendee)
1115
+						$attendee = EE_Registry::instance()->BUS->execute(
1116
+							new CreateAttendeeCommand(
1117
+								$this->_attendee_data[ $reg_url_link ],
1118
+								$registration
1119
+							)
1120
+						);
1121
+						// who's #1 ?
1122
+						if ($att_nmbr === 1) {
1123
+							$this->checkout->primary_attendee_obj = $attendee;
1124
+						}
1125
+					}
1126
+					// EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1127
+					// add relation to registration, set attendee ID, and cache attendee
1128
+					$this->_associate_attendee_with_registration($registration, $attendee);
1129
+					// \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1130
+					if (! $registration->attendee() instanceof EE_Attendee) {
1131
+						EE_Error::add_error(
1132
+							sprintf(
1133
+								esc_html_x(
1134
+									'Registration %s has an invalid or missing Attendee object.',
1135
+									'Registration 123-456-789 has an invalid or missing Attendee object.',
1136
+									'event_espresso'
1137
+								),
1138
+								$reg_url_link
1139
+							),
1140
+							__FILE__,
1141
+							__FUNCTION__,
1142
+							__LINE__
1143
+						);
1144
+						return false;
1145
+					}
1146
+					/** @type EE_Registration_Processor $registration_processor */
1147
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1148
+					// at this point, we should have enough details about the registrant to consider the registration
1149
+					// NOT incomplete
1150
+					$registration_processor->toggle_incomplete_registration_status_to_default(
1151
+						$registration,
1152
+						false,
1153
+						new Context(
1154
+							'spco_reg_step_attendee_information_process_registrations',
1155
+							esc_html__(
1156
+								'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1157
+								'event_espresso'
1158
+							)
1159
+						)
1160
+					);
1161
+					// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1162
+					// abandoned
1163
+					$this->checkout->transaction->toggle_failed_transaction_status();
1164
+					// if we've gotten this far, then let's save what we have
1165
+					$registration->save();
1166
+					// add relation between TXN and registration
1167
+					$this->_associate_registration_with_transaction($registration);
1168
+				}
1169
+			} else {
1170
+				EE_Error::add_error(
1171
+					esc_html__(
1172
+						'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1173
+						'event_espresso'
1174
+					),
1175
+					__FILE__,
1176
+					__FUNCTION__,
1177
+					__LINE__
1178
+				);
1179
+				// remove malformed data
1180
+				unset($valid_data[ $reg_url_link ]);
1181
+				return false;
1182
+			}
1183
+		} // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1184
+		return $att_nmbr;
1185
+	}
1186
+
1187
+
1188
+	/**
1189
+	 *    _save_registration_form_input
1190
+	 *
1191
+	 * @param EE_Registration $registration
1192
+	 * @param string          $form_input
1193
+	 * @param string          $input_value
1194
+	 * @return bool
1195
+	 * @throws EE_Error
1196
+	 * @throws InvalidArgumentException
1197
+	 * @throws InvalidDataTypeException
1198
+	 * @throws InvalidInterfaceException
1199
+	 * @throws ReflectionException
1200
+	 */
1201
+	private function _save_registration_form_input(
1202
+		EE_Registration $registration,
1203
+		$form_input = '',
1204
+		$input_value = ''
1205
+	) {
1206
+		// \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1207
+		// \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1208
+		// \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1209
+		// allow for plugins to hook in and do their own processing of the form input.
1210
+		// For plugins to bypass normal processing here, they just need to return a boolean value.
1211
+		if (apply_filters(
1212
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1213
+			false,
1214
+			$registration,
1215
+			$form_input,
1216
+			$input_value,
1217
+			$this
1218
+		)) {
1219
+			return true;
1220
+		}
1221
+		/*
1222 1222
          * $answer_cache_id is the key used to find the EE_Answer we want
1223 1223
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1224 1224
          */
1225
-        $answer_cache_id = $this->checkout->reg_url_link
1226
-            ? $form_input . '-' . $registration->reg_url_link()
1227
-            : $form_input;
1228
-        $answer_is_obj = isset($this->_registration_answers[ $answer_cache_id ])
1229
-                         && $this->_registration_answers[ $answer_cache_id ] instanceof EE_Answer;
1230
-        // rename form_inputs if they are EE_Attendee properties
1231
-        switch ((string) $form_input) {
1232
-            case 'state':
1233
-            case 'STA_ID':
1234
-                $attendee_property = true;
1235
-                $form_input = 'STA_ID';
1236
-                break;
1237
-
1238
-            case 'country':
1239
-            case 'CNT_ISO':
1240
-                $attendee_property = true;
1241
-                $form_input = 'CNT_ISO';
1242
-                break;
1243
-
1244
-            default:
1245
-                $ATT_input = 'ATT_' . $form_input;
1246
-                // EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1247
-                $attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1248
-                $form_input = $attendee_property ? 'ATT_' . $form_input : $form_input;
1249
-        }
1250
-        // EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1251
-        // EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1252
-        // EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1253
-        // if this form input has a corresponding attendee property
1254
-        if ($attendee_property) {
1255
-            $this->_attendee_data[ $registration->reg_url_link() ][ $form_input ] = $input_value;
1256
-            if ($answer_is_obj) {
1257
-                // and delete the corresponding answer since we won't be storing this data in that object
1258
-                $registration->_remove_relation_to($this->_registration_answers[ $answer_cache_id ], 'Answer');
1259
-                $this->_registration_answers[ $answer_cache_id ]->delete_permanently();
1260
-            }
1261
-            return true;
1262
-        }
1263
-        if ($answer_is_obj) {
1264
-            // save this data to the answer object
1265
-            $this->_registration_answers[ $answer_cache_id ]->set_value($input_value);
1266
-            $result = $this->_registration_answers[ $answer_cache_id ]->save();
1267
-            return $result !== false;
1268
-        }
1269
-        foreach ($this->_registration_answers as $answer) {
1270
-            if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1271
-                $answer->set_value($input_value);
1272
-                $result = $answer->save();
1273
-                return $result !== false;
1274
-            }
1275
-        }
1276
-        return false;
1277
-    }
1278
-
1279
-
1280
-    /**
1281
-     *    _verify_critical_attendee_details_are_set
1282
-     *
1283
-     * @param string $form_input
1284
-     * @param string $input_value
1285
-     * @return boolean
1286
-     */
1287
-    private function _verify_critical_attendee_details_are_set_and_validate_email(
1288
-        $form_input = '',
1289
-        $input_value = ''
1290
-    ) {
1291
-        if (empty($input_value)) {
1292
-            // if the form input isn't marked as being required, then just return
1293
-            if (! isset($this->_required_questions[ $form_input ]) || ! $this->_required_questions[ $form_input ]) {
1294
-                return true;
1295
-            }
1296
-            switch ($form_input) {
1297
-                case 'fname':
1298
-                    EE_Error::add_error(
1299
-                        esc_html__('First Name is a required value.', 'event_espresso'),
1300
-                        __FILE__,
1301
-                        __FUNCTION__,
1302
-                        __LINE__
1303
-                    );
1304
-                    return false;
1305
-                    break;
1306
-                case 'lname':
1307
-                    EE_Error::add_error(
1308
-                        esc_html__('Last Name is a required value.', 'event_espresso'),
1309
-                        __FILE__,
1310
-                        __FUNCTION__,
1311
-                        __LINE__
1312
-                    );
1313
-                    return false;
1314
-                    break;
1315
-                case 'email':
1316
-                    EE_Error::add_error(
1317
-                        esc_html__('Please enter a valid email address.', 'event_espresso'),
1318
-                        __FILE__,
1319
-                        __FUNCTION__,
1320
-                        __LINE__
1321
-                    );
1322
-                    return false;
1323
-                    break;
1324
-            }
1325
-        }
1326
-        return true;
1327
-    }
1328
-
1329
-
1330
-    /**
1331
-     *    _associate_attendee_with_registration
1332
-     *
1333
-     * @param EE_Registration $registration
1334
-     * @param EE_Attendee     $attendee
1335
-     * @return void
1336
-     * @throws EE_Error
1337
-     * @throws InvalidArgumentException
1338
-     * @throws ReflectionException
1339
-     * @throws RuntimeException
1340
-     * @throws InvalidDataTypeException
1341
-     * @throws InvalidInterfaceException
1342
-     */
1343
-    private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1344
-    {
1345
-        // add relation to attendee
1346
-        $registration->_add_relation_to($attendee, 'Attendee');
1347
-        $registration->set_attendee_id($attendee->ID());
1348
-        $registration->update_cache_after_object_save('Attendee', $attendee);
1349
-    }
1350
-
1351
-
1352
-    /**
1353
-     *    _associate_registration_with_transaction
1354
-     *
1355
-     * @param EE_Registration $registration
1356
-     * @return void
1357
-     * @throws EE_Error
1358
-     * @throws InvalidArgumentException
1359
-     * @throws ReflectionException
1360
-     * @throws InvalidDataTypeException
1361
-     * @throws InvalidInterfaceException
1362
-     */
1363
-    private function _associate_registration_with_transaction(EE_Registration $registration)
1364
-    {
1365
-        // add relation to registration
1366
-        $this->checkout->transaction->_add_relation_to($registration, 'Registration');
1367
-        $this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1368
-    }
1369
-
1370
-
1371
-    /**
1372
-     *    _copy_critical_attendee_details_from_primary_registrant
1373
-     *    ensures that all attendees at least have data for first name, last name, and email address
1374
-     *
1375
-     * @param array $attendee_data
1376
-     * @return array
1377
-     * @throws EE_Error
1378
-     * @throws InvalidArgumentException
1379
-     * @throws ReflectionException
1380
-     * @throws InvalidDataTypeException
1381
-     * @throws InvalidInterfaceException
1382
-     */
1383
-    private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1384
-    {
1385
-        // bare minimum critical details include first name, last name, email address
1386
-        $critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1387
-        // add address info to critical details?
1388
-        if (apply_filters(
1389
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1390
-            false
1391
-        )) {
1392
-            $address_details = array(
1393
-                'ATT_address',
1394
-                'ATT_address2',
1395
-                'ATT_city',
1396
-                'STA_ID',
1397
-                'CNT_ISO',
1398
-                'ATT_zip',
1399
-                'ATT_phone',
1400
-            );
1401
-            $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1402
-        }
1403
-        foreach ($critical_attendee_details as $critical_attendee_detail) {
1404
-            if (! isset($attendee_data[ $critical_attendee_detail ])
1405
-                || empty($attendee_data[ $critical_attendee_detail ])
1406
-            ) {
1407
-                $attendee_data[ $critical_attendee_detail ] = $this->checkout->primary_attendee_obj->get(
1408
-                    $critical_attendee_detail
1409
-                );
1410
-            }
1411
-        }
1412
-        return $attendee_data;
1413
-    }
1414
-
1415
-
1416
-    /**
1417
-     *    update_reg_step
1418
-     *    this is the final step after a user  revisits the site to edit their attendee information
1419
-     *    this gets called AFTER the process_reg_step() method above
1420
-     *
1421
-     * @return bool
1422
-     * @throws EE_Error
1423
-     * @throws InvalidArgumentException
1424
-     * @throws ReflectionException
1425
-     * @throws RuntimeException
1426
-     * @throws InvalidDataTypeException
1427
-     * @throws InvalidInterfaceException
1428
-     */
1429
-    public function update_reg_step()
1430
-    {
1431
-        // save everything
1432
-        if ($this->process_reg_step()) {
1433
-            $this->checkout->redirect = true;
1434
-            $this->checkout->redirect_url = add_query_arg(
1435
-                array(
1436
-                    'e_reg_url_link' => $this->checkout->reg_url_link,
1437
-                    'revisit'        => true,
1438
-                ),
1439
-                $this->checkout->thank_you_page_url
1440
-            );
1441
-            $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1442
-            return true;
1443
-        }
1444
-        return false;
1445
-    }
1225
+		$answer_cache_id = $this->checkout->reg_url_link
1226
+			? $form_input . '-' . $registration->reg_url_link()
1227
+			: $form_input;
1228
+		$answer_is_obj = isset($this->_registration_answers[ $answer_cache_id ])
1229
+						 && $this->_registration_answers[ $answer_cache_id ] instanceof EE_Answer;
1230
+		// rename form_inputs if they are EE_Attendee properties
1231
+		switch ((string) $form_input) {
1232
+			case 'state':
1233
+			case 'STA_ID':
1234
+				$attendee_property = true;
1235
+				$form_input = 'STA_ID';
1236
+				break;
1237
+
1238
+			case 'country':
1239
+			case 'CNT_ISO':
1240
+				$attendee_property = true;
1241
+				$form_input = 'CNT_ISO';
1242
+				break;
1243
+
1244
+			default:
1245
+				$ATT_input = 'ATT_' . $form_input;
1246
+				// EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1247
+				$attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1248
+				$form_input = $attendee_property ? 'ATT_' . $form_input : $form_input;
1249
+		}
1250
+		// EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1251
+		// EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1252
+		// EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1253
+		// if this form input has a corresponding attendee property
1254
+		if ($attendee_property) {
1255
+			$this->_attendee_data[ $registration->reg_url_link() ][ $form_input ] = $input_value;
1256
+			if ($answer_is_obj) {
1257
+				// and delete the corresponding answer since we won't be storing this data in that object
1258
+				$registration->_remove_relation_to($this->_registration_answers[ $answer_cache_id ], 'Answer');
1259
+				$this->_registration_answers[ $answer_cache_id ]->delete_permanently();
1260
+			}
1261
+			return true;
1262
+		}
1263
+		if ($answer_is_obj) {
1264
+			// save this data to the answer object
1265
+			$this->_registration_answers[ $answer_cache_id ]->set_value($input_value);
1266
+			$result = $this->_registration_answers[ $answer_cache_id ]->save();
1267
+			return $result !== false;
1268
+		}
1269
+		foreach ($this->_registration_answers as $answer) {
1270
+			if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1271
+				$answer->set_value($input_value);
1272
+				$result = $answer->save();
1273
+				return $result !== false;
1274
+			}
1275
+		}
1276
+		return false;
1277
+	}
1278
+
1279
+
1280
+	/**
1281
+	 *    _verify_critical_attendee_details_are_set
1282
+	 *
1283
+	 * @param string $form_input
1284
+	 * @param string $input_value
1285
+	 * @return boolean
1286
+	 */
1287
+	private function _verify_critical_attendee_details_are_set_and_validate_email(
1288
+		$form_input = '',
1289
+		$input_value = ''
1290
+	) {
1291
+		if (empty($input_value)) {
1292
+			// if the form input isn't marked as being required, then just return
1293
+			if (! isset($this->_required_questions[ $form_input ]) || ! $this->_required_questions[ $form_input ]) {
1294
+				return true;
1295
+			}
1296
+			switch ($form_input) {
1297
+				case 'fname':
1298
+					EE_Error::add_error(
1299
+						esc_html__('First Name is a required value.', 'event_espresso'),
1300
+						__FILE__,
1301
+						__FUNCTION__,
1302
+						__LINE__
1303
+					);
1304
+					return false;
1305
+					break;
1306
+				case 'lname':
1307
+					EE_Error::add_error(
1308
+						esc_html__('Last Name is a required value.', 'event_espresso'),
1309
+						__FILE__,
1310
+						__FUNCTION__,
1311
+						__LINE__
1312
+					);
1313
+					return false;
1314
+					break;
1315
+				case 'email':
1316
+					EE_Error::add_error(
1317
+						esc_html__('Please enter a valid email address.', 'event_espresso'),
1318
+						__FILE__,
1319
+						__FUNCTION__,
1320
+						__LINE__
1321
+					);
1322
+					return false;
1323
+					break;
1324
+			}
1325
+		}
1326
+		return true;
1327
+	}
1328
+
1329
+
1330
+	/**
1331
+	 *    _associate_attendee_with_registration
1332
+	 *
1333
+	 * @param EE_Registration $registration
1334
+	 * @param EE_Attendee     $attendee
1335
+	 * @return void
1336
+	 * @throws EE_Error
1337
+	 * @throws InvalidArgumentException
1338
+	 * @throws ReflectionException
1339
+	 * @throws RuntimeException
1340
+	 * @throws InvalidDataTypeException
1341
+	 * @throws InvalidInterfaceException
1342
+	 */
1343
+	private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1344
+	{
1345
+		// add relation to attendee
1346
+		$registration->_add_relation_to($attendee, 'Attendee');
1347
+		$registration->set_attendee_id($attendee->ID());
1348
+		$registration->update_cache_after_object_save('Attendee', $attendee);
1349
+	}
1350
+
1351
+
1352
+	/**
1353
+	 *    _associate_registration_with_transaction
1354
+	 *
1355
+	 * @param EE_Registration $registration
1356
+	 * @return void
1357
+	 * @throws EE_Error
1358
+	 * @throws InvalidArgumentException
1359
+	 * @throws ReflectionException
1360
+	 * @throws InvalidDataTypeException
1361
+	 * @throws InvalidInterfaceException
1362
+	 */
1363
+	private function _associate_registration_with_transaction(EE_Registration $registration)
1364
+	{
1365
+		// add relation to registration
1366
+		$this->checkout->transaction->_add_relation_to($registration, 'Registration');
1367
+		$this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1368
+	}
1369
+
1370
+
1371
+	/**
1372
+	 *    _copy_critical_attendee_details_from_primary_registrant
1373
+	 *    ensures that all attendees at least have data for first name, last name, and email address
1374
+	 *
1375
+	 * @param array $attendee_data
1376
+	 * @return array
1377
+	 * @throws EE_Error
1378
+	 * @throws InvalidArgumentException
1379
+	 * @throws ReflectionException
1380
+	 * @throws InvalidDataTypeException
1381
+	 * @throws InvalidInterfaceException
1382
+	 */
1383
+	private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1384
+	{
1385
+		// bare minimum critical details include first name, last name, email address
1386
+		$critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1387
+		// add address info to critical details?
1388
+		if (apply_filters(
1389
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1390
+			false
1391
+		)) {
1392
+			$address_details = array(
1393
+				'ATT_address',
1394
+				'ATT_address2',
1395
+				'ATT_city',
1396
+				'STA_ID',
1397
+				'CNT_ISO',
1398
+				'ATT_zip',
1399
+				'ATT_phone',
1400
+			);
1401
+			$critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1402
+		}
1403
+		foreach ($critical_attendee_details as $critical_attendee_detail) {
1404
+			if (! isset($attendee_data[ $critical_attendee_detail ])
1405
+				|| empty($attendee_data[ $critical_attendee_detail ])
1406
+			) {
1407
+				$attendee_data[ $critical_attendee_detail ] = $this->checkout->primary_attendee_obj->get(
1408
+					$critical_attendee_detail
1409
+				);
1410
+			}
1411
+		}
1412
+		return $attendee_data;
1413
+	}
1414
+
1415
+
1416
+	/**
1417
+	 *    update_reg_step
1418
+	 *    this is the final step after a user  revisits the site to edit their attendee information
1419
+	 *    this gets called AFTER the process_reg_step() method above
1420
+	 *
1421
+	 * @return bool
1422
+	 * @throws EE_Error
1423
+	 * @throws InvalidArgumentException
1424
+	 * @throws ReflectionException
1425
+	 * @throws RuntimeException
1426
+	 * @throws InvalidDataTypeException
1427
+	 * @throws InvalidInterfaceException
1428
+	 */
1429
+	public function update_reg_step()
1430
+	{
1431
+		// save everything
1432
+		if ($this->process_reg_step()) {
1433
+			$this->checkout->redirect = true;
1434
+			$this->checkout->redirect_url = add_query_arg(
1435
+				array(
1436
+					'e_reg_url_link' => $this->checkout->reg_url_link,
1437
+					'revisit'        => true,
1438
+				),
1439
+				$this->checkout->thank_you_page_url
1440
+			);
1441
+			$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1442
+			return true;
1443
+		}
1444
+		return false;
1445
+	}
1446 1446
 }
Please login to merge, or discard this patch.
core/domain/services/registration/CopyRegistrationService.php 1 patch
Indentation   +141 added lines, -141 removed lines patch added patch discarded remove patch
@@ -27,151 +27,151 @@
 block discarded – undo
27 27
 {
28 28
 
29 29
 
30
-    /**
31
-     * @param EE_Registration $target_registration
32
-     * @param EE_Registration $registration_to_copy
33
-     * @return bool
34
-     * @throws UnexpectedEntityException
35
-     * @throws EntityNotFoundException
36
-     * @throws RuntimeException
37
-     * @throws EE_Error
38
-     */
39
-    public function copyRegistrationDetails(
40
-        EE_Registration $target_registration,
41
-        EE_Registration $registration_to_copy
42
-    ) {
43
-        // copy attendee
44
-        $target_registration->set_attendee_id($registration_to_copy->attendee_ID());
45
-        $target_registration->updateStatusBasedOnTotalPaid(false);
46
-        $target_registration->save();
47
-        // get answers to previous reg questions
48
-        $answers = $this->reindexAnswersByQuestionId($registration_to_copy->answers());
49
-        // get questions to new event reg form
50
-        $new_event = $target_registration->event();
51
-        $field_name = 'Event_Question_Group.'
52
-            . EEM_Event_Question_Group::instance()->fieldNameForContext(
53
-                $registration_to_copy->is_primary_registrant()
54
-            );
55
-        $question_groups = $new_event->question_groups([
56
-                [
57
-                    'Event.EVT_ID' => $new_event->ID(),
58
-                    $field_name => true,
59
-                ],
60
-                'order_by' => ['QSG_order' => 'ASC'],
61
-            ]);
62
-        foreach ($question_groups as $question_group) {
63
-            if ($question_group instanceof \EE_Question_Group) {
64
-                foreach ($question_group->questions() as $question) {
65
-                    if ($question instanceof EE_Question) {
66
-                        $this->generateNewAnswer(
67
-                            $question,
68
-                            $target_registration,
69
-                            $answers
70
-                        );
71
-                    }
72
-                }
73
-            }
74
-        }
75
-        return true;
76
-    }
30
+	/**
31
+	 * @param EE_Registration $target_registration
32
+	 * @param EE_Registration $registration_to_copy
33
+	 * @return bool
34
+	 * @throws UnexpectedEntityException
35
+	 * @throws EntityNotFoundException
36
+	 * @throws RuntimeException
37
+	 * @throws EE_Error
38
+	 */
39
+	public function copyRegistrationDetails(
40
+		EE_Registration $target_registration,
41
+		EE_Registration $registration_to_copy
42
+	) {
43
+		// copy attendee
44
+		$target_registration->set_attendee_id($registration_to_copy->attendee_ID());
45
+		$target_registration->updateStatusBasedOnTotalPaid(false);
46
+		$target_registration->save();
47
+		// get answers to previous reg questions
48
+		$answers = $this->reindexAnswersByQuestionId($registration_to_copy->answers());
49
+		// get questions to new event reg form
50
+		$new_event = $target_registration->event();
51
+		$field_name = 'Event_Question_Group.'
52
+			. EEM_Event_Question_Group::instance()->fieldNameForContext(
53
+				$registration_to_copy->is_primary_registrant()
54
+			);
55
+		$question_groups = $new_event->question_groups([
56
+				[
57
+					'Event.EVT_ID' => $new_event->ID(),
58
+					$field_name => true,
59
+				],
60
+				'order_by' => ['QSG_order' => 'ASC'],
61
+			]);
62
+		foreach ($question_groups as $question_group) {
63
+			if ($question_group instanceof \EE_Question_Group) {
64
+				foreach ($question_group->questions() as $question) {
65
+					if ($question instanceof EE_Question) {
66
+						$this->generateNewAnswer(
67
+							$question,
68
+							$target_registration,
69
+							$answers
70
+						);
71
+					}
72
+				}
73
+			}
74
+		}
75
+		return true;
76
+	}
77 77
 
78 78
 
79
-    /**
80
-     * @param EE_Answer[] $answers
81
-     * @return array
82
-     * @throws EE_Error
83
-     */
84
-    protected function reindexAnswersByQuestionId(array $answers)
85
-    {
86
-        $reindexed_answers = array();
87
-        foreach ($answers as $answer) {
88
-            if ($answer instanceof EE_Answer) {
89
-                $reindexed_answers[ $answer->question_ID() ] = $answer->value();
90
-            }
91
-        }
92
-        return $reindexed_answers;
93
-    }
79
+	/**
80
+	 * @param EE_Answer[] $answers
81
+	 * @return array
82
+	 * @throws EE_Error
83
+	 */
84
+	protected function reindexAnswersByQuestionId(array $answers)
85
+	{
86
+		$reindexed_answers = array();
87
+		foreach ($answers as $answer) {
88
+			if ($answer instanceof EE_Answer) {
89
+				$reindexed_answers[ $answer->question_ID() ] = $answer->value();
90
+			}
91
+		}
92
+		return $reindexed_answers;
93
+	}
94 94
 
95 95
 
96
-    /**
97
-     * @param EE_Question      $question
98
-     * @param EE_Registration  $registration
99
-     * @param                  $previous_answers
100
-     * @return EE_Answer
101
-     * @throws UnexpectedEntityException
102
-     * @throws EE_Error
103
-     */
104
-    protected function generateNewAnswer(
105
-        EE_Question $question,
106
-        EE_Registration $registration,
107
-        $previous_answers
108
-    ) {
109
-        $old_answer_value = isset($previous_answers[ $question->ID() ])
110
-            ? $previous_answers[ $question->ID() ]
111
-            : '';
112
-        $new_answer = EE_Answer::new_instance(
113
-            array(
114
-                'QST_ID'    => $question->ID(),
115
-                'REG_ID'    => $registration->ID(),
116
-                'ANS_value' => $old_answer_value,
117
-            )
118
-        );
119
-        if (! $new_answer instanceof EE_Answer) {
120
-            throw new UnexpectedEntityException($new_answer, 'EE_Answer');
121
-        }
122
-        $new_answer->save();
123
-        return $new_answer;
124
-    }
96
+	/**
97
+	 * @param EE_Question      $question
98
+	 * @param EE_Registration  $registration
99
+	 * @param                  $previous_answers
100
+	 * @return EE_Answer
101
+	 * @throws UnexpectedEntityException
102
+	 * @throws EE_Error
103
+	 */
104
+	protected function generateNewAnswer(
105
+		EE_Question $question,
106
+		EE_Registration $registration,
107
+		$previous_answers
108
+	) {
109
+		$old_answer_value = isset($previous_answers[ $question->ID() ])
110
+			? $previous_answers[ $question->ID() ]
111
+			: '';
112
+		$new_answer = EE_Answer::new_instance(
113
+			array(
114
+				'QST_ID'    => $question->ID(),
115
+				'REG_ID'    => $registration->ID(),
116
+				'ANS_value' => $old_answer_value,
117
+			)
118
+		);
119
+		if (! $new_answer instanceof EE_Answer) {
120
+			throw new UnexpectedEntityException($new_answer, 'EE_Answer');
121
+		}
122
+		$new_answer->save();
123
+		return $new_answer;
124
+	}
125 125
 
126 126
 
127
-    /**
128
-     * @param EE_Registration $target_registration
129
-     * @param EE_Registration $registration_to_copy
130
-     * @return bool
131
-     * @throws RuntimeException
132
-     * @throws UnexpectedEntityException
133
-     * @throws EE_Error
134
-     */
135
-    public function copyPaymentDetails(
136
-        EE_Registration $target_registration,
137
-        EE_Registration $registration_to_copy
138
-    ) {
139
-        $save = false;
140
-        $previous_registration_payments = $registration_to_copy->registration_payments();
141
-        $new_registration_payment_total = 0;
142
-        $registration_to_copy_total = $registration_to_copy->paid();
143
-        foreach ($previous_registration_payments as $previous_registration_payment) {
144
-            if ($previous_registration_payment instanceof EE_Registration_Payment
145
-                && $previous_registration_payment->payment() instanceof EE_Payment
146
-                && $previous_registration_payment->payment()->is_approved()
147
-            ) {
148
-                $payment_amount = $previous_registration_payment->amount();
149
-                $new_registration_payment = EE_Registration_Payment::new_instance(
150
-                    array(
151
-                        'REG_ID'     => $target_registration->ID(),
152
-                        'PAY_ID'     => $previous_registration_payment->payment()->ID(),
153
-                        'RPY_amount' => $payment_amount,
154
-                    )
155
-                );
156
-                if (! $new_registration_payment instanceof EE_Registration_Payment) {
157
-                    throw new UnexpectedEntityException($new_registration_payment, 'EE_Registration_Payment');
158
-                }
159
-                $new_registration_payment->save();
160
-                // if new reg payment is good, then set old reg payment amount to zero
161
-                $previous_registration_payment->set_amount(0);
162
-                $previous_registration_payment->save();
163
-                // now  increment/decrement payment amounts
164
-                $new_registration_payment_total += $payment_amount;
165
-                $registration_to_copy_total -= $payment_amount;
166
-                $save = true;
167
-            }
168
-        }
169
-        if ($save) {
170
-            $target_registration->set_paid($new_registration_payment_total);
171
-            $target_registration->save();
172
-            $registration_to_copy->set_paid($registration_to_copy_total);
173
-            $registration_to_copy->save();
174
-        }
175
-        return true;
176
-    }
127
+	/**
128
+	 * @param EE_Registration $target_registration
129
+	 * @param EE_Registration $registration_to_copy
130
+	 * @return bool
131
+	 * @throws RuntimeException
132
+	 * @throws UnexpectedEntityException
133
+	 * @throws EE_Error
134
+	 */
135
+	public function copyPaymentDetails(
136
+		EE_Registration $target_registration,
137
+		EE_Registration $registration_to_copy
138
+	) {
139
+		$save = false;
140
+		$previous_registration_payments = $registration_to_copy->registration_payments();
141
+		$new_registration_payment_total = 0;
142
+		$registration_to_copy_total = $registration_to_copy->paid();
143
+		foreach ($previous_registration_payments as $previous_registration_payment) {
144
+			if ($previous_registration_payment instanceof EE_Registration_Payment
145
+				&& $previous_registration_payment->payment() instanceof EE_Payment
146
+				&& $previous_registration_payment->payment()->is_approved()
147
+			) {
148
+				$payment_amount = $previous_registration_payment->amount();
149
+				$new_registration_payment = EE_Registration_Payment::new_instance(
150
+					array(
151
+						'REG_ID'     => $target_registration->ID(),
152
+						'PAY_ID'     => $previous_registration_payment->payment()->ID(),
153
+						'RPY_amount' => $payment_amount,
154
+					)
155
+				);
156
+				if (! $new_registration_payment instanceof EE_Registration_Payment) {
157
+					throw new UnexpectedEntityException($new_registration_payment, 'EE_Registration_Payment');
158
+				}
159
+				$new_registration_payment->save();
160
+				// if new reg payment is good, then set old reg payment amount to zero
161
+				$previous_registration_payment->set_amount(0);
162
+				$previous_registration_payment->save();
163
+				// now  increment/decrement payment amounts
164
+				$new_registration_payment_total += $payment_amount;
165
+				$registration_to_copy_total -= $payment_amount;
166
+				$save = true;
167
+			}
168
+		}
169
+		if ($save) {
170
+			$target_registration->set_paid($new_registration_payment_total);
171
+			$target_registration->save();
172
+			$registration_to_copy->set_paid($registration_to_copy_total);
173
+			$registration_to_copy->save();
174
+		}
175
+		return true;
176
+	}
177 177
 }
Please login to merge, or discard this patch.
4_1_0_stages/EE_DMS_4_1_0_event_question_group.dmsstage.php 2 patches
Indentation   +104 added lines, -106 removed lines patch added patch discarded remove patch
@@ -16,15 +16,13 @@  discard block
 block discarded – undo
16 16
             'EQG_primary'=>new EE_Boolean_Field('EQG_primary', __('Flag indicating question is only for primary attendees','event_espresso'), false, false)
17 17
         )
18 18
     );
19
-
20
-
21 19
  *
22 20
  */
23 21
 class EE_DMS_4_1_0_event_question_group extends EE_Data_Migration_Script_Stage_Table
24 22
 {
25
-    private $_new_table;
26
-    public function _migrate_old_row($old_row)
27
-    {
23
+	private $_new_table;
24
+	public function _migrate_old_row($old_row)
25
+	{
28 26
 //      $txn_id = $this->get_migration_script()->get_mapping_new_pk($this->_old_table, $old_row['id'], $this->_new_transaction_table);
29 27
 //          if ( ! $txn_id ){
30 28
 //              $this->add_error(sprintf(__("Could not find the transaction for the 3.1 attendee %d from row %s", "event_espresso"),$old_row['id'],$this->_json_encode($old_row)));
@@ -34,8 +32,8 @@  discard block
 block discarded – undo
34 32
 //          $new_line_items = $this->_insert_new_line_items($txn,$old_row);
35 33
 //          $this->get_migration_script()->set_mapping($this->_old_table,$old_row['id'],$this->_new_line_table,$new_line_items);
36 34
 
37
-            $this->_insert_new_event_question_groups($old_row);
38
-    }
35
+			$this->_insert_new_event_question_groups($old_row);
36
+	}
39 37
 //  function _migration_step($num_items=50){
40 38
 //      global $wpdb;
41 39
 //      $start_at_record = $this->count_records_migrated();
@@ -55,109 +53,109 @@  discard block
 block discarded – undo
55 53
 //      $count = $wpdb->get_var("SELECT COUNT(id) FROM ".$this->_old_table);
56 54
 //      return $count;
57 55
 //  }
58
-    public function __construct()
59
-    {
60
-        global $wpdb;
61
-        $this->_old_table = $wpdb->prefix."events_detail";
62
-        $this->_extra_where_sql = 'WHERE event_status!="D"';
63
-        $this->_new_table = $wpdb->prefix."esp_event_question_group";
64
-        $this->_pretty_name = __("Question Groups in each Event", "event_espresso");
65
-        parent::__construct();
66
-    }
56
+	public function __construct()
57
+	{
58
+		global $wpdb;
59
+		$this->_old_table = $wpdb->prefix."events_detail";
60
+		$this->_extra_where_sql = 'WHERE event_status!="D"';
61
+		$this->_new_table = $wpdb->prefix."esp_event_question_group";
62
+		$this->_pretty_name = __("Question Groups in each Event", "event_espresso");
63
+		parent::__construct();
64
+	}
67 65
 
68
-    /**
69
-     * Attempts to insert a new question group inthe new format given an old one
70
-     * @global type $wpdb
71
-     * @param array $old_event
72
-     * @return void
73
-     */
74
-    private function _insert_new_event_question_groups($old_event)
75
-    {
76
-        $new_event_question_group_ids = array();
77
-        $question_groups_for_primary = maybe_unserialize($old_event['question_groups']);
78
-        if (is_array($question_groups_for_primary)) {
79
-            foreach ($question_groups_for_primary as $old_question_group_id) {
80
-                $new_id = $this->_insert_event_question_group($old_event, $old_question_group_id, true);
81
-                if ($new_id) {
82
-                    $new_event_question_group_ids[] = $new_id;
83
-                }
84
-            }
85
-        }
86
-        $event_meta = maybe_unserialize($old_event['event_meta']);
87
-        if (isset($event_meta['add_attendee_question_groups'])) {
88
-            if (is_array($event_meta['add_attendee_question_groups'])) {
89
-                foreach ($event_meta['add_attendee_question_groups'] as $old_question_group_id) {
90
-                    $new_id = $this->_insert_event_question_group($old_event, $old_question_group_id, false);
91
-                    if ($new_id) {
92
-                        $new_event_question_group_ids[] = $new_id;
93
-                    }
94
-                }
95
-            }
96
-        }
66
+	/**
67
+	 * Attempts to insert a new question group inthe new format given an old one
68
+	 * @global type $wpdb
69
+	 * @param array $old_event
70
+	 * @return void
71
+	 */
72
+	private function _insert_new_event_question_groups($old_event)
73
+	{
74
+		$new_event_question_group_ids = array();
75
+		$question_groups_for_primary = maybe_unserialize($old_event['question_groups']);
76
+		if (is_array($question_groups_for_primary)) {
77
+			foreach ($question_groups_for_primary as $old_question_group_id) {
78
+				$new_id = $this->_insert_event_question_group($old_event, $old_question_group_id, true);
79
+				if ($new_id) {
80
+					$new_event_question_group_ids[] = $new_id;
81
+				}
82
+			}
83
+		}
84
+		$event_meta = maybe_unserialize($old_event['event_meta']);
85
+		if (isset($event_meta['add_attendee_question_groups'])) {
86
+			if (is_array($event_meta['add_attendee_question_groups'])) {
87
+				foreach ($event_meta['add_attendee_question_groups'] as $old_question_group_id) {
88
+					$new_id = $this->_insert_event_question_group($old_event, $old_question_group_id, false);
89
+					if ($new_id) {
90
+						$new_event_question_group_ids[] = $new_id;
91
+					}
92
+				}
93
+			}
94
+		}
97 95
 
98 96
 
99
-        $this->get_migration_script()->set_mapping($this->_old_table, $old_event['id'], $this->_new_table, $new_event_question_group_ids);
100
-    }
97
+		$this->get_migration_script()->set_mapping($this->_old_table, $old_event['id'], $this->_new_table, $new_event_question_group_ids);
98
+	}
101 99
 
102
-    private function _insert_event_question_group($old_event, $old_question_group_id, $primary)
103
-    {
104
-        global $wpdb;
105
-        $new_question_group_id = $this->get_migration_script()->get_mapping_new_pk(
106
-            $wpdb->prefix . "events_qst_group",
107
-            intval($old_question_group_id),
108
-            $wpdb->prefix . "esp_question_group"
109
-        );
100
+	private function _insert_event_question_group($old_event, $old_question_group_id, $primary)
101
+	{
102
+		global $wpdb;
103
+		$new_question_group_id = $this->get_migration_script()->get_mapping_new_pk(
104
+			$wpdb->prefix . "events_qst_group",
105
+			intval($old_question_group_id),
106
+			$wpdb->prefix . "esp_question_group"
107
+		);
110 108
 
111
-        if (! $new_question_group_id) {
112
-            $this->add_error(
113
-                sprintf(
114
-                    // translators: %s question ID, %s event ID
115
-                    __("Could not find 4.1 question ID for 3.1 question id #%s on event $%s", "event_espresso"),
116
-                    $old_question_group_id,
117
-                    $old_event['id']
118
-                )
119
-            );
120
-            return 0;
121
-        }
122
-        $new_event_id = $this->get_migration_script()->get_mapping_new_pk(
123
-            $wpdb->prefix . "events_detail",
124
-            intval($old_event['id']),
125
-            $wpdb->posts
126
-        );
127
-        if (! $new_question_group_id) {
128
-            $this->add_error(
129
-                sprintf(
130
-                    // translators: %s event ID
131
-                    __("Could not find 4.1 event 3.1 event id #%s", "event_espresso"),
132
-                    $old_event['id']
133
-                )
134
-            );
135
-            return 0;
136
-        }
137
-        $cols_n_values = array(
138
-            'EVT_ID'=>$new_event_id,
139
-            'QSG_ID'=>$new_question_group_id,
140
-            'EQG_primary' => $primary
141
-        );
109
+		if (! $new_question_group_id) {
110
+			$this->add_error(
111
+				sprintf(
112
+					// translators: %s question ID, %s event ID
113
+					__("Could not find 4.1 question ID for 3.1 question id #%s on event $%s", "event_espresso"),
114
+					$old_question_group_id,
115
+					$old_event['id']
116
+				)
117
+			);
118
+			return 0;
119
+		}
120
+		$new_event_id = $this->get_migration_script()->get_mapping_new_pk(
121
+			$wpdb->prefix . "events_detail",
122
+			intval($old_event['id']),
123
+			$wpdb->posts
124
+		);
125
+		if (! $new_question_group_id) {
126
+			$this->add_error(
127
+				sprintf(
128
+					// translators: %s event ID
129
+					__("Could not find 4.1 event 3.1 event id #%s", "event_espresso"),
130
+					$old_event['id']
131
+				)
132
+			);
133
+			return 0;
134
+		}
135
+		$cols_n_values = array(
136
+			'EVT_ID'=>$new_event_id,
137
+			'QSG_ID'=>$new_question_group_id,
138
+			'EQG_primary' => $primary
139
+		);
142 140
 
143
-        $datatypes = array(
144
-            '%d',// EVT_ID
145
-            '%d',// QSG_ID
146
-            '%d',// EQG_primary
147
-        );
148
-        $success = $wpdb->insert($this->_new_table, $cols_n_values, $datatypes);
149
-        if (! $success) {
150
-            $this->add_error(
151
-                $this->get_migration_script()->_create_error_message_for_db_insertion(
152
-                    $this->_old_table,
153
-                    $old_event,
154
-                    $this->_new_table,
155
-                    $cols_n_values,
156
-                    $datatypes
157
-                )
158
-            );
159
-            return 0;
160
-        }
161
-        return $wpdb->insert_id;
162
-    }
141
+		$datatypes = array(
142
+			'%d',// EVT_ID
143
+			'%d',// QSG_ID
144
+			'%d',// EQG_primary
145
+		);
146
+		$success = $wpdb->insert($this->_new_table, $cols_n_values, $datatypes);
147
+		if (! $success) {
148
+			$this->add_error(
149
+				$this->get_migration_script()->_create_error_message_for_db_insertion(
150
+					$this->_old_table,
151
+					$old_event,
152
+					$this->_new_table,
153
+					$cols_n_values,
154
+					$datatypes
155
+				)
156
+			);
157
+			return 0;
158
+		}
159
+		return $wpdb->insert_id;
160
+	}
163 161
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -103,12 +103,12 @@  discard block
 block discarded – undo
103 103
     {
104 104
         global $wpdb;
105 105
         $new_question_group_id = $this->get_migration_script()->get_mapping_new_pk(
106
-            $wpdb->prefix . "events_qst_group",
106
+            $wpdb->prefix."events_qst_group",
107 107
             intval($old_question_group_id),
108
-            $wpdb->prefix . "esp_question_group"
108
+            $wpdb->prefix."esp_question_group"
109 109
         );
110 110
 
111
-        if (! $new_question_group_id) {
111
+        if ( ! $new_question_group_id) {
112 112
             $this->add_error(
113 113
                 sprintf(
114 114
                     // translators: %s question ID, %s event ID
@@ -120,11 +120,11 @@  discard block
 block discarded – undo
120 120
             return 0;
121 121
         }
122 122
         $new_event_id = $this->get_migration_script()->get_mapping_new_pk(
123
-            $wpdb->prefix . "events_detail",
123
+            $wpdb->prefix."events_detail",
124 124
             intval($old_event['id']),
125 125
             $wpdb->posts
126 126
         );
127
-        if (! $new_question_group_id) {
127
+        if ( ! $new_question_group_id) {
128 128
             $this->add_error(
129 129
                 sprintf(
130 130
                     // translators: %s event ID
@@ -141,12 +141,12 @@  discard block
 block discarded – undo
141 141
         );
142 142
 
143 143
         $datatypes = array(
144
-            '%d',// EVT_ID
145
-            '%d',// QSG_ID
146
-            '%d',// EQG_primary
144
+            '%d', // EVT_ID
145
+            '%d', // QSG_ID
146
+            '%d', // EQG_primary
147 147
         );
148 148
         $success = $wpdb->insert($this->_new_table, $cols_n_values, $datatypes);
149
-        if (! $success) {
149
+        if ( ! $success) {
150 150
             $this->add_error(
151 151
                 $this->get_migration_script()->_create_error_message_for_db_insertion(
152 152
                     $this->_old_table,
Please login to merge, or discard this patch.
core/data_migration_scripts/EE_Data_Migration_Class_Base.core.php 1 patch
Indentation   +404 added lines, -404 removed lines patch added patch discarded remove patch
@@ -17,408 +17,408 @@
 block discarded – undo
17 17
 abstract class EE_Data_Migration_Class_Base
18 18
 {
19 19
 
20
-    /**
21
-     * @var $records_to_migrate int count of all that have been migrated
22
-     */
23
-    protected $_records_to_migrate = 0;
24
-
25
-    /**
26
-     *
27
-     * @var $records_migrated int
28
-     */
29
-    protected $_records_migrated = 0;
30
-
31
-    /**
32
-     * Whether this migration script is done or not. This COULD be deduced by
33
-     * _records_to_migrate and _records_migrated, but that might nto be accurate
34
-     *
35
-     * @var string one of EE_Data_migration_Manager::status_* constants
36
-     */
37
-    protected $_status = null;
38
-
39
-    /**
40
-     * internationalized name of this class. Convention is to NOT restate that
41
-     * this class if a migration script or a migration script stage
42
-     *
43
-     * @var string (i18ned)
44
-     */
45
-    protected $_pretty_name = null;
46
-
47
-    /**
48
-     * @var array
49
-     */
50
-    protected $_errors = array();
51
-
52
-    /**
53
-     * @var \EventEspresso\core\services\database\TableManager $table_manager
54
-     */
55
-    protected $_table_manager;
56
-
57
-    /**
58
-     * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
59
-     */
60
-    protected $_table_analysis;
61
-
62
-
63
-    /**
64
-     * Just initializes the status of the migration
65
-     *
66
-     * @param TableManager  $table_manager
67
-     * @param TableAnalysis $table_analysis
68
-     */
69
-    public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
70
-    {
71
-        $this->_table_manager = $table_manager;
72
-        $this->_table_analysis = $table_analysis;
73
-        $this->set_status(EE_Data_Migration_Manager::status_continue);
74
-    }
75
-
76
-
77
-    /**
78
-     * Just gets the pretty name for this migration script or stage
79
-     *
80
-     * @throws EE_Error
81
-     * @return string
82
-     */
83
-    public function pretty_name()
84
-    {
85
-        if ($this->_pretty_name === null) {
86
-            throw new EE_Error(
87
-                sprintf(
88
-                    __(
89
-                        "Please give a pretty name to the migration script stage %s by assigning the property _pretty_name in the constructor",
90
-                        "event_espresso"
91
-                    ),
92
-                    get_class($this)
93
-                )
94
-            );
95
-        }
96
-        return $this->_pretty_name;
97
-    }
98
-
99
-    /**
100
-     *
101
-     * @return int
102
-     */
103
-    public function count_records_to_migrate()
104
-    {
105
-        if ($this->_records_to_migrate == null) {
106
-            $this->_records_to_migrate = $this->_count_records_to_migrate();
107
-        }
108
-        return $this->_records_to_migrate;
109
-    }
110
-
111
-    /**
112
-     * Counts records already migrated. This should only be implemented by EE_Data_Migration_Script_base and
113
-     * EE_Data_migration_Script_Stage
114
-     *
115
-     * @return int
116
-     */
117
-    abstract public function count_records_migrated();
118
-
119
-    /**
120
-     * Counts the records to migrate; the public version may cache it
121
-     *
122
-     * @return int
123
-     */
124
-    abstract protected function _count_records_to_migrate();
125
-
126
-    /**
127
-     * Returns a string indicating the migration script's status.
128
-     *
129
-     * @return string one of EE_Data_Migration_Manager::status_* constants
130
-     * @throws EE_Error
131
-     */
132
-    public function get_status()
133
-    {
134
-        if ($this->_status === null) {
135
-            throw new EE_Error(
136
-                sprintf(
137
-                    __(
138
-                        "Trying to get status of Migration class %s, but it has not been initialized yet. It should be set in the constructor.",
139
-                        "event_espresso"
140
-                    ),
141
-                    get_class($this)
142
-                )
143
-            );
144
-        }
145
-        return $this->_status;
146
-    }
147
-
148
-    /**
149
-     *
150
-     * @param string $status
151
-     * @return void
152
-     */
153
-    protected function set_status($status)
154
-    {
155
-        $this->_status = $status;
156
-    }
157
-
158
-    /**
159
-     * @return array of strings
160
-     */
161
-    abstract public function get_errors();
162
-
163
-    /**
164
-     * Returns the last error that occurred. If none occurred, returns null
165
-     *
166
-     * @return string
167
-     */
168
-    public function get_last_error()
169
-    {
170
-        $errors = $this->get_errors();
171
-        if ($errors) {
172
-            return end($errors);
173
-        } else {
174
-            return null;
175
-        }
176
-    }
177
-
178
-    /**
179
-     * Adds an error to the array of errors on this class.
180
-     *
181
-     * @param string  $error a string describing the error that will be useful for debugging. Consider including all
182
-     *                       the data that led to the error, and a stack trace etc.
183
-     * @param boolean $force force the error to be added (because otherwise we have a limit). If forcing and errors are
184
-     *                       already at their limit, we will purposefully forget the first half
185
-     */
186
-    public function add_error($error, $force = false)
187
-    {
188
-        if (! defined('EE_DMS_ERROR_LIMIT')) {
189
-            $limit = 50;
190
-        } else {
191
-            $limit = EE_DMS_ERROR_LIMIT;
192
-        }
193
-        // make sure errors is an array, see ticket #8261
194
-        if (is_string($this->_errors)) {
195
-            $this->_errors = array($this->_errors);
196
-        }
197
-        if (count($this->_errors) >= $limit) {
198
-            if ($force) {
199
-                // get rid of the first half of the errors and any above the limit
200
-                $this->_errors = array_slice($this->_errors, $limit / 2, $limit / 2);
201
-                $this->_errors[] = "Limit reached; removed first half of errors to save space";
202
-                $this->_errors[] = $error;
203
-            } else {
204
-                $this->_errors[ $limit ] = 'More, but limit reached...';
205
-            }
206
-        } else {
207
-            $this->_errors[] = $error;
208
-        }
209
-    }
210
-
211
-    /**
212
-     * Indicates there was a fatal error and the migration cannot possibly continue
213
-     *
214
-     * @return boolean
215
-     */
216
-    public function is_broken()
217
-    {
218
-        return $this->get_status() == EE_Data_Migration_Manager::status_fatal_error;
219
-    }
220
-
221
-    /**
222
-     * @deprecated since 4.6.12
223
-     */
224
-    public function is_borked()
225
-    {
226
-        EE_Error::doing_it_wrong(
227
-            'is_borked',
228
-            __(
229
-                'The cheeky "is_borked" method had been replaced with the more proper "is_broken"',
230
-                'event_espresso'
231
-            ),
232
-            '4.6.12'
233
-        );
234
-        return $this->is_broken();
235
-    }
236
-
237
-    /**
238
-     * Sets the status to as having a fatal error
239
-     */
240
-    public function set_broken()
241
-    {
242
-        $this->_status = EE_Data_Migration_Manager::status_fatal_error;
243
-    }
244
-
245
-    /**
246
-     *
247
-     * @deprecated since 4.6.12
248
-     */
249
-    public function set_borked()
250
-    {
251
-        EE_Error::doing_it_wrong(
252
-            'is_borked',
253
-            __(
254
-                'The cheeky "is_borked" method had been replaced with the more proper "is_broken"',
255
-                'event_espresso'
256
-            ),
257
-            '4.6.12'
258
-        );
259
-        return $this->set_broken();
260
-    }
261
-
262
-    /**
263
-     * Checks if this thing believes it is completed
264
-     *
265
-     * @return boolean
266
-     */
267
-    public function is_completed()
268
-    {
269
-        return $this->get_status() == EE_Data_Migration_Manager::status_completed;
270
-    }
271
-
272
-    /**
273
-     * Checks if the current script has more to do or not (ie, if it's status is CONTINUE)
274
-     *
275
-     * @return boolean
276
-     */
277
-    public function has_more_to_do()
278
-    {
279
-        return $this->get_status() == EE_Data_Migration_Manager::status_continue;
280
-    }
281
-
282
-    /**
283
-     * Marks that we believe this migration thing is completed
284
-     */
285
-    public function set_completed()
286
-    {
287
-        $this->_status = EE_Data_Migration_Manager::status_completed;
288
-    }
289
-
290
-    /**
291
-     * Marks that we think this migration class can continue to migrate
292
-     */
293
-    public function reattempt()
294
-    {
295
-        $this->_status = EE_Data_Migration_Manager::status_continue;
296
-        $this->add_error(__('Reattempt migration', 'event_espresso'), true);
297
-    }
298
-
299
-    /**
300
-     * A lot like "__sleep()" magic method in purpose, this is meant for persisting this class'
301
-     * properties to the DB. However, we don't want to use __sleep() because its quite
302
-     * possible that this class is defined when it goes to sleep, but NOT available when it
303
-     * awakes (eg, this class is part of an addon that is deactivated at some point).
304
-     */
305
-    public function properties_as_array()
306
-    {
307
-        $properties = get_object_vars($this);
308
-        $properties['class'] = get_class($this);
309
-        unset($properties['_migration_script']);
310
-        unset($properties['_table_manager']);
311
-        unset($properties['_table_analysis']);
312
-        return $properties;
313
-    }
314
-
315
-    /**
316
-     * Sets all of the properties of this script stage to match what's in the array, which is assumed
317
-     * to have been made from the properties_as_array() function.
318
-     *
319
-     * @param array $array_of_properties like what's produced from properties_as_array() method
320
-     */
321
-    abstract public function instantiate_from_array_of_properties($array_of_properties);
322
-
323
-    /**
324
-     * Convenience method for showing a database insertion error
325
-     *
326
-     * @param string $old_table
327
-     * @param array  $old_row_as_array
328
-     * @param string $new_table
329
-     * @param array  $new_row_as_array columns=>values like used in wpdb->insert
330
-     * @param array  $data_types       numerically indexed
331
-     * @return string
332
-     */
333
-    protected function _create_error_message_for_db_insertion(
334
-        $old_table,
335
-        $old_row_as_array,
336
-        $new_table,
337
-        $new_row_as_array,
338
-        $data_types
339
-    ) {
340
-        global $wpdb;
341
-        $old_columns_and_values_for_string = array();
342
-        foreach ($old_row_as_array as $column => $value) {
343
-            $old_columns_and_values_for_string[] = "$column => $value";
344
-        }
345
-        $new_columns_and_values_for_string = array();
346
-        $count = 0;
347
-        foreach ($new_row_as_array as $column => $value) {
348
-            $new_columns_and_values_for_string[] = " $column => $value (" . $data_types[ $count++ ] . ")";
349
-        }
350
-        return sprintf(
351
-            __(
352
-                'Received error "%6$s" inserting row %5$s %1$s %5$s into table %2$s.%5$s Data used was %5$s %3$s %5$s from table %4$s.',
353
-                'event_espresso'
354
-            ),
355
-            implode(", ", $new_columns_and_values_for_string),
356
-            $new_table,
357
-            implode(", ", $old_columns_and_values_for_string),
358
-            $old_table,
359
-            '<br/>',
360
-            $wpdb->last_error
361
-        );
362
-    }
363
-
364
-
365
-    /**
366
-     * Same as json_encode, just avoids putting
367
-     * serialized arrays into the http build query, as that would
368
-     *
369
-     * @param array $array_of_data
370
-     * @return string
371
-     */
372
-    protected function _json_encode($array_of_data)
373
-    {
374
-        // we'd rather NOT serialize the transaction details
375
-        $fields_to_include = array();
376
-        foreach ($array_of_data as $name => $value) {
377
-            $unserialized_data = @unserialize($value);
378
-            if ($unserialized_data === false) {
379
-                $fields_to_include[ $name ] = $value;
380
-            }
381
-        }
382
-        return wp_json_encode($fields_to_include);
383
-    }
384
-
385
-    /**
386
-     * Gets the table manager (or throws an exception if it cannot be retrieved)
387
-     *
388
-     * @return TableManager
389
-     * @throws EE_Error
390
-     */
391
-    protected function _get_table_manager()
392
-    {
393
-        if ($this->_table_manager instanceof TableManager) {
394
-            return $this->_table_manager;
395
-        } else {
396
-            throw new EE_Error(
397
-                sprintf(
398
-                    __('Table manager on migration class %1$s is not set properly.', 'event_espresso'),
399
-                    get_class($this)
400
-                )
401
-            );
402
-        }
403
-    }
404
-
405
-    /**
406
-     * Gets the injected table analyzer, or throws an exception
407
-     *
408
-     * @return TableAnalysis
409
-     * @throws EE_Error
410
-     */
411
-    protected function _get_table_analysis()
412
-    {
413
-        if ($this->_table_analysis instanceof TableAnalysis) {
414
-            return $this->_table_analysis;
415
-        } else {
416
-            throw new EE_Error(
417
-                sprintf(
418
-                    __('Table analysis class on migration class %1$s is not set properly.', 'event_espresso'),
419
-                    get_class($this)
420
-                )
421
-            );
422
-        }
423
-    }
20
+	/**
21
+	 * @var $records_to_migrate int count of all that have been migrated
22
+	 */
23
+	protected $_records_to_migrate = 0;
24
+
25
+	/**
26
+	 *
27
+	 * @var $records_migrated int
28
+	 */
29
+	protected $_records_migrated = 0;
30
+
31
+	/**
32
+	 * Whether this migration script is done or not. This COULD be deduced by
33
+	 * _records_to_migrate and _records_migrated, but that might nto be accurate
34
+	 *
35
+	 * @var string one of EE_Data_migration_Manager::status_* constants
36
+	 */
37
+	protected $_status = null;
38
+
39
+	/**
40
+	 * internationalized name of this class. Convention is to NOT restate that
41
+	 * this class if a migration script or a migration script stage
42
+	 *
43
+	 * @var string (i18ned)
44
+	 */
45
+	protected $_pretty_name = null;
46
+
47
+	/**
48
+	 * @var array
49
+	 */
50
+	protected $_errors = array();
51
+
52
+	/**
53
+	 * @var \EventEspresso\core\services\database\TableManager $table_manager
54
+	 */
55
+	protected $_table_manager;
56
+
57
+	/**
58
+	 * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
59
+	 */
60
+	protected $_table_analysis;
61
+
62
+
63
+	/**
64
+	 * Just initializes the status of the migration
65
+	 *
66
+	 * @param TableManager  $table_manager
67
+	 * @param TableAnalysis $table_analysis
68
+	 */
69
+	public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
70
+	{
71
+		$this->_table_manager = $table_manager;
72
+		$this->_table_analysis = $table_analysis;
73
+		$this->set_status(EE_Data_Migration_Manager::status_continue);
74
+	}
75
+
76
+
77
+	/**
78
+	 * Just gets the pretty name for this migration script or stage
79
+	 *
80
+	 * @throws EE_Error
81
+	 * @return string
82
+	 */
83
+	public function pretty_name()
84
+	{
85
+		if ($this->_pretty_name === null) {
86
+			throw new EE_Error(
87
+				sprintf(
88
+					__(
89
+						"Please give a pretty name to the migration script stage %s by assigning the property _pretty_name in the constructor",
90
+						"event_espresso"
91
+					),
92
+					get_class($this)
93
+				)
94
+			);
95
+		}
96
+		return $this->_pretty_name;
97
+	}
98
+
99
+	/**
100
+	 *
101
+	 * @return int
102
+	 */
103
+	public function count_records_to_migrate()
104
+	{
105
+		if ($this->_records_to_migrate == null) {
106
+			$this->_records_to_migrate = $this->_count_records_to_migrate();
107
+		}
108
+		return $this->_records_to_migrate;
109
+	}
110
+
111
+	/**
112
+	 * Counts records already migrated. This should only be implemented by EE_Data_Migration_Script_base and
113
+	 * EE_Data_migration_Script_Stage
114
+	 *
115
+	 * @return int
116
+	 */
117
+	abstract public function count_records_migrated();
118
+
119
+	/**
120
+	 * Counts the records to migrate; the public version may cache it
121
+	 *
122
+	 * @return int
123
+	 */
124
+	abstract protected function _count_records_to_migrate();
125
+
126
+	/**
127
+	 * Returns a string indicating the migration script's status.
128
+	 *
129
+	 * @return string one of EE_Data_Migration_Manager::status_* constants
130
+	 * @throws EE_Error
131
+	 */
132
+	public function get_status()
133
+	{
134
+		if ($this->_status === null) {
135
+			throw new EE_Error(
136
+				sprintf(
137
+					__(
138
+						"Trying to get status of Migration class %s, but it has not been initialized yet. It should be set in the constructor.",
139
+						"event_espresso"
140
+					),
141
+					get_class($this)
142
+				)
143
+			);
144
+		}
145
+		return $this->_status;
146
+	}
147
+
148
+	/**
149
+	 *
150
+	 * @param string $status
151
+	 * @return void
152
+	 */
153
+	protected function set_status($status)
154
+	{
155
+		$this->_status = $status;
156
+	}
157
+
158
+	/**
159
+	 * @return array of strings
160
+	 */
161
+	abstract public function get_errors();
162
+
163
+	/**
164
+	 * Returns the last error that occurred. If none occurred, returns null
165
+	 *
166
+	 * @return string
167
+	 */
168
+	public function get_last_error()
169
+	{
170
+		$errors = $this->get_errors();
171
+		if ($errors) {
172
+			return end($errors);
173
+		} else {
174
+			return null;
175
+		}
176
+	}
177
+
178
+	/**
179
+	 * Adds an error to the array of errors on this class.
180
+	 *
181
+	 * @param string  $error a string describing the error that will be useful for debugging. Consider including all
182
+	 *                       the data that led to the error, and a stack trace etc.
183
+	 * @param boolean $force force the error to be added (because otherwise we have a limit). If forcing and errors are
184
+	 *                       already at their limit, we will purposefully forget the first half
185
+	 */
186
+	public function add_error($error, $force = false)
187
+	{
188
+		if (! defined('EE_DMS_ERROR_LIMIT')) {
189
+			$limit = 50;
190
+		} else {
191
+			$limit = EE_DMS_ERROR_LIMIT;
192
+		}
193
+		// make sure errors is an array, see ticket #8261
194
+		if (is_string($this->_errors)) {
195
+			$this->_errors = array($this->_errors);
196
+		}
197
+		if (count($this->_errors) >= $limit) {
198
+			if ($force) {
199
+				// get rid of the first half of the errors and any above the limit
200
+				$this->_errors = array_slice($this->_errors, $limit / 2, $limit / 2);
201
+				$this->_errors[] = "Limit reached; removed first half of errors to save space";
202
+				$this->_errors[] = $error;
203
+			} else {
204
+				$this->_errors[ $limit ] = 'More, but limit reached...';
205
+			}
206
+		} else {
207
+			$this->_errors[] = $error;
208
+		}
209
+	}
210
+
211
+	/**
212
+	 * Indicates there was a fatal error and the migration cannot possibly continue
213
+	 *
214
+	 * @return boolean
215
+	 */
216
+	public function is_broken()
217
+	{
218
+		return $this->get_status() == EE_Data_Migration_Manager::status_fatal_error;
219
+	}
220
+
221
+	/**
222
+	 * @deprecated since 4.6.12
223
+	 */
224
+	public function is_borked()
225
+	{
226
+		EE_Error::doing_it_wrong(
227
+			'is_borked',
228
+			__(
229
+				'The cheeky "is_borked" method had been replaced with the more proper "is_broken"',
230
+				'event_espresso'
231
+			),
232
+			'4.6.12'
233
+		);
234
+		return $this->is_broken();
235
+	}
236
+
237
+	/**
238
+	 * Sets the status to as having a fatal error
239
+	 */
240
+	public function set_broken()
241
+	{
242
+		$this->_status = EE_Data_Migration_Manager::status_fatal_error;
243
+	}
244
+
245
+	/**
246
+	 *
247
+	 * @deprecated since 4.6.12
248
+	 */
249
+	public function set_borked()
250
+	{
251
+		EE_Error::doing_it_wrong(
252
+			'is_borked',
253
+			__(
254
+				'The cheeky "is_borked" method had been replaced with the more proper "is_broken"',
255
+				'event_espresso'
256
+			),
257
+			'4.6.12'
258
+		);
259
+		return $this->set_broken();
260
+	}
261
+
262
+	/**
263
+	 * Checks if this thing believes it is completed
264
+	 *
265
+	 * @return boolean
266
+	 */
267
+	public function is_completed()
268
+	{
269
+		return $this->get_status() == EE_Data_Migration_Manager::status_completed;
270
+	}
271
+
272
+	/**
273
+	 * Checks if the current script has more to do or not (ie, if it's status is CONTINUE)
274
+	 *
275
+	 * @return boolean
276
+	 */
277
+	public function has_more_to_do()
278
+	{
279
+		return $this->get_status() == EE_Data_Migration_Manager::status_continue;
280
+	}
281
+
282
+	/**
283
+	 * Marks that we believe this migration thing is completed
284
+	 */
285
+	public function set_completed()
286
+	{
287
+		$this->_status = EE_Data_Migration_Manager::status_completed;
288
+	}
289
+
290
+	/**
291
+	 * Marks that we think this migration class can continue to migrate
292
+	 */
293
+	public function reattempt()
294
+	{
295
+		$this->_status = EE_Data_Migration_Manager::status_continue;
296
+		$this->add_error(__('Reattempt migration', 'event_espresso'), true);
297
+	}
298
+
299
+	/**
300
+	 * A lot like "__sleep()" magic method in purpose, this is meant for persisting this class'
301
+	 * properties to the DB. However, we don't want to use __sleep() because its quite
302
+	 * possible that this class is defined when it goes to sleep, but NOT available when it
303
+	 * awakes (eg, this class is part of an addon that is deactivated at some point).
304
+	 */
305
+	public function properties_as_array()
306
+	{
307
+		$properties = get_object_vars($this);
308
+		$properties['class'] = get_class($this);
309
+		unset($properties['_migration_script']);
310
+		unset($properties['_table_manager']);
311
+		unset($properties['_table_analysis']);
312
+		return $properties;
313
+	}
314
+
315
+	/**
316
+	 * Sets all of the properties of this script stage to match what's in the array, which is assumed
317
+	 * to have been made from the properties_as_array() function.
318
+	 *
319
+	 * @param array $array_of_properties like what's produced from properties_as_array() method
320
+	 */
321
+	abstract public function instantiate_from_array_of_properties($array_of_properties);
322
+
323
+	/**
324
+	 * Convenience method for showing a database insertion error
325
+	 *
326
+	 * @param string $old_table
327
+	 * @param array  $old_row_as_array
328
+	 * @param string $new_table
329
+	 * @param array  $new_row_as_array columns=>values like used in wpdb->insert
330
+	 * @param array  $data_types       numerically indexed
331
+	 * @return string
332
+	 */
333
+	protected function _create_error_message_for_db_insertion(
334
+		$old_table,
335
+		$old_row_as_array,
336
+		$new_table,
337
+		$new_row_as_array,
338
+		$data_types
339
+	) {
340
+		global $wpdb;
341
+		$old_columns_and_values_for_string = array();
342
+		foreach ($old_row_as_array as $column => $value) {
343
+			$old_columns_and_values_for_string[] = "$column => $value";
344
+		}
345
+		$new_columns_and_values_for_string = array();
346
+		$count = 0;
347
+		foreach ($new_row_as_array as $column => $value) {
348
+			$new_columns_and_values_for_string[] = " $column => $value (" . $data_types[ $count++ ] . ")";
349
+		}
350
+		return sprintf(
351
+			__(
352
+				'Received error "%6$s" inserting row %5$s %1$s %5$s into table %2$s.%5$s Data used was %5$s %3$s %5$s from table %4$s.',
353
+				'event_espresso'
354
+			),
355
+			implode(", ", $new_columns_and_values_for_string),
356
+			$new_table,
357
+			implode(", ", $old_columns_and_values_for_string),
358
+			$old_table,
359
+			'<br/>',
360
+			$wpdb->last_error
361
+		);
362
+	}
363
+
364
+
365
+	/**
366
+	 * Same as json_encode, just avoids putting
367
+	 * serialized arrays into the http build query, as that would
368
+	 *
369
+	 * @param array $array_of_data
370
+	 * @return string
371
+	 */
372
+	protected function _json_encode($array_of_data)
373
+	{
374
+		// we'd rather NOT serialize the transaction details
375
+		$fields_to_include = array();
376
+		foreach ($array_of_data as $name => $value) {
377
+			$unserialized_data = @unserialize($value);
378
+			if ($unserialized_data === false) {
379
+				$fields_to_include[ $name ] = $value;
380
+			}
381
+		}
382
+		return wp_json_encode($fields_to_include);
383
+	}
384
+
385
+	/**
386
+	 * Gets the table manager (or throws an exception if it cannot be retrieved)
387
+	 *
388
+	 * @return TableManager
389
+	 * @throws EE_Error
390
+	 */
391
+	protected function _get_table_manager()
392
+	{
393
+		if ($this->_table_manager instanceof TableManager) {
394
+			return $this->_table_manager;
395
+		} else {
396
+			throw new EE_Error(
397
+				sprintf(
398
+					__('Table manager on migration class %1$s is not set properly.', 'event_espresso'),
399
+					get_class($this)
400
+				)
401
+			);
402
+		}
403
+	}
404
+
405
+	/**
406
+	 * Gets the injected table analyzer, or throws an exception
407
+	 *
408
+	 * @return TableAnalysis
409
+	 * @throws EE_Error
410
+	 */
411
+	protected function _get_table_analysis()
412
+	{
413
+		if ($this->_table_analysis instanceof TableAnalysis) {
414
+			return $this->_table_analysis;
415
+		} else {
416
+			throw new EE_Error(
417
+				sprintf(
418
+					__('Table analysis class on migration class %1$s is not set properly.', 'event_espresso'),
419
+					get_class($this)
420
+				)
421
+			);
422
+		}
423
+	}
424 424
 }
Please login to merge, or discard this patch.
registrations/form_sections/EE_Registration_Custom_Questions_Form.form.php 2 patches
Indentation   +161 added lines, -161 removed lines patch added patch discarded remove patch
@@ -18,179 +18,179 @@
 block discarded – undo
18 18
  */
19 19
 class EE_Registration_Custom_Questions_Form extends EE_Form_Section_Proper
20 20
 {
21
-    /**
22
-     *
23
-     * @var EE_Registration
24
-     */
25
-    protected $_registration = null;
21
+	/**
22
+	 *
23
+	 * @var EE_Registration
24
+	 */
25
+	protected $_registration = null;
26 26
 
27
-    /**
28
-     *
29
-     * @param EE_Registration $reg
30
-     * @param array $options
31
-     */
32
-    public function __construct(EE_Registration $reg, $options = array())
33
-    {
34
-        $this->_registration = $reg;
35
-        if (! isset($options['layout_strategy'])) {
36
-            $options['layout_strategy'] = new EE_Admin_Two_Column_Layout();
37
-        }
38
-        if (! isset($options['html_id'])) {
39
-            $options['html_id'] = 'reg-admin-attendee-questions-frm';
40
-        }
41
-        $this->build_form_from_registration();
42
-        parent::__construct($options);
43
-    }
27
+	/**
28
+	 *
29
+	 * @param EE_Registration $reg
30
+	 * @param array $options
31
+	 */
32
+	public function __construct(EE_Registration $reg, $options = array())
33
+	{
34
+		$this->_registration = $reg;
35
+		if (! isset($options['layout_strategy'])) {
36
+			$options['layout_strategy'] = new EE_Admin_Two_Column_Layout();
37
+		}
38
+		if (! isset($options['html_id'])) {
39
+			$options['html_id'] = 'reg-admin-attendee-questions-frm';
40
+		}
41
+		$this->build_form_from_registration();
42
+		parent::__construct($options);
43
+	}
44 44
 
45 45
 
46
-    /**
47
-     * Gets the registration object this form is about
48
-     * @return EE_Registration
49
-     */
50
-    public function get_registration()
51
-    {
52
-        return $this->_registration;
53
-    }
46
+	/**
47
+	 * Gets the registration object this form is about
48
+	 * @return EE_Registration
49
+	 */
50
+	public function get_registration()
51
+	{
52
+		return $this->_registration;
53
+	}
54 54
 
55
-    /**
56
-     * @since $VID:$
57
-     * @throws EE_Error
58
-     * @throws InvalidArgumentException
59
-     * @throws ReflectionException
60
-     * @throws InvalidDataTypeException
61
-     * @throws InvalidInterfaceException
62
-     */
63
-    public function build_form_from_registration()
64
-    {
65
-        $reg = $this->get_registration();
66
-        if (! $reg instanceof EE_Registration) {
67
-            throw new EE_Error(__('We cannot build the registration custom questions form because there is no registration set on it yet', 'event_espresso'));
68
-        }
69
-        // we want to get all their question groups
70
-        $question_groups = EEM_Question_Group::instance()->get_all(
71
-            [
72
-                [
73
-                    'Event_Question_Group.EVT_ID' => $reg->event_ID(),
74
-                    'OR' => [
75
-                        'Question.QST_system*blank' =>  '',
76
-                        'Question.QST_system*null' => ['IS_NULL']
77
-                    ],
78
-                    'Event_Question_Group.'
79
-                    . EEM_Event_Question_Group::instance()->fieldNameForContext(
80
-                        $reg->is_primary_registrant()
81
-                    ) => true
82
-                ],
83
-                'order_by' => ['QSG_order' => 'ASC']
84
-            ]
85
-        );
86
-        // get each question groups questions
87
-        foreach ($question_groups as $question_group) {
88
-            if ($question_group instanceof EE_Question_Group) {
89
-                $this->_subsections[ $question_group->ID() ] = $this->build_subform_from_question_group(
90
-                    $question_group,
91
-                    $reg
92
-                );
93
-            }
94
-        }
95
-    }
55
+	/**
56
+	 * @since $VID:$
57
+	 * @throws EE_Error
58
+	 * @throws InvalidArgumentException
59
+	 * @throws ReflectionException
60
+	 * @throws InvalidDataTypeException
61
+	 * @throws InvalidInterfaceException
62
+	 */
63
+	public function build_form_from_registration()
64
+	{
65
+		$reg = $this->get_registration();
66
+		if (! $reg instanceof EE_Registration) {
67
+			throw new EE_Error(__('We cannot build the registration custom questions form because there is no registration set on it yet', 'event_espresso'));
68
+		}
69
+		// we want to get all their question groups
70
+		$question_groups = EEM_Question_Group::instance()->get_all(
71
+			[
72
+				[
73
+					'Event_Question_Group.EVT_ID' => $reg->event_ID(),
74
+					'OR' => [
75
+						'Question.QST_system*blank' =>  '',
76
+						'Question.QST_system*null' => ['IS_NULL']
77
+					],
78
+					'Event_Question_Group.'
79
+					. EEM_Event_Question_Group::instance()->fieldNameForContext(
80
+						$reg->is_primary_registrant()
81
+					) => true
82
+				],
83
+				'order_by' => ['QSG_order' => 'ASC']
84
+			]
85
+		);
86
+		// get each question groups questions
87
+		foreach ($question_groups as $question_group) {
88
+			if ($question_group instanceof EE_Question_Group) {
89
+				$this->_subsections[ $question_group->ID() ] = $this->build_subform_from_question_group(
90
+					$question_group,
91
+					$reg
92
+				);
93
+			}
94
+		}
95
+	}
96 96
 
97 97
 
98 98
 
99
-    /**
100
-     *
101
-     * @param EE_Question_Group $question_group
102
-     * @param EE_Registration   $registration
103
-     * @return \EE_Form_Section_Proper
104
-     * @throws \EE_Error
105
-     */
106
-    public function build_subform_from_question_group($question_group, $registration)
107
-    {
108
-        if (! $question_group instanceof EE_Question_Group ||
109
-            ! $registration instanceof EE_Registration) {
110
-            throw new EE_Error(__('A valid question group and registration must be passed to EE_Registration_Custom_Question_Form', 'event_espresso'));
111
-        }
112
-        $parts_of_subsection = array(
113
-            'title' => new EE_Form_Section_HTML(
114
-                EEH_HTML::h5(
115
-                    $question_group->name(),
116
-                    $question_group->identifier(),
117
-                    'espresso-question-group-title-h5 section-title'
118
-                )
119
-            )
120
-        );
121
-        $questions = $question_group->questions(
122
-            array(
123
-                array(
124
-                    'OR' => array(
125
-                        'QST_system*blank' => '',
126
-                        'QST_system*null' => array( 'IS_NULL' )
127
-                    )
128
-                )
129
-            )
130
-        );
131
-        foreach ($questions as $question) {
132
-            $parts_of_subsection[ $question->ID() ] = $question->generate_form_input($registration);
133
-        }
134
-        if (EE_Registry::instance()->CAP->current_user_can(
135
-            'ee_edit_registration',
136
-            'edit-reg-questions-mbox',
137
-            $this->_registration->ID()
138
-        )) {
139
-            $parts_of_subsection['edit_link'] = new EE_Form_Section_HTML(
140
-                '<tr><th/><td class="reg-admin-edit-attendee-question-td"><a class="reg-admin-edit-attendee-question-lnk" href="#" aria-label="' . esc_attr__('click to edit question', 'event_espresso') . '">
99
+	/**
100
+	 *
101
+	 * @param EE_Question_Group $question_group
102
+	 * @param EE_Registration   $registration
103
+	 * @return \EE_Form_Section_Proper
104
+	 * @throws \EE_Error
105
+	 */
106
+	public function build_subform_from_question_group($question_group, $registration)
107
+	{
108
+		if (! $question_group instanceof EE_Question_Group ||
109
+			! $registration instanceof EE_Registration) {
110
+			throw new EE_Error(__('A valid question group and registration must be passed to EE_Registration_Custom_Question_Form', 'event_espresso'));
111
+		}
112
+		$parts_of_subsection = array(
113
+			'title' => new EE_Form_Section_HTML(
114
+				EEH_HTML::h5(
115
+					$question_group->name(),
116
+					$question_group->identifier(),
117
+					'espresso-question-group-title-h5 section-title'
118
+				)
119
+			)
120
+		);
121
+		$questions = $question_group->questions(
122
+			array(
123
+				array(
124
+					'OR' => array(
125
+						'QST_system*blank' => '',
126
+						'QST_system*null' => array( 'IS_NULL' )
127
+					)
128
+				)
129
+			)
130
+		);
131
+		foreach ($questions as $question) {
132
+			$parts_of_subsection[ $question->ID() ] = $question->generate_form_input($registration);
133
+		}
134
+		if (EE_Registry::instance()->CAP->current_user_can(
135
+			'ee_edit_registration',
136
+			'edit-reg-questions-mbox',
137
+			$this->_registration->ID()
138
+		)) {
139
+			$parts_of_subsection['edit_link'] = new EE_Form_Section_HTML(
140
+				'<tr><th/><td class="reg-admin-edit-attendee-question-td"><a class="reg-admin-edit-attendee-question-lnk" href="#" aria-label="' . esc_attr__('click to edit question', 'event_espresso') . '">
141 141
 		  			<span class="reg-admin-edit-question-group-spn">' . __('edit the above question group', 'event_espresso') . '</span>
142 142
 		  			<div class="dashicons dashicons-edit"></div>
143 143
 		  		</a></td></tr>'
144
-            );
145
-        }
146
-        return new EE_Form_Section_Proper(
147
-            array(
148
-                'subsections' => $parts_of_subsection,
149
-                'html_class' => 'question-group-questions',
150
-            )
151
-        );
152
-    }
144
+			);
145
+		}
146
+		return new EE_Form_Section_Proper(
147
+			array(
148
+				'subsections' => $parts_of_subsection,
149
+				'html_class' => 'question-group-questions',
150
+			)
151
+		);
152
+	}
153 153
 
154
-    /**
155
-     * Overrides parent so if inputs were disabled, we leave those with their defaults
156
-     * from the answers in the DB
157
-     * @param array $req_data like $_POST
158
-     * @return void
159
-     */
160
-    protected function _normalize($req_data)
161
-    {
162
-        $this->_received_submission = true;
163
-        $this->_validation_errors = array();
164
-        foreach ($this->get_validatable_subsections() as $subsection) {
165
-            if ($subsection->form_data_present_in($req_data)) {
166
-                try {
167
-                    $subsection->_normalize($req_data);
168
-                } catch (EE_Validation_Error $e) {
169
-                    $subsection->add_validation_error($e);
170
-                }
171
-            }
172
-        }
173
-    }
154
+	/**
155
+	 * Overrides parent so if inputs were disabled, we leave those with their defaults
156
+	 * from the answers in the DB
157
+	 * @param array $req_data like $_POST
158
+	 * @return void
159
+	 */
160
+	protected function _normalize($req_data)
161
+	{
162
+		$this->_received_submission = true;
163
+		$this->_validation_errors = array();
164
+		foreach ($this->get_validatable_subsections() as $subsection) {
165
+			if ($subsection->form_data_present_in($req_data)) {
166
+				try {
167
+					$subsection->_normalize($req_data);
168
+				} catch (EE_Validation_Error $e) {
169
+					$subsection->add_validation_error($e);
170
+				}
171
+			}
172
+		}
173
+	}
174 174
 
175 175
 
176 176
 
177
-    /**
178
-     * Performs validation on this form section and its subsections. For each subsection,
179
-     * calls _validate_{subsection_name} on THIS form (if the function exists) and passes it the subsection, then calls _validate on that subsection.
180
-     * If you need to perform validation on the form as a whole (considering multiple) you would be best to override this _validate method,
181
-     * calling parent::_validate() first.
182
-     */
183
-    protected function _validate()
184
-    {
185
-        foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
186
-            if ($subsection->form_data_present_in(array_merge($_GET, $_POST))) {
187
-                if (method_exists($this, '_validate_'.$subsection_name)) {
188
-                    call_user_func_array(array($this,'_validate_'.$subsection_name), array($subsection));
189
-                }
190
-                $subsection->_validate();
191
-            } elseif ($subsection instanceof EE_Form_Section_Proper) {
192
-                $subsection->_received_submission = true;
193
-            }
194
-        }
195
-    }
177
+	/**
178
+	 * Performs validation on this form section and its subsections. For each subsection,
179
+	 * calls _validate_{subsection_name} on THIS form (if the function exists) and passes it the subsection, then calls _validate on that subsection.
180
+	 * If you need to perform validation on the form as a whole (considering multiple) you would be best to override this _validate method,
181
+	 * calling parent::_validate() first.
182
+	 */
183
+	protected function _validate()
184
+	{
185
+		foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
186
+			if ($subsection->form_data_present_in(array_merge($_GET, $_POST))) {
187
+				if (method_exists($this, '_validate_'.$subsection_name)) {
188
+					call_user_func_array(array($this,'_validate_'.$subsection_name), array($subsection));
189
+				}
190
+				$subsection->_validate();
191
+			} elseif ($subsection instanceof EE_Form_Section_Proper) {
192
+				$subsection->_received_submission = true;
193
+			}
194
+		}
195
+	}
196 196
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -32,10 +32,10 @@  discard block
 block discarded – undo
32 32
     public function __construct(EE_Registration $reg, $options = array())
33 33
     {
34 34
         $this->_registration = $reg;
35
-        if (! isset($options['layout_strategy'])) {
35
+        if ( ! isset($options['layout_strategy'])) {
36 36
             $options['layout_strategy'] = new EE_Admin_Two_Column_Layout();
37 37
         }
38
-        if (! isset($options['html_id'])) {
38
+        if ( ! isset($options['html_id'])) {
39 39
             $options['html_id'] = 'reg-admin-attendee-questions-frm';
40 40
         }
41 41
         $this->build_form_from_registration();
@@ -63,7 +63,7 @@  discard block
 block discarded – undo
63 63
     public function build_form_from_registration()
64 64
     {
65 65
         $reg = $this->get_registration();
66
-        if (! $reg instanceof EE_Registration) {
66
+        if ( ! $reg instanceof EE_Registration) {
67 67
             throw new EE_Error(__('We cannot build the registration custom questions form because there is no registration set on it yet', 'event_espresso'));
68 68
         }
69 69
         // we want to get all their question groups
@@ -86,7 +86,7 @@  discard block
 block discarded – undo
86 86
         // get each question groups questions
87 87
         foreach ($question_groups as $question_group) {
88 88
             if ($question_group instanceof EE_Question_Group) {
89
-                $this->_subsections[ $question_group->ID() ] = $this->build_subform_from_question_group(
89
+                $this->_subsections[$question_group->ID()] = $this->build_subform_from_question_group(
90 90
                     $question_group,
91 91
                     $reg
92 92
                 );
@@ -105,7 +105,7 @@  discard block
 block discarded – undo
105 105
      */
106 106
     public function build_subform_from_question_group($question_group, $registration)
107 107
     {
108
-        if (! $question_group instanceof EE_Question_Group ||
108
+        if ( ! $question_group instanceof EE_Question_Group ||
109 109
             ! $registration instanceof EE_Registration) {
110 110
             throw new EE_Error(__('A valid question group and registration must be passed to EE_Registration_Custom_Question_Form', 'event_espresso'));
111 111
         }
@@ -123,13 +123,13 @@  discard block
 block discarded – undo
123 123
                 array(
124 124
                     'OR' => array(
125 125
                         'QST_system*blank' => '',
126
-                        'QST_system*null' => array( 'IS_NULL' )
126
+                        'QST_system*null' => array('IS_NULL')
127 127
                     )
128 128
                 )
129 129
             )
130 130
         );
131 131
         foreach ($questions as $question) {
132
-            $parts_of_subsection[ $question->ID() ] = $question->generate_form_input($registration);
132
+            $parts_of_subsection[$question->ID()] = $question->generate_form_input($registration);
133 133
         }
134 134
         if (EE_Registry::instance()->CAP->current_user_can(
135 135
             'ee_edit_registration',
@@ -137,8 +137,8 @@  discard block
 block discarded – undo
137 137
             $this->_registration->ID()
138 138
         )) {
139 139
             $parts_of_subsection['edit_link'] = new EE_Form_Section_HTML(
140
-                '<tr><th/><td class="reg-admin-edit-attendee-question-td"><a class="reg-admin-edit-attendee-question-lnk" href="#" aria-label="' . esc_attr__('click to edit question', 'event_espresso') . '">
141
-		  			<span class="reg-admin-edit-question-group-spn">' . __('edit the above question group', 'event_espresso') . '</span>
140
+                '<tr><th/><td class="reg-admin-edit-attendee-question-td"><a class="reg-admin-edit-attendee-question-lnk" href="#" aria-label="'.esc_attr__('click to edit question', 'event_espresso').'">
141
+		  			<span class="reg-admin-edit-question-group-spn">' . __('edit the above question group', 'event_espresso').'</span>
142 142
 		  			<div class="dashicons dashicons-edit"></div>
143 143
 		  		</a></td></tr>'
144 144
             );
@@ -185,7 +185,7 @@  discard block
 block discarded – undo
185 185
         foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
186 186
             if ($subsection->form_data_present_in(array_merge($_GET, $_POST))) {
187 187
                 if (method_exists($this, '_validate_'.$subsection_name)) {
188
-                    call_user_func_array(array($this,'_validate_'.$subsection_name), array($subsection));
188
+                    call_user_func_array(array($this, '_validate_'.$subsection_name), array($subsection));
189 189
                 }
190 190
                 $subsection->_validate();
191 191
             } elseif ($subsection instanceof EE_Form_Section_Proper) {
Please login to merge, or discard this patch.
4_10_0_stages/EE_DMS_4_10_0_Event_Question_Group.dmsstage.php 2 patches
Indentation   +110 added lines, -110 removed lines patch added patch discarded remove patch
@@ -14,118 +14,118 @@
 block discarded – undo
14 14
 
15 15
 
16 16
 
17
-    /**
18
-     * Just initializes the status of the migration
19
-     */
20
-    public function __construct()
21
-    {
22
-        global $wpdb;
23
-        $this->_pretty_name = __('Event-Question Group Relations', 'event_espresso');
24
-        $this->_old_table = $wpdb->prefix.'esp_event_question_group';
25
-        $this->_extra_where_sql = "WHERE EQG_primary = 0 AND EQG_additional=0";
26
-        parent::__construct();
27
-    }
17
+	/**
18
+	 * Just initializes the status of the migration
19
+	 */
20
+	public function __construct()
21
+	{
22
+		global $wpdb;
23
+		$this->_pretty_name = __('Event-Question Group Relations', 'event_espresso');
24
+		$this->_old_table = $wpdb->prefix.'esp_event_question_group';
25
+		$this->_extra_where_sql = "WHERE EQG_primary = 0 AND EQG_additional=0";
26
+		parent::__construct();
27
+	}
28 28
 
29 29
 
30
-    /**
31
-     * Removes the duplicate event_question_group rows that only had EQG_primary=0. Now we just have one row
32
-     * joining event-to-question-groups with two columns: EQG_primary and EQG_additional, indicating which question
33
-     * groups apply to which category of registrant.
34
-     * @param array $event_question_group an associative array where keys are column names and values are their values.
35
-     * @return null
36
-     */
37
-    protected function _migrate_old_row($event_question_group)
38
-    {
39
-        if (isset($event_question_group['EVT_ID'], $event_question_group['QSG_ID'])) {
40
-            global $wpdb;
41
-            // If the question group was also for primary attendees, we should just update that row.
42
-            // And we delete this row.
43
-            $success = $wpdb->update(
44
-                $this->_old_table,
45
-                ['EQG_additional' => true],  // data
46
-                [
47
-                    'EQG_primary' => true,
48
-                    'EVT_ID' => $event_question_group['EVT_ID'],
49
-                    'QSG_ID' => $event_question_group['QSG_ID']
50
-                ],  // where
51
-                array( '%d' ),   // data format
52
-                array( '%d', '%d', '%d' )  // where format
53
-            );
54
-            if ($success) {
55
-                // Ok it's confirmed: the question group WAS for the primary attendee group too. So
56
-                // now we just need to delete this row.
57
-                $successful_delete = $wpdb->delete(
58
-                    $this->_old_table,
59
-                    [
60
-                        'EQG_ID' => $event_question_group['EQG_ID']
61
-                    ],
62
-                    ['%d']
63
-                );
64
-                if (! $successful_delete) {
65
-                    $this->add_error(
66
-                        sprintf(
67
-                            __('Could not delete old event-question group relation row "%1$s" because "%2$s"', 'event_espresso'),
68
-                            wp_json_encode($event_question_group),
69
-                            $wpdb->last_error
70
-                        )
71
-                    );
72
-                }
73
-            } else {
74
-                // Oh, the question group actually was NOT for the primary attendee. So we just need to update this row
75
-                $wpdb->update(
76
-                    $this->_old_table,
77
-                    ['EQG_additional' => true],  // data
78
-                    [
79
-                        'EVT_ID' => $event_question_group['EVT_ID'],
80
-                        'QSG_ID' => $event_question_group['QSG_ID']
81
-                    ],  // where
82
-                    array( '%d' ),   // data format
83
-                    array( '%d', '%d', '%d' )  // where format
84
-                );
85
-            }
86
-        }
87
-    }
30
+	/**
31
+	 * Removes the duplicate event_question_group rows that only had EQG_primary=0. Now we just have one row
32
+	 * joining event-to-question-groups with two columns: EQG_primary and EQG_additional, indicating which question
33
+	 * groups apply to which category of registrant.
34
+	 * @param array $event_question_group an associative array where keys are column names and values are their values.
35
+	 * @return null
36
+	 */
37
+	protected function _migrate_old_row($event_question_group)
38
+	{
39
+		if (isset($event_question_group['EVT_ID'], $event_question_group['QSG_ID'])) {
40
+			global $wpdb;
41
+			// If the question group was also for primary attendees, we should just update that row.
42
+			// And we delete this row.
43
+			$success = $wpdb->update(
44
+				$this->_old_table,
45
+				['EQG_additional' => true],  // data
46
+				[
47
+					'EQG_primary' => true,
48
+					'EVT_ID' => $event_question_group['EVT_ID'],
49
+					'QSG_ID' => $event_question_group['QSG_ID']
50
+				],  // where
51
+				array( '%d' ),   // data format
52
+				array( '%d', '%d', '%d' )  // where format
53
+			);
54
+			if ($success) {
55
+				// Ok it's confirmed: the question group WAS for the primary attendee group too. So
56
+				// now we just need to delete this row.
57
+				$successful_delete = $wpdb->delete(
58
+					$this->_old_table,
59
+					[
60
+						'EQG_ID' => $event_question_group['EQG_ID']
61
+					],
62
+					['%d']
63
+				);
64
+				if (! $successful_delete) {
65
+					$this->add_error(
66
+						sprintf(
67
+							__('Could not delete old event-question group relation row "%1$s" because "%2$s"', 'event_espresso'),
68
+							wp_json_encode($event_question_group),
69
+							$wpdb->last_error
70
+						)
71
+					);
72
+				}
73
+			} else {
74
+				// Oh, the question group actually was NOT for the primary attendee. So we just need to update this row
75
+				$wpdb->update(
76
+					$this->_old_table,
77
+					['EQG_additional' => true],  // data
78
+					[
79
+						'EVT_ID' => $event_question_group['EVT_ID'],
80
+						'QSG_ID' => $event_question_group['QSG_ID']
81
+					],  // where
82
+					array( '%d' ),   // data format
83
+					array( '%d', '%d', '%d' )  // where format
84
+				);
85
+			}
86
+		}
87
+	}
88 88
 
89
-    /**
90
-     * Gets the rows for the existing table that shouldn't exist in 4.10.
91
-     * Specifically the rows where EQG_primary=false and EQG_additional=false.
92
-     * Gotcha: because the migration is REMOVING rows as it goes, we shouldn't use the offset.
93
-     *
94
-     * @global wpdb $wpdb
95
-     * @param int   $limit
96
-     * @return array of arrays like $wpdb->get_results($sql, ARRAY_A)
97
-     */
98
-    protected function _get_rows($limit)
99
-    {
100
-        global $wpdb;
101
-        $query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} " . $wpdb->prepare(
102
-            "LIMIT %d",
103
-            $limit
104
-        );
105
-        return $wpdb->get_results($query, ARRAY_A);
106
-    }
89
+	/**
90
+	 * Gets the rows for the existing table that shouldn't exist in 4.10.
91
+	 * Specifically the rows where EQG_primary=false and EQG_additional=false.
92
+	 * Gotcha: because the migration is REMOVING rows as it goes, we shouldn't use the offset.
93
+	 *
94
+	 * @global wpdb $wpdb
95
+	 * @param int   $limit
96
+	 * @return array of arrays like $wpdb->get_results($sql, ARRAY_A)
97
+	 */
98
+	protected function _get_rows($limit)
99
+	{
100
+		global $wpdb;
101
+		$query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} " . $wpdb->prepare(
102
+			"LIMIT %d",
103
+			$limit
104
+		);
105
+		return $wpdb->get_results($query, ARRAY_A);
106
+	}
107 107
 
108
-    /**
109
-     * Slight departure from the normal procedure here: because this removes rows from the DB, we need to ensure
110
-     * we count the records first, then do the migration.
111
-     *
112
-     * @param int $num_items
113
-     * @return int number of items ACTUALLY migrated
114
-     */
115
-    public function _migration_step($num_items = 50)
116
-    {
117
-        // Count the items right away. This migration step will be removing those rows, so we need to count them
118
-        // right away to get an accurate count.
119
-        $this->count_records_to_migrate();
120
-        $rows = $this->_get_rows($num_items);
121
-        $items_actually_migrated = 0;
122
-        foreach ($rows as $old_row) {
123
-            $this->_migrate_old_row($old_row);
124
-            $items_actually_migrated++;
125
-        }
126
-        if ($this->count_records_migrated() + $items_actually_migrated >= $this->count_records_to_migrate()) {
127
-            $this->set_completed();
128
-        }
129
-        return $items_actually_migrated;
130
-    }
108
+	/**
109
+	 * Slight departure from the normal procedure here: because this removes rows from the DB, we need to ensure
110
+	 * we count the records first, then do the migration.
111
+	 *
112
+	 * @param int $num_items
113
+	 * @return int number of items ACTUALLY migrated
114
+	 */
115
+	public function _migration_step($num_items = 50)
116
+	{
117
+		// Count the items right away. This migration step will be removing those rows, so we need to count them
118
+		// right away to get an accurate count.
119
+		$this->count_records_to_migrate();
120
+		$rows = $this->_get_rows($num_items);
121
+		$items_actually_migrated = 0;
122
+		foreach ($rows as $old_row) {
123
+			$this->_migrate_old_row($old_row);
124
+			$items_actually_migrated++;
125
+		}
126
+		if ($this->count_records_migrated() + $items_actually_migrated >= $this->count_records_to_migrate()) {
127
+			$this->set_completed();
128
+		}
129
+		return $items_actually_migrated;
130
+	}
131 131
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -42,14 +42,14 @@  discard block
 block discarded – undo
42 42
             // And we delete this row.
43 43
             $success = $wpdb->update(
44 44
                 $this->_old_table,
45
-                ['EQG_additional' => true],  // data
45
+                ['EQG_additional' => true], // data
46 46
                 [
47 47
                     'EQG_primary' => true,
48 48
                     'EVT_ID' => $event_question_group['EVT_ID'],
49 49
                     'QSG_ID' => $event_question_group['QSG_ID']
50
-                ],  // where
51
-                array( '%d' ),   // data format
52
-                array( '%d', '%d', '%d' )  // where format
50
+                ], // where
51
+                array('%d'), // data format
52
+                array('%d', '%d', '%d')  // where format
53 53
             );
54 54
             if ($success) {
55 55
                 // Ok it's confirmed: the question group WAS for the primary attendee group too. So
@@ -61,7 +61,7 @@  discard block
 block discarded – undo
61 61
                     ],
62 62
                     ['%d']
63 63
                 );
64
-                if (! $successful_delete) {
64
+                if ( ! $successful_delete) {
65 65
                     $this->add_error(
66 66
                         sprintf(
67 67
                             __('Could not delete old event-question group relation row "%1$s" because "%2$s"', 'event_espresso'),
@@ -74,13 +74,13 @@  discard block
 block discarded – undo
74 74
                 // Oh, the question group actually was NOT for the primary attendee. So we just need to update this row
75 75
                 $wpdb->update(
76 76
                     $this->_old_table,
77
-                    ['EQG_additional' => true],  // data
77
+                    ['EQG_additional' => true], // data
78 78
                     [
79 79
                         'EVT_ID' => $event_question_group['EVT_ID'],
80 80
                         'QSG_ID' => $event_question_group['QSG_ID']
81
-                    ],  // where
82
-                    array( '%d' ),   // data format
83
-                    array( '%d', '%d', '%d' )  // where format
81
+                    ], // where
82
+                    array('%d'), // data format
83
+                    array('%d', '%d', '%d')  // where format
84 84
                 );
85 85
             }
86 86
         }
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
     protected function _get_rows($limit)
99 99
     {
100 100
         global $wpdb;
101
-        $query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} " . $wpdb->prepare(
101
+        $query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} ".$wpdb->prepare(
102 102
             "LIMIT %d",
103 103
             $limit
104 104
         );
Please login to merge, or discard this patch.
core/data_migration_scripts/EE_DMS_Core_4_10_0.dms.php 2 patches
Indentation   +186 added lines, -186 removed lines patch added patch discarded remove patch
@@ -15,9 +15,9 @@  discard block
 block discarded – undo
15 15
 $stages = glob(EE_CORE . 'data_migration_scripts/4_10_0_stages/*');
16 16
 $class_to_filepath = [];
17 17
 foreach ($stages as $filepath) {
18
-    $matches = [];
19
-    preg_match('~4_10_0_stages/(.*).dmsstage.php~', $filepath, $matches);
20
-    $class_to_filepath[ $matches[1] ] = $filepath;
18
+	$matches = [];
19
+	preg_match('~4_10_0_stages/(.*).dmsstage.php~', $filepath, $matches);
20
+	$class_to_filepath[ $matches[1] ] = $filepath;
21 21
 }
22 22
 // give addons a chance to autoload their stages too
23 23
 $class_to_filepath = apply_filters('FHEE__EE_DMS_4_10_0__autoloaded_stages', $class_to_filepath);
@@ -35,67 +35,67 @@  discard block
 block discarded – undo
35 35
  */
36 36
 class EE_DMS_Core_4_10_0 extends EE_Data_Migration_Script_Base
37 37
 {
38
-    /**
39
-     *
40
-     * @param TableManager  $table_manager
41
-     * @param TableAnalysis $table_analysis
42
-     */
43
-    public function __construct(
44
-        TableManager $table_manager = null,
45
-        TableAnalysis $table_analysis = null,
46
-        EE_DMS_Core_4_9_0 $dms_4_9
47
-    ) {
48
-        $this->previous_dms = $dms_4_9;
49
-        $this->_pretty_name = esc_html__("Data Update to Event Espresso 4.10.0", "event_espresso");
50
-        $this->_priority = 10;
51
-        $this->_migration_stages = array(
52
-            new EE_DMS_4_10_0_Event_Question_Group(),
53
-        );
54
-        parent::__construct($table_manager, $table_analysis);
55
-    }
38
+	/**
39
+	 *
40
+	 * @param TableManager  $table_manager
41
+	 * @param TableAnalysis $table_analysis
42
+	 */
43
+	public function __construct(
44
+		TableManager $table_manager = null,
45
+		TableAnalysis $table_analysis = null,
46
+		EE_DMS_Core_4_9_0 $dms_4_9
47
+	) {
48
+		$this->previous_dms = $dms_4_9;
49
+		$this->_pretty_name = esc_html__("Data Update to Event Espresso 4.10.0", "event_espresso");
50
+		$this->_priority = 10;
51
+		$this->_migration_stages = array(
52
+			new EE_DMS_4_10_0_Event_Question_Group(),
53
+		);
54
+		parent::__construct($table_manager, $table_analysis);
55
+	}
56 56
 
57 57
 
58 58
 
59
-    /**
60
-     * Whether to migrate or not.
61
-     *
62
-     * @param array $version_array
63
-     * @return bool
64
-     */
65
-    public function can_migrate_from_version($version_array)
66
-    {
67
-        $version_string = $version_array['Core'];
68
-        if (version_compare($version_string, '4.10.0.rc.000', '<') && version_compare($version_string, '4.9.0', '>=')) {
69
-            //          echo "$version_string can be migrated from";
70
-            return true;
71
-        } elseif (! $version_string) {
72
-            //          echo "no version string provided: $version_string";
73
-            // no version string provided... this must be pre 4.3
74
-            return false;// changed mind. dont want people thinking they should migrate yet because they cant
75
-        }
76
-        return false;
77
-    }
59
+	/**
60
+	 * Whether to migrate or not.
61
+	 *
62
+	 * @param array $version_array
63
+	 * @return bool
64
+	 */
65
+	public function can_migrate_from_version($version_array)
66
+	{
67
+		$version_string = $version_array['Core'];
68
+		if (version_compare($version_string, '4.10.0.rc.000', '<') && version_compare($version_string, '4.9.0', '>=')) {
69
+			//          echo "$version_string can be migrated from";
70
+			return true;
71
+		} elseif (! $version_string) {
72
+			//          echo "no version string provided: $version_string";
73
+			// no version string provided... this must be pre 4.3
74
+			return false;// changed mind. dont want people thinking they should migrate yet because they cant
75
+		}
76
+		return false;
77
+	}
78 78
 
79 79
 
80 80
 
81
-    /**
82
-     * @return bool
83
-     */
84
-    public function schema_changes_before_migration()
85
-    {
86
-        require_once(EE_HELPERS . 'EEH_Activation.helper.php');
87
-        $now_in_mysql = current_time('mysql', true);
88
-        $table_name = 'esp_answer';
89
-        $sql = " ANS_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
81
+	/**
82
+	 * @return bool
83
+	 */
84
+	public function schema_changes_before_migration()
85
+	{
86
+		require_once(EE_HELPERS . 'EEH_Activation.helper.php');
87
+		$now_in_mysql = current_time('mysql', true);
88
+		$table_name = 'esp_answer';
89
+		$sql = " ANS_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
90 90
 					REG_ID int(10) unsigned NOT NULL,
91 91
 					QST_ID int(10) unsigned NOT NULL,
92 92
 					ANS_value text NOT NULL,
93 93
 					PRIMARY KEY  (ANS_ID),
94 94
 					KEY REG_ID (REG_ID),
95 95
 					KEY QST_ID (QST_ID)";
96
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
97
-        $table_name = 'esp_attendee_meta';
98
-        $sql = "ATTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
96
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
97
+		$table_name = 'esp_attendee_meta';
98
+		$sql = "ATTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
99 99
 				ATT_ID bigint(20) unsigned NOT NULL,
100 100
 				ATT_fname varchar(45) NOT NULL,
101 101
 				ATT_lname varchar(45) NOT NULL,
@@ -112,9 +112,9 @@  discard block
 block discarded – undo
112 112
 				KEY ATT_email (ATT_email(191)),
113 113
 				KEY ATT_lname (ATT_lname),
114 114
 				KEY ATT_fname (ATT_fname)";
115
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
116
-        $table_name = 'esp_checkin';
117
-        $sql = "CHK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
115
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
116
+		$table_name = 'esp_checkin';
117
+		$sql = "CHK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
118 118
 				REG_ID int(10) unsigned NOT NULL,
119 119
 				DTT_ID int(10) unsigned NOT NULL,
120 120
 				CHK_in tinyint(1) unsigned NOT NULL DEFAULT 1,
@@ -122,9 +122,9 @@  discard block
 block discarded – undo
122 122
 				PRIMARY KEY  (CHK_ID),
123 123
 				KEY REG_ID (REG_ID),
124 124
 				KEY DTT_ID (DTT_ID)";
125
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
126
-        $table_name = 'esp_country';
127
-        $sql = "CNT_ISO varchar(2) NOT NULL,
125
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
126
+		$table_name = 'esp_country';
127
+		$sql = "CNT_ISO varchar(2) NOT NULL,
128 128
 				CNT_ISO3 varchar(3) NOT NULL,
129 129
 				RGN_ID tinyint(3) unsigned DEFAULT NULL,
130 130
 				CNT_name varchar(45) NOT NULL,
@@ -140,29 +140,29 @@  discard block
 block discarded – undo
140 140
 				CNT_is_EU tinyint(1) DEFAULT '0',
141 141
 				CNT_active tinyint(1) DEFAULT '0',
142 142
 				PRIMARY KEY  (CNT_ISO)";
143
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
144
-        $table_name = 'esp_currency';
145
-        $sql = "CUR_code varchar(6) NOT NULL,
143
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
144
+		$table_name = 'esp_currency';
145
+		$sql = "CUR_code varchar(6) NOT NULL,
146 146
 				CUR_single varchar(45) DEFAULT 'dollar',
147 147
 				CUR_plural varchar(45) DEFAULT 'dollars',
148 148
 				CUR_sign varchar(45) DEFAULT '$',
149 149
 				CUR_dec_plc varchar(1) NOT NULL DEFAULT '2',
150 150
 				CUR_active tinyint(1) DEFAULT '0',
151 151
 				PRIMARY KEY  (CUR_code)";
152
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
153
-        // note: although this table is no longer in use,
154
-        // it hasn't been removed because then queries to the model will have errors.
155
-        // but you should expect this table and its corresponding model to be removed in
156
-        // the next few months
157
-        $table_name = 'esp_currency_payment_method';
158
-        $sql = "CPM_ID int(11) NOT NULL AUTO_INCREMENT,
152
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
153
+		// note: although this table is no longer in use,
154
+		// it hasn't been removed because then queries to the model will have errors.
155
+		// but you should expect this table and its corresponding model to be removed in
156
+		// the next few months
157
+		$table_name = 'esp_currency_payment_method';
158
+		$sql = "CPM_ID int(11) NOT NULL AUTO_INCREMENT,
159 159
 				CUR_code varchar(6) NOT NULL,
160 160
 				PMD_ID int(11) NOT NULL,
161 161
 				PRIMARY KEY  (CPM_ID),
162 162
 				KEY PMD_ID (PMD_ID)";
163
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
164
-        $table_name = 'esp_datetime';
165
-        $sql = "DTT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
163
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
164
+		$table_name = 'esp_datetime';
165
+		$sql = "DTT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
166 166
 				EVT_ID bigint(20) unsigned NOT NULL,
167 167
 				DTT_name varchar(255) NOT NULL DEFAULT '',
168 168
 				DTT_description text NOT NULL,
@@ -179,25 +179,25 @@  discard block
 block discarded – undo
179 179
 				KEY DTT_EVT_start (DTT_EVT_start),
180 180
 				KEY EVT_ID (EVT_ID),
181 181
 				KEY DTT_is_primary (DTT_is_primary)";
182
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
183
-        $table_name = "esp_datetime_ticket";
184
-        $sql = "DTK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
182
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
183
+		$table_name = "esp_datetime_ticket";
184
+		$sql = "DTK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
185 185
 				DTT_ID int(10) unsigned NOT NULL,
186 186
 				TKT_ID int(10) unsigned NOT NULL,
187 187
 				PRIMARY KEY  (DTK_ID),
188 188
 				KEY DTT_ID (DTT_ID),
189 189
 				KEY TKT_ID (TKT_ID)";
190
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
191
-        $table_name = 'esp_event_message_template';
192
-        $sql = "EMT_ID bigint(20) unsigned NOT NULL AUTO_INCREMENT,
190
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
191
+		$table_name = 'esp_event_message_template';
192
+		$sql = "EMT_ID bigint(20) unsigned NOT NULL AUTO_INCREMENT,
193 193
 				EVT_ID bigint(20) unsigned NOT NULL DEFAULT 0,
194 194
 				GRP_ID int(10) unsigned NOT NULL DEFAULT 0,
195 195
 				PRIMARY KEY  (EMT_ID),
196 196
 				KEY EVT_ID (EVT_ID),
197 197
 				KEY GRP_ID (GRP_ID)";
198
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
199
-        $table_name = 'esp_event_meta';
200
-        $sql = "EVTM_ID int(10) NOT NULL AUTO_INCREMENT,
198
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
199
+		$table_name = 'esp_event_meta';
200
+		$sql = "EVTM_ID int(10) NOT NULL AUTO_INCREMENT,
201 201
 				EVT_ID bigint(20) unsigned NOT NULL,
202 202
 				EVT_display_desc tinyint(1) unsigned NOT NULL DEFAULT 1,
203 203
 				EVT_display_ticket_selector tinyint(1) unsigned NOT NULL DEFAULT 1,
@@ -212,9 +212,9 @@  discard block
 block discarded – undo
212 212
 				EVT_donations tinyint(1) NULL,
213 213
 				PRIMARY KEY  (EVTM_ID),
214 214
 				KEY EVT_ID (EVT_ID)";
215
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
216
-        $table_name = 'esp_event_question_group';
217
-        $sql = "EQG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
215
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
216
+		$table_name = 'esp_event_question_group';
217
+		$sql = "EQG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
218 218
 				EVT_ID bigint(20) unsigned NOT NULL,
219 219
 				QSG_ID int(10) unsigned NOT NULL,
220 220
 				EQG_primary tinyint(1) unsigned NOT NULL DEFAULT 0,
@@ -222,25 +222,25 @@  discard block
 block discarded – undo
222 222
 				PRIMARY KEY  (EQG_ID),
223 223
 				KEY EVT_ID (EVT_ID),
224 224
 				KEY QSG_ID (QSG_ID)";
225
-        $this->_table_is_changed_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
226
-        $table_name = 'esp_event_venue';
227
-        $sql = "EVV_ID int(11) NOT NULL AUTO_INCREMENT,
225
+		$this->_table_is_changed_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
226
+		$table_name = 'esp_event_venue';
227
+		$sql = "EVV_ID int(11) NOT NULL AUTO_INCREMENT,
228 228
 				EVT_ID bigint(20) unsigned NOT NULL,
229 229
 				VNU_ID bigint(20) unsigned NOT NULL,
230 230
 				EVV_primary tinyint(1) unsigned NOT NULL DEFAULT 0,
231 231
 				PRIMARY KEY  (EVV_ID)";
232
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
233
-        $table_name = 'esp_extra_meta';
234
-        $sql = "EXM_ID int(11) NOT NULL AUTO_INCREMENT,
232
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
233
+		$table_name = 'esp_extra_meta';
234
+		$sql = "EXM_ID int(11) NOT NULL AUTO_INCREMENT,
235 235
 				OBJ_ID int(11) DEFAULT NULL,
236 236
 				EXM_type varchar(45) DEFAULT NULL,
237 237
 				EXM_key varchar(45) DEFAULT NULL,
238 238
 				EXM_value text,
239 239
 				PRIMARY KEY  (EXM_ID),
240 240
 				KEY EXM_type (EXM_type,OBJ_ID,EXM_key)";
241
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
242
-        $table_name = 'esp_extra_join';
243
-        $sql = "EXJ_ID int(11) NOT NULL AUTO_INCREMENT,
241
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
242
+		$table_name = 'esp_extra_join';
243
+		$sql = "EXJ_ID int(11) NOT NULL AUTO_INCREMENT,
244 244
 				EXJ_first_model_id varchar(6) NOT NULL,
245 245
 				EXJ_first_model_name varchar(20) NOT NULL,
246 246
 				EXJ_second_model_id varchar(6) NOT NULL,
@@ -248,9 +248,9 @@  discard block
 block discarded – undo
248 248
 				PRIMARY KEY  (EXJ_ID),
249 249
 				KEY first_model (EXJ_first_model_name,EXJ_first_model_id),
250 250
 				KEY second_model (EXJ_second_model_name,EXJ_second_model_id)";
251
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
252
-        $table_name = 'esp_line_item';
253
-        $sql = "LIN_ID int(11) NOT NULL AUTO_INCREMENT,
251
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
252
+		$table_name = 'esp_line_item';
253
+		$sql = "LIN_ID int(11) NOT NULL AUTO_INCREMENT,
254 254
 				LIN_code varchar(245) NOT NULL DEFAULT '',
255 255
 				TXN_ID int(11) DEFAULT NULL,
256 256
 				LIN_name varchar(245) NOT NULL DEFAULT '',
@@ -271,9 +271,9 @@  discard block
 block discarded – undo
271 271
 				KEY txn_type_timestamp (TXN_ID,LIN_type,LIN_timestamp),
272 272
 				KEY txn_obj_id_obj_type (TXN_ID,OBJ_ID,OBJ_type),
273 273
 				KEY obj_id_obj_type (OBJ_ID,OBJ_type)";
274
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
275
-        $table_name = 'esp_log';
276
-        $sql = "LOG_ID int(11) NOT NULL AUTO_INCREMENT,
274
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
275
+		$table_name = 'esp_log';
276
+		$sql = "LOG_ID int(11) NOT NULL AUTO_INCREMENT,
277 277
 				LOG_time datetime DEFAULT NULL,
278 278
 				OBJ_ID varchar(45) DEFAULT NULL,
279 279
 				OBJ_type varchar(45) DEFAULT NULL,
@@ -284,9 +284,9 @@  discard block
 block discarded – undo
284 284
 				KEY LOG_time (LOG_time),
285 285
 				KEY OBJ (OBJ_type,OBJ_ID),
286 286
 				KEY LOG_type (LOG_type)";
287
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
288
-        $table_name = 'esp_message';
289
-        $sql = "MSG_ID bigint(20) unsigned NOT NULL AUTO_INCREMENT,
287
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
288
+		$table_name = 'esp_message';
289
+		$sql = "MSG_ID bigint(20) unsigned NOT NULL AUTO_INCREMENT,
290 290
 				GRP_ID int(10) unsigned NULL,
291 291
 				MSG_token varchar(255) NULL,
292 292
 				TXN_ID int(10) unsigned NULL,
@@ -318,18 +318,18 @@  discard block
 block discarded – undo
318 318
 				KEY STS_ID (STS_ID),
319 319
 				KEY MSG_created (MSG_created),
320 320
 				KEY MSG_modified (MSG_modified)";
321
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
322
-        $table_name = 'esp_message_template';
323
-        $sql = "MTP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
321
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
322
+		$table_name = 'esp_message_template';
323
+		$sql = "MTP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
324 324
 				GRP_ID int(10) unsigned NOT NULL,
325 325
 				MTP_context varchar(50) NOT NULL,
326 326
 				MTP_template_field varchar(30) NOT NULL,
327 327
 				MTP_content text NOT NULL,
328 328
 				PRIMARY KEY  (MTP_ID),
329 329
 				KEY GRP_ID (GRP_ID)";
330
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
331
-        $table_name = 'esp_message_template_group';
332
-        $sql = "GRP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
330
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
331
+		$table_name = 'esp_message_template_group';
332
+		$sql = "GRP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
333 333
 				MTP_user_id int(10) NOT NULL DEFAULT '1',
334 334
 				MTP_name varchar(245) NOT NULL DEFAULT '',
335 335
 				MTP_description varchar(245) NOT NULL DEFAULT '',
@@ -341,9 +341,9 @@  discard block
 block discarded – undo
341 341
 				MTP_is_active tinyint(1) NOT NULL DEFAULT '1',
342 342
 				PRIMARY KEY  (GRP_ID),
343 343
 				KEY MTP_user_id (MTP_user_id)";
344
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
345
-        $table_name = 'esp_payment';
346
-        $sql = "PAY_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
344
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
345
+		$table_name = 'esp_payment';
346
+		$sql = "PAY_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
347 347
 				TXN_ID int(10) unsigned DEFAULT NULL,
348 348
 				STS_ID varchar(3) DEFAULT NULL,
349 349
 				PAY_timestamp datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
@@ -360,9 +360,9 @@  discard block
 block discarded – undo
360 360
 				PRIMARY KEY  (PAY_ID),
361 361
 				KEY PAY_timestamp (PAY_timestamp),
362 362
 				KEY TXN_ID (TXN_ID)";
363
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
364
-        $table_name = 'esp_payment_method';
365
-        $sql = "PMD_ID int(11) NOT NULL AUTO_INCREMENT,
363
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
364
+		$table_name = 'esp_payment_method';
365
+		$sql = "PMD_ID int(11) NOT NULL AUTO_INCREMENT,
366 366
 				PMD_type varchar(124) DEFAULT NULL,
367 367
 				PMD_name varchar(255) DEFAULT NULL,
368 368
 				PMD_desc text,
@@ -378,24 +378,24 @@  discard block
 block discarded – undo
378 378
 				PRIMARY KEY  (PMD_ID),
379 379
 				UNIQUE KEY PMD_slug_UNIQUE (PMD_slug),
380 380
 				KEY PMD_type (PMD_type)";
381
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
382
-        $table_name = "esp_ticket_price";
383
-        $sql = "TKP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
381
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
382
+		$table_name = "esp_ticket_price";
383
+		$sql = "TKP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
384 384
 				TKT_ID int(10) unsigned NOT NULL,
385 385
 				PRC_ID int(10) unsigned NOT NULL,
386 386
 				PRIMARY KEY  (TKP_ID),
387 387
 				KEY TKT_ID (TKT_ID),
388 388
 				KEY PRC_ID (PRC_ID)";
389
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
390
-        $table_name = "esp_ticket_template";
391
-        $sql = "TTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
389
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
390
+		$table_name = "esp_ticket_template";
391
+		$sql = "TTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
392 392
 				TTM_name varchar(45) NOT NULL,
393 393
 				TTM_description text,
394 394
 				TTM_file varchar(45),
395 395
 				PRIMARY KEY  (TTM_ID)";
396
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
397
-        $table_name = 'esp_question';
398
-        $sql = 'QST_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
396
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
397
+		$table_name = 'esp_question';
398
+		$sql = 'QST_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
399 399
 				QST_display_text text NOT NULL,
400 400
 				QST_admin_label varchar(255) NOT NULL,
401 401
 				QST_system varchar(25) DEFAULT NULL,
@@ -409,18 +409,18 @@  discard block
 block discarded – undo
409 409
 				QST_deleted tinyint(2) unsigned NOT NULL DEFAULT 0,
410 410
 				PRIMARY KEY  (QST_ID),
411 411
 				KEY QST_order (QST_order)';
412
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
413
-        $table_name = 'esp_question_group_question';
414
-        $sql = "QGQ_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
412
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
413
+		$table_name = 'esp_question_group_question';
414
+		$sql = "QGQ_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
415 415
 				QSG_ID int(10) unsigned NOT NULL,
416 416
 				QST_ID int(10) unsigned NOT NULL,
417 417
 				QGQ_order int(10) unsigned NOT NULL DEFAULT 0,
418 418
 				PRIMARY KEY  (QGQ_ID),
419 419
 				KEY QST_ID (QST_ID),
420 420
 				KEY QSG_ID_order (QSG_ID,QGQ_order)";
421
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
422
-        $table_name = 'esp_question_option';
423
-        $sql = "QSO_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
421
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
422
+		$table_name = 'esp_question_option';
423
+		$sql = "QSO_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
424 424
 				QSO_value varchar(255) NOT NULL,
425 425
 				QSO_desc text NOT NULL,
426 426
 				QST_ID int(10) unsigned NOT NULL,
@@ -430,9 +430,9 @@  discard block
 block discarded – undo
430 430
 				PRIMARY KEY  (QSO_ID),
431 431
 				KEY QST_ID (QST_ID),
432 432
 				KEY QSO_order (QSO_order)";
433
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
434
-        $table_name = 'esp_registration';
435
-        $sql = "REG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
433
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
434
+		$table_name = 'esp_registration';
435
+		$sql = "REG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
436 436
 				EVT_ID bigint(20) unsigned NOT NULL,
437 437
 				ATT_ID bigint(20) unsigned NOT NULL,
438 438
 				TXN_ID int(10) unsigned NOT NULL,
@@ -456,18 +456,18 @@  discard block
 block discarded – undo
456 456
 				KEY TKT_ID (TKT_ID),
457 457
 				KEY EVT_ID (EVT_ID),
458 458
 				KEY STS_ID (STS_ID)";
459
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
460
-        $table_name = 'esp_registration_payment';
461
-        $sql = "RPY_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
459
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
460
+		$table_name = 'esp_registration_payment';
461
+		$sql = "RPY_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
462 462
 					  REG_ID int(10) unsigned NOT NULL,
463 463
 					  PAY_ID int(10) unsigned NULL,
464 464
 					  RPY_amount decimal(12,3) NOT NULL DEFAULT '0.00',
465 465
 					  PRIMARY KEY  (RPY_ID),
466 466
 					  KEY REG_ID (REG_ID),
467 467
 					  KEY PAY_ID (PAY_ID)";
468
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
469
-        $table_name = 'esp_state';
470
-        $sql = "STA_ID smallint(5) unsigned NOT NULL AUTO_INCREMENT,
468
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
469
+		$table_name = 'esp_state';
470
+		$sql = "STA_ID smallint(5) unsigned NOT NULL AUTO_INCREMENT,
471 471
 				CNT_ISO varchar(2) NOT NULL,
472 472
 				STA_abbrev varchar(24) NOT NULL,
473 473
 				STA_name varchar(100) NOT NULL,
@@ -475,9 +475,9 @@  discard block
 block discarded – undo
475 475
 				PRIMARY KEY  (STA_ID),
476 476
 				KEY STA_abbrev (STA_abbrev),
477 477
 				KEY CNT_ISO (CNT_ISO)";
478
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
479
-        $table_name = 'esp_status';
480
-        $sql = "STS_ID varchar(3) NOT NULL,
478
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
479
+		$table_name = 'esp_status';
480
+		$sql = "STS_ID varchar(3) NOT NULL,
481 481
 				STS_code varchar(45) NOT NULL,
482 482
 				STS_type varchar(45) NOT NULL,
483 483
 				STS_can_edit tinyint(1) NOT NULL DEFAULT 0,
@@ -485,9 +485,9 @@  discard block
 block discarded – undo
485 485
 				STS_open tinyint(1) NOT NULL DEFAULT 1,
486 486
 				UNIQUE KEY STS_ID_UNIQUE (STS_ID),
487 487
 				KEY STS_type (STS_type)";
488
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
489
-        $table_name = 'esp_transaction';
490
-        $sql = "TXN_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
488
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
489
+		$table_name = 'esp_transaction';
490
+		$sql = "TXN_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
491 491
 				TXN_timestamp datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
492 492
 				TXN_total decimal(12,3) DEFAULT '0.00',
493 493
 				TXN_paid decimal(12,3) NOT NULL DEFAULT '0.00',
@@ -499,9 +499,9 @@  discard block
 block discarded – undo
499 499
 				PRIMARY KEY  (TXN_ID),
500 500
 				KEY TXN_timestamp (TXN_timestamp),
501 501
 				KEY STS_ID (STS_ID)";
502
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
503
-        $table_name = 'esp_venue_meta';
504
-        $sql = "VNUM_ID int(11) NOT NULL AUTO_INCREMENT,
502
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
503
+		$table_name = 'esp_venue_meta';
504
+		$sql = "VNUM_ID int(11) NOT NULL AUTO_INCREMENT,
505 505
 			VNU_ID bigint(20) unsigned NOT NULL DEFAULT 0,
506 506
 			VNU_address varchar(255) DEFAULT NULL,
507 507
 			VNU_address2 varchar(255) DEFAULT NULL,
@@ -520,10 +520,10 @@  discard block
 block discarded – undo
520 520
 			KEY VNU_ID (VNU_ID),
521 521
 			KEY STA_ID (STA_ID),
522 522
 			KEY CNT_ISO (CNT_ISO)";
523
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
524
-        // modified tables
525
-        $table_name = "esp_price";
526
-        $sql = "PRC_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
523
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
524
+		// modified tables
525
+		$table_name = "esp_price";
526
+		$sql = "PRC_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
527 527
 				PRT_ID tinyint(3) unsigned NOT NULL,
528 528
 				PRC_amount decimal(12,3) NOT NULL DEFAULT '0.00',
529 529
 				PRC_name varchar(245) NOT NULL,
@@ -536,9 +536,9 @@  discard block
 block discarded – undo
536 536
 				PRC_parent int(10) unsigned DEFAULT 0,
537 537
 				PRIMARY KEY  (PRC_ID),
538 538
 				KEY PRT_ID (PRT_ID)";
539
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
540
-        $table_name = "esp_price_type";
541
-        $sql = "PRT_ID tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
539
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
540
+		$table_name = "esp_price_type";
541
+		$sql = "PRT_ID tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
542 542
 				PRT_name varchar(45) NOT NULL,
543 543
 				PBT_ID tinyint(3) unsigned NOT NULL DEFAULT '1',
544 544
 				PRT_is_percent tinyint(1) NOT NULL DEFAULT '0',
@@ -547,9 +547,9 @@  discard block
 block discarded – undo
547 547
 				PRT_deleted tinyint(1) NOT NULL DEFAULT '0',
548 548
 				UNIQUE KEY PRT_name_UNIQUE (PRT_name),
549 549
 				PRIMARY KEY  (PRT_ID)";
550
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
551
-        $table_name = "esp_ticket";
552
-        $sql = "TKT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
550
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB ');
551
+		$table_name = "esp_ticket";
552
+		$sql = "TKT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
553 553
 				TTM_ID int(10) unsigned NOT NULL,
554 554
 				TKT_name varchar(245) NOT NULL DEFAULT '',
555 555
 				TKT_description text NOT NULL,
@@ -572,9 +572,9 @@  discard block
 block discarded – undo
572 572
 				TKT_deleted tinyint(1) NOT NULL DEFAULT '0',
573 573
 				PRIMARY KEY  (TKT_ID),
574 574
 				KEY TKT_start_date (TKT_start_date)";
575
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
576
-        $table_name = 'esp_question_group';
577
-        $sql = 'QSG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
575
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
576
+		$table_name = 'esp_question_group';
577
+		$sql = 'QSG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
578 578
 				QSG_name varchar(255) NOT NULL,
579 579
 				QSG_identifier varchar(100) NOT NULL,
580 580
 				QSG_desc text NULL,
@@ -587,38 +587,38 @@  discard block
 block discarded – undo
587 587
 				PRIMARY KEY  (QSG_ID),
588 588
 				UNIQUE KEY QSG_identifier_UNIQUE (QSG_identifier),
589 589
 				KEY QSG_order (QSG_order)';
590
-        $this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
591
-        $this->insert_default_data();
592
-        return true;
593
-    }
590
+		$this->_table_has_not_changed_since_previous($table_name, $sql, 'ENGINE=InnoDB');
591
+		$this->insert_default_data();
592
+		return true;
593
+	}
594 594
 
595
-    /**
596
-     * Inserts default data on new installs
597
-     * @since $VID:$
598
-     * @throws EE_Error
599
-     * @throws InvalidArgumentException
600
-     * @throws ReflectionException
601
-     * @throws InvalidDataTypeException
602
-     * @throws InvalidInterfaceException
603
-     */
604
-    public function insert_default_data()
605
-    {
606
-        $this->previous_dms->insert_default_data();
607
-    }
595
+	/**
596
+	 * Inserts default data on new installs
597
+	 * @since $VID:$
598
+	 * @throws EE_Error
599
+	 * @throws InvalidArgumentException
600
+	 * @throws ReflectionException
601
+	 * @throws InvalidDataTypeException
602
+	 * @throws InvalidInterfaceException
603
+	 */
604
+	public function insert_default_data()
605
+	{
606
+		$this->previous_dms->insert_default_data();
607
+	}
608 608
 
609 609
 
610 610
 
611
-    /**
612
-     * @return boolean
613
-     */
614
-    public function schema_changes_after_migration()
615
-    {
616
-        return true;
617
-    }
611
+	/**
612
+	 * @return boolean
613
+	 */
614
+	public function schema_changes_after_migration()
615
+	{
616
+		return true;
617
+	}
618 618
 
619 619
 
620 620
 
621
-    public function migration_page_hooks()
622
-    {
623
-    }
621
+	public function migration_page_hooks()
622
+	{
623
+	}
624 624
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -12,12 +12,12 @@  discard block
 block discarded – undo
12 12
 // unfortunately, this needs to be done upon INCLUSION of this file,
13 13
 // instead of construction, because it only gets constructed on first page load
14 14
 // (all other times it gets resurrected from a wordpress option)
15
-$stages = glob(EE_CORE . 'data_migration_scripts/4_10_0_stages/*');
15
+$stages = glob(EE_CORE.'data_migration_scripts/4_10_0_stages/*');
16 16
 $class_to_filepath = [];
17 17
 foreach ($stages as $filepath) {
18 18
     $matches = [];
19 19
     preg_match('~4_10_0_stages/(.*).dmsstage.php~', $filepath, $matches);
20
-    $class_to_filepath[ $matches[1] ] = $filepath;
20
+    $class_to_filepath[$matches[1]] = $filepath;
21 21
 }
22 22
 // give addons a chance to autoload their stages too
23 23
 $class_to_filepath = apply_filters('FHEE__EE_DMS_4_10_0__autoloaded_stages', $class_to_filepath);
@@ -68,10 +68,10 @@  discard block
 block discarded – undo
68 68
         if (version_compare($version_string, '4.10.0.rc.000', '<') && version_compare($version_string, '4.9.0', '>=')) {
69 69
             //          echo "$version_string can be migrated from";
70 70
             return true;
71
-        } elseif (! $version_string) {
71
+        } elseif ( ! $version_string) {
72 72
             //          echo "no version string provided: $version_string";
73 73
             // no version string provided... this must be pre 4.3
74
-            return false;// changed mind. dont want people thinking they should migrate yet because they cant
74
+            return false; // changed mind. dont want people thinking they should migrate yet because they cant
75 75
         }
76 76
         return false;
77 77
     }
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
      */
84 84
     public function schema_changes_before_migration()
85 85
     {
86
-        require_once(EE_HELPERS . 'EEH_Activation.helper.php');
86
+        require_once(EE_HELPERS.'EEH_Activation.helper.php');
87 87
         $now_in_mysql = current_time('mysql', true);
88 88
         $table_name = 'esp_answer';
89 89
         $sql = " ANS_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
Please login to merge, or discard this patch.
core/data_migration_scripts/EE_Data_Migration_Script_Base.core.php 1 patch
Indentation   +882 added lines, -882 removed lines patch added patch discarded remove patch
@@ -15,886 +15,886 @@
 block discarded – undo
15 15
 abstract class EE_Data_Migration_Script_Base extends EE_Data_Migration_Class_Base
16 16
 {
17 17
 
18
-    /**
19
-     * Set by client code to indicate this DMS is being ran as part of a proper migration,
20
-     * instead of being used to merely setup (or verify) the database structure.
21
-     * Defaults to TRUE, so client code that's NOT using this DMS as part of a proper migration
22
-     * should call EE_Data_Migration_Script_Base::set_migrating( FALSE )
23
-     *
24
-     * @var boolean
25
-     */
26
-    protected $_migrating = true;
27
-
28
-    /**
29
-     * numerically-indexed array where each value is EE_Data_Migration_Script_Stage object
30
-     *
31
-     * @var EE_Data_Migration_Script_Stage[] $migration_functions
32
-     */
33
-    protected $_migration_stages = array();
34
-
35
-    /**
36
-     * Indicates we've already ran the schema changes that needed to happen BEFORE the data migration
37
-     *
38
-     * @var boolean
39
-     */
40
-    protected $_schema_changes_before_migration_ran = null;
41
-
42
-    /**
43
-     * Indicates we've already ran the schema changes that needed to happen AFTER the data migration
44
-     *
45
-     * @var boolean
46
-     */
47
-    protected $_schema_changes_after_migration_ran = null;
48
-
49
-    /**
50
-     * String which describes what's currently happening in this migration
51
-     *
52
-     * @var string
53
-     */
54
-    protected $_feedback_message;
55
-
56
-    /**
57
-     * Indicates the script's priority. Like wp's add_action and add_filter, lower numbers
58
-     * correspond to earlier execution
59
-     *
60
-     * @var int
61
-     */
62
-    protected $_priority = 5;
63
-
64
-    /**
65
-     * Multi-dimensional array that defines the mapping from OLD table Primary Keys
66
-     * to NEW table Primary Keys.
67
-     * Top-level array keys are OLD table names (minus the "wp_" part),
68
-     * 2nd-level array keys are NEW table names (again, minus the "wp_" part),
69
-     * 3rd-level array keys are the OLD table primary keys
70
-     * and 3rd-level array values are the NEW table primary keys
71
-     *
72
-     * @var array
73
-     */
74
-    protected $_mappings = array();
75
-
76
-    /**
77
-     * @var EE_Data_Migration_Script_Base
78
-     */
79
-    protected $previous_dms;
80
-
81
-
82
-    /**
83
-     * Returns whether or not this data migration script can operate on the given version of the database.
84
-     * Eg, if this migration script can migrate from 3.1.26 or higher (but not anything after 4.0.0), and
85
-     * it's passed a string like '3.1.38B', it should return true.
86
-     * If this DMS is to migrate data from an EE3 addon, you will probably want to use
87
-     * EventEspresso\core\services\database\TableAnalysis::tableExists() to check for old EE3 tables, and
88
-     * EE_Data_Migration_Manager::get_migration_ran() to check that core was already
89
-     * migrated from EE3 to EE4 (ie, this DMS probably relies on some migration data generated
90
-     * during the Core 4.1.0 DMS. If core didn't run that DMS, you probably don't want
91
-     * to run this DMS).
92
-     * If this DMS migrates data from a previous version of this EE4 addon, just
93
-     * comparing $current_database_state_of[ $this->slug() ] will probably suffice.
94
-     * If this DMS should never migrate data, because it's only used to define the initial
95
-     * database state, just return FALSE (and core's activation process will take care
96
-     * of calling its schema_changes_before_migration() and
97
-     * schema_changes_after_migration() for you. )
98
-     *
99
-     * @param array $current_database_state_of keys are EE plugin slugs (eg 'Core', 'Calendar', 'Mailchimp', etc)
100
-     * @return boolean
101
-     */
102
-    abstract public function can_migrate_from_version($current_database_state_of);
103
-
104
-
105
-    /**
106
-     * Performs database schema changes that need to occur BEFORE the data is migrated.
107
-     * Eg, if we were going to change user passwords from plaintext to encoded versions
108
-     * during this migration, this would probably add a new column called something like
109
-     * "encoded_password".
110
-     *
111
-     * @return boolean of success
112
-     */
113
-    abstract public function schema_changes_before_migration();
114
-
115
-
116
-    /**
117
-     * Performs the database schema changes that need to occur AFTER the data has been migrated.
118
-     * Usually this will mean we'll be removing old columns. Eg, if we were changing passwords
119
-     * from plaintext to encoded versions, and we had added a column called "encoded_password",
120
-     * this function would probably remove the old column "password" (which still holds the plaintext password)
121
-     * and possibly rename "encoded_password" to "password"
122
-     *
123
-     * @return boolean of success
124
-     */
125
-    abstract public function schema_changes_after_migration();
126
-
127
-
128
-    /**
129
-     * All children of this must call parent::__construct()
130
-     * at the end of their constructor or suffer the consequences!
131
-     *
132
-     * @param TableManager  $table_manager
133
-     * @param TableAnalysis $table_analysis
134
-     */
135
-    public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
136
-    {
137
-        $this->_migration_stages = (array) apply_filters(
138
-            'FHEE__' . get_class($this) . '__construct__migration_stages',
139
-            $this->_migration_stages
140
-        );
141
-        foreach ($this->_migration_stages as $migration_stage) {
142
-            if ($migration_stage instanceof EE_Data_Migration_Script_Stage) {
143
-                $migration_stage->_construct_finalize($this);
144
-            }
145
-        }
146
-        parent::__construct($table_manager, $table_analysis);
147
-    }
148
-
149
-
150
-    /**
151
-     * Place to add hooks and filters for tweaking the migrations page, in order
152
-     * to customize it
153
-     */
154
-    public function migration_page_hooks()
155
-    {
156
-        // by default none are added because we normally like the default look of the migration page
157
-    }
158
-
159
-
160
-    /**
161
-     * Sets the mapping from old table primary keys to new table primary keys.
162
-     * This mapping is automatically persisted as a property on the migration
163
-     *
164
-     * @param string     $old_table with wpdb prefix (wp_). Eg: wp_events_detail
165
-     * @param int|string $old_pk    old primary key. Eg events_detail.id's value
166
-     * @param string     $new_table with wpdb prefix (wp_). Eg: wp_posts
167
-     * @param int|string $new_pk    eg posts.ID
168
-     * @return void
169
-     */
170
-    public function set_mapping($old_table, $old_pk, $new_table, $new_pk)
171
-    {
172
-        // make sure it has the needed keys
173
-        if (! isset($this->_mappings[ $old_table ]) || ! isset($this->_mappings[ $old_table ][ $new_table ])) {
174
-            $this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
175
-        }
176
-        $this->_mappings[ $old_table ][ $new_table ][ $old_pk ] = $new_pk;
177
-    }
178
-
179
-
180
-    /**
181
-     * Gets the new primary key, if provided with the OLD table and the primary key
182
-     * of an item in the old table, and the new table
183
-     *
184
-     * @param string     $old_table with wpdb prefix (wp_). Eg: wp_events_detail
185
-     * @param int|string $old_pk    old primary key. Eg events_detail.id's value
186
-     * @param string     $new_table with wpdb prefix (wp_). Eg: wp_posts
187
-     * @return mixed the primary key on the new table
188
-     */
189
-    public function get_mapping_new_pk($old_table, $old_pk, $new_table)
190
-    {
191
-        if (! isset($this->_mappings[ $old_table ]) ||
192
-            ! isset($this->_mappings[ $old_table ][ $new_table ])) {
193
-            // try fetching the option
194
-            $this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
195
-        }
196
-        return isset($this->_mappings[ $old_table ][ $new_table ][ $old_pk ])
197
-            ? $this->_mappings[ $old_table ][ $new_table ][ $old_pk ] : null;
198
-    }
199
-
200
-
201
-    /**
202
-     * Gets the old primary key, if provided with the OLD table,
203
-     * and the new table and the primary key of an item in the new table
204
-     *
205
-     * @param string $old_table with wpdb prefix (wp_). Eg: wp_events_detail
206
-     * @param string $new_table with wpdb prefix (wp_). Eg: wp_posts
207
-     * @param mixed  $new_pk
208
-     * @return mixed
209
-     */
210
-    public function get_mapping_old_pk($old_table, $new_table, $new_pk)
211
-    {
212
-        if (! isset($this->_mappings[ $old_table ]) ||
213
-            ! isset($this->_mappings[ $old_table ][ $new_table ])) {
214
-            // try fetching the option
215
-            $this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
216
-        }
217
-        if (isset($this->_mappings[ $old_table ][ $new_table ])) {
218
-            $new_pk_to_old_pk = array_flip($this->_mappings[ $old_table ][ $new_table ]);
219
-            if (isset($new_pk_to_old_pk[ $new_pk ])) {
220
-                return $new_pk_to_old_pk[ $new_pk ];
221
-            }
222
-        }
223
-        return null;
224
-    }
225
-
226
-
227
-    /**
228
-     * Gets the mapping array option specified by the table names
229
-     *
230
-     * @param string $old_table_name
231
-     * @param string $new_table_name
232
-     * @return array
233
-     */
234
-    protected function _get_mapping_option($old_table_name, $new_table_name)
235
-    {
236
-        $option = get_option($this->_get_mapping_option_name($old_table_name, $new_table_name), array());
237
-        return $option;
238
-    }
239
-
240
-
241
-    /**
242
-     * Updates the mapping option specified by the table names with the array provided
243
-     *
244
-     * @param string $old_table_name
245
-     * @param string $new_table_name
246
-     * @param array  $mapping_array
247
-     * @return boolean success of updating option
248
-     */
249
-    protected function _set_mapping_option($old_table_name, $new_table_name, $mapping_array)
250
-    {
251
-        $success = update_option($this->_get_mapping_option_name($old_table_name, $new_table_name), $mapping_array, false);
252
-        return $success;
253
-    }
254
-
255
-
256
-    /**
257
-     * Gets the option name for this script to map from $old_table_name to $new_table_name
258
-     *
259
-     * @param string $old_table_name
260
-     * @param string $new_table_name
261
-     * @return string
262
-     */
263
-    protected function _get_mapping_option_name($old_table_name, $new_table_name)
264
-    {
265
-        global $wpdb;
266
-        $old_table_name_sans_wp = str_replace($wpdb->prefix, "", $old_table_name);
267
-        $new_table_name_sans_wp = str_replace($wpdb->prefix, "", $new_table_name);
268
-        $migrates_to = EE_Data_Migration_Manager::instance()->script_migrates_to_version(get_class($this));
269
-        return substr(
270
-            EE_Data_Migration_Manager::data_migration_script_mapping_option_prefix . $migrates_to ['slug'] . '_' . $migrates_to['version'] . '_' . $old_table_name_sans_wp . '_' . $new_table_name_sans_wp,
271
-            0,
272
-            64
273
-        );
274
-    }
275
-
276
-
277
-    /**
278
-     * Counts all the records that will be migrated during this data migration.
279
-     * For example, if we were changing old user passwords from plaintext to encoded versions,
280
-     * this would be a count of all users who have passwords. If we were going to also split
281
-     * attendee records into transactions, registrations, and attendee records, this would include
282
-     * the count of all attendees currently in existence in the DB (ie, users + attendees).
283
-     * If you can't determine how many records there are to migrate, just provide a guess: this
284
-     * number will only be used in calculating the percent complete. If you estimate there to be
285
-     * 100 records to migrate, and it turns out there's 120, we'll just show the migration as being at
286
-     * 99% until the function "migration_step" returns EE_Data_Migration_Script_Base::status_complete.
287
-     *
288
-     * @return int
289
-     */
290
-    protected function _count_records_to_migrate()
291
-    {
292
-        $count = 0;
293
-        foreach ($this->stages() as $stage) {
294
-            $count += $stage->count_records_to_migrate();
295
-        }
296
-        return $count;
297
-    }
298
-
299
-
300
-    /**
301
-     * Returns the number of records updated so far. Usually this is easiest to do
302
-     * by just setting a transient and updating it after each migration_step
303
-     *
304
-     * @return int
305
-     */
306
-    public function count_records_migrated()
307
-    {
308
-        $count = 0;
309
-        foreach ($this->stages() as $stage) {
310
-            $count += $stage->count_records_migrated();
311
-        }
312
-        $this->_records_migrated = $count;
313
-        return $count;
314
-    }
315
-
316
-
317
-    /**
318
-     * @param int $num_records_to_migrate_limit
319
-     * @return int
320
-     * @throws EE_Error
321
-     * @throws Exception
322
-     */
323
-    public function migration_step($num_records_to_migrate_limit)
324
-    {
325
-        // reset the feedback message
326
-        $this->_feedback_message = '';
327
-        // if we haven't yet done the 1st schema changes, do them now. buffer any output
328
-        $this->_maybe_do_schema_changes(true);
329
-
330
-        $num_records_actually_migrated = 0;
331
-        $records_migrated_per_stage = array();
332
-        // setup the 'stage' variable, which should hold the last run stage of the migration  (or none at all if nothing runs)
333
-        $stage = null;
334
-        // get the next stage that isn't complete
335
-        foreach ($this->stages() as $stage) {
336
-            if ($stage->get_status() == EE_Data_Migration_Manager::status_continue) {
337
-                try {
338
-                    $records_migrated_during_stage = $stage->migration_step(
339
-                        $num_records_to_migrate_limit - $num_records_actually_migrated
340
-                    );
341
-                    $num_records_actually_migrated += $records_migrated_during_stage;
342
-                    $records_migrated_per_stage[ $stage->pretty_name() ] = $records_migrated_during_stage;
343
-                } catch (Exception $e) {
344
-                    // yes if we catch an exception here, we consider that migration stage borked.
345
-                    $stage->set_status(EE_Data_Migration_Manager::status_fatal_error);
346
-                    $this->set_status(EE_Data_Migration_Manager::status_fatal_error);
347
-                    $stage->add_error($e->getMessage() . ". Stack-trace:" . $e->getTraceAsString());
348
-                    throw $e;
349
-                }
350
-                // check that the migration stage didn't mark itself as having a fatal error
351
-                if ($stage->is_broken()) {
352
-                    $this->set_broken();
353
-                    throw new EE_Error($stage->get_last_error());
354
-                }
355
-            }
356
-            // once we've migrated all the number we intended to (possibly from different stages), stop migrating
357
-            // or if we had a fatal error
358
-            // or if the current script stopped early- its not done, but it's done all it thinks we should do on this step
359
-            if ($num_records_actually_migrated >= $num_records_to_migrate_limit
360
-                || $stage->is_broken()
361
-                || $stage->has_more_to_do()
362
-            ) {
363
-                break;
364
-            }
365
-        }
366
-        // check if we're all done this data migration...
367
-        // which is indicated by being done early AND the last stage claims to be done
368
-        if ($stage == null) {
369
-            // this migration script apparently has NO stages... which is super weird, but whatever
370
-            $this->set_completed();
371
-            $this->_maybe_do_schema_changes(false);
372
-        } elseif ($num_records_actually_migrated < $num_records_to_migrate_limit && ! $stage->has_more_to_do()) {
373
-            // apparently we're done, because we couldn't migrate the number we intended to
374
-            $this->set_completed();
375
-            $this->_update_feedback_message(array_reverse($records_migrated_per_stage));
376
-            // do schema changes for after the migration now
377
-            // first double-check we haven't already done this
378
-            $this->_maybe_do_schema_changes(false);
379
-        } else {
380
-            // update feedback message, keeping in mind that we show them with the most recent at the top
381
-            $this->_update_feedback_message(array_reverse($records_migrated_per_stage));
382
-        }
383
-        return $num_records_actually_migrated;
384
-    }
385
-
386
-
387
-    /**
388
-     * Updates the feedback message according to what was done during this migration stage.
389
-     *
390
-     * @param array $records_migrated_per_stage KEYS are pretty names for each stage; values are the count of records
391
-     *                                          migrated from that stage
392
-     * @return void
393
-     */
394
-    private function _update_feedback_message($records_migrated_per_stage)
395
-    {
396
-        $feedback_message_array = array();
397
-        foreach ($records_migrated_per_stage as $migration_stage_name => $num_records_migrated) {
398
-            $feedback_message_array[] = sprintf(
399
-                __("Migrated %d records successfully during %s", "event_espresso"),
400
-                $num_records_migrated,
401
-                $migration_stage_name
402
-            );
403
-        }
404
-        $this->_feedback_message .= implode("<br>", $feedback_message_array);
405
-    }
406
-
407
-
408
-    /**
409
-     * Calls either schema_changes_before_migration() (if $before==true) or schema_changes_after_migration
410
-     * (if $before==false). Buffers their outputs and stores them on the class.
411
-     *
412
-     * @param boolean $before
413
-     * @throws Exception
414
-     * @return void
415
-     */
416
-    private function _maybe_do_schema_changes($before = true)
417
-    {
418
-        // so this property will be either _schema_changes_after_migration_ran or _schema_changes_before_migration_ran
419
-        $property_name = '_schema_changes_' . ($before ? 'before' : 'after') . '_migration_ran';
420
-        if (! $this->{$property_name}) {
421
-            try {
422
-                ob_start();
423
-                if ($before) {
424
-                    $this->schema_changes_before_migration();
425
-                } else {
426
-                    $this->schema_changes_after_migration();
427
-                }
428
-                $output = ob_get_contents();
429
-                ob_end_clean();
430
-            } catch (Exception $e) {
431
-                $this->set_status(EE_Data_Migration_Manager::status_fatal_error);
432
-                throw $e;
433
-            }
434
-            // record that we've done these schema changes
435
-            $this->{$property_name} = true;
436
-            // if there were any warnings etc, record them as non-fatal errors
437
-            if ($output) {
438
-                // there were some warnings
439
-                $this->_errors[] = $output;
440
-            }
441
-        }
442
-    }
443
-
444
-
445
-    /**
446
-     * Wrapper for EEH_Activation::create_table. However, takes into account the request type when
447
-     * deciding what to pass for its 4th arg, $drop_pre_existing_tables. Using this function, instead
448
-     * of _table_should_exist_previously, indicates that this table should be new to the EE version being migrated to
449
-     * or
450
-     * activated currently. If this is a brand new activation or a migration, and we're indicating this table should
451
-     * not
452
-     * previously exist, then we want to set $drop_pre_existing_tables to TRUE (ie, we shouldn't discover that this
453
-     * table exists in the DB in EEH_Activation::create_table- if it DOES exist, something's wrong and the old table
454
-     * should be nuked.
455
-     *
456
-     * Just for a bit of context, the migration script's db_schema_changes_* methods
457
-     * are called basically in 3 cases: on brand new activation of EE4 (ie no previous version of EE existed and the
458
-     * plugin is being activated and we want to add all the brand new tables), upon reactivation of EE4 (it was
459
-     * deactivated and then reactivated, in which case we want to just verify the DB structure is ok) that table should
460
-     * be dropped), and during a migration when we're moving the DB to the state of the migration script
461
-     *
462
-     * @param string $table_name
463
-     * @param string $table_definition_sql
464
-     * @param string $engine_string
465
-     */
466
-    protected function _table_is_new_in_this_version(
467
-        $table_name,
468
-        $table_definition_sql,
469
-        $engine_string = 'ENGINE=InnoDB '
470
-    ) {
471
-        $this->_create_table_and_catch_errors(
472
-            $table_name,
473
-            $table_definition_sql,
474
-            $engine_string,
475
-            $this->_pre_existing_table_should_be_dropped(true)
476
-        );
477
-    }
478
-
479
-    /**
480
-     * Like _table_is_new_in_this_version and _table_should_exist_previously, this function verifies the given table
481
-     * exists. But we understand that this table has CHANGED in this version since the previous version. So it's not
482
-     * completely new, but it's different. So we need to treat it like a new table in terms of verifying it's schema is
483
-     * correct on activations, migrations, upgrades; but if it exists when it shouldn't, we need to be as lenient as
484
-     * _table_should_exist_previously.
485
-     * 8656]{Assumes only this plugin could have added this table (ie, if its a new activation of this plugin, the
486
-     * table shouldn't exist).
487
-     *
488
-     * @param string $table_name
489
-     * @param string $table_definition_sql
490
-     * @param string $engine_string
491
-     */
492
-    protected function _table_is_changed_in_this_version(
493
-        $table_name,
494
-        $table_definition_sql,
495
-        $engine_string = 'ENGINE=MyISAM'
496
-    ) {
497
-        $this->_create_table_and_catch_errors(
498
-            $table_name,
499
-            $table_definition_sql,
500
-            $engine_string,
501
-            $this->_pre_existing_table_should_be_dropped(false)
502
-        );
503
-    }
504
-
505
-
506
-    /**
507
-     * _old_table_exists
508
-     * returns TRUE if the requested table exists in the current database
509
-     *
510
-     * @param string $table_name
511
-     * @return boolean
512
-     */
513
-    protected function _old_table_exists($table_name)
514
-    {
515
-        return $this->_get_table_analysis()->tableExists($table_name);
516
-    }
517
-
518
-
519
-    /**
520
-     * _delete_table_if_empty
521
-     * returns TRUE if the requested table was empty and successfully empty
522
-     *
523
-     * @param string $table_name
524
-     * @return boolean
525
-     */
526
-    protected function _delete_table_if_empty($table_name)
527
-    {
528
-        return EEH_Activation::delete_db_table_if_empty($table_name);
529
-    }
530
-
531
-
532
-    /**
533
-     * It is preferred to use _table_has_not_changed_since_previous or _table_is_changed_in_this_version
534
-     * as these are significantly more efficient or explicit.
535
-     * Please see description of _table_is_new_in_this_version. This function will only set
536
-     * EEH_Activation::create_table's $drop_pre_existing_tables to TRUE if it's a brand
537
-     * new activation. ie, a more accurate name for this method would be "_table_added_previously_by_this_plugin"
538
-     * because the table will be cleared out if this is a new activation (ie, if its a new activation, it actually
539
-     * should exist previously). Otherwise, we'll always set $drop_pre_existing_tables to FALSE because the table
540
-     * should have existed. Note, if the table is being MODIFIED in this version being activated or migrated to, then
541
-     * you want _table_is_changed_in_this_version NOT this one. We don't check this table's structure during migrations
542
-     * because apparently it hasn't changed since the previous one, right?
543
-     *
544
-     * @param string $table_name
545
-     * @param string $table_definition_sql
546
-     * @param string $engine_string
547
-     */
548
-    protected function _table_should_exist_previously(
549
-        $table_name,
550
-        $table_definition_sql,
551
-        $engine_string = 'ENGINE=MyISAM'
552
-    ) {
553
-        $this->_create_table_and_catch_errors(
554
-            $table_name,
555
-            $table_definition_sql,
556
-            $engine_string,
557
-            $this->_pre_existing_table_should_be_dropped(false)
558
-        );
559
-    }
560
-
561
-    /**
562
-     * Exactly the same as _table_should_exist_previously(), except if this migration script is currently doing
563
-     * a migration, we skip checking this table's structure in the database and just assume it's correct.
564
-     * So this is useful only to improve efficiency when doing migrations (not a big deal for single site installs,
565
-     * but important for multisite where migrations can take a very long time otherwise).
566
-     * If the table is known to have changed since previous version, use _table_is_changed_in_this_version().
567
-     * Assumes only this plugin could have added this table (ie, if its a new activation of this plugin, the table
568
-     * shouldn't exist).
569
-     *
570
-     * @param string $table_name
571
-     * @param string $table_definition_sql
572
-     * @param string $engine_string
573
-     */
574
-    protected function _table_has_not_changed_since_previous(
575
-        $table_name,
576
-        $table_definition_sql,
577
-        $engine_string = 'ENGINE=MyISAM'
578
-    ) {
579
-        if ($this->_currently_migrating()) {
580
-            // if we're doing a migration, and this table apparently already exists, then we don't need do anything right?
581
-            return;
582
-        }
583
-        $this->_create_table_and_catch_errors(
584
-            $table_name,
585
-            $table_definition_sql,
586
-            $engine_string,
587
-            $this->_pre_existing_table_should_be_dropped(false)
588
-        );
589
-    }
590
-
591
-    /**
592
-     * Returns whether or not this migration script is being used as part of an actual migration
593
-     *
594
-     * @return boolean
595
-     */
596
-    protected function _currently_migrating()
597
-    {
598
-        // we want to know if we are currently performing a migration. We could just believe what was set on the _migrating property, but let's double-check (ie the script should apply and we should be in MM)
599
-        return $this->_migrating &&
600
-               $this->can_migrate_from_version(
601
-                   EE_Data_Migration_Manager::instance()->ensure_current_database_state_is_set()
602
-               ) &&
603
-               EE_Maintenance_Mode::instance()->real_level() == EE_Maintenance_Mode::level_2_complete_maintenance;
604
-    }
605
-
606
-    /**
607
-     * Determines if a table should be dropped, based on whether it's reported to be new in $table_is_new,
608
-     * and the plugin's request type.
609
-     * Assumes only this plugin could have added the table (ie, if its a new activation of this plugin, the table
610
-     * shouldn't exist no matter what).
611
-     *
612
-     * @param boolean $table_is_new
613
-     * @return boolean
614
-     */
615
-    protected function _pre_existing_table_should_be_dropped($table_is_new)
616
-    {
617
-        if ($table_is_new) {
618
-            if ($this->_get_req_type_for_plugin_corresponding_to_this_dms() == EE_System::req_type_new_activation
619
-                || $this->_currently_migrating()
620
-            ) {
621
-                return true;
622
-            } else {
623
-                return false;
624
-            }
625
-        } else {
626
-            if (in_array(
627
-                $this->_get_req_type_for_plugin_corresponding_to_this_dms(),
628
-                array(EE_System::req_type_new_activation)
629
-            )) {
630
-                return true;
631
-            } else {
632
-                return false;
633
-            }
634
-        }
635
-    }
636
-
637
-    /**
638
-     * Just wraps EEH_Activation::create_table, but catches any errors it may throw and adds them as errors on the DMS
639
-     *
640
-     * @param string  $table_name
641
-     * @param string  $table_definition_sql
642
-     * @param string  $engine_string
643
-     * @param boolean $drop_pre_existing_tables
644
-     */
645
-    private function _create_table_and_catch_errors(
646
-        $table_name,
647
-        $table_definition_sql,
648
-        $engine_string = 'ENGINE=MyISAM',
649
-        $drop_pre_existing_tables = false
650
-    ) {
651
-        try {
652
-            EEH_Activation::create_table($table_name, $table_definition_sql, $engine_string, $drop_pre_existing_tables);
653
-        } catch (EE_Error $e) {
654
-            $message = $e->getMessage() . '<br>Stack Trace:' . $e->getTraceAsString();
655
-            $this->add_error($message);
656
-            $this->_feedback_message .= $message;
657
-        }
658
-    }
659
-
660
-
661
-    /**
662
-     * Gets the request type for the plugin (core or addon) that corresponds to this DMS
663
-     *
664
-     * @return int one of EE_System::_req_type_* constants
665
-     * @throws EE_Error
666
-     */
667
-    private function _get_req_type_for_plugin_corresponding_to_this_dms()
668
-    {
669
-        if ($this->slug() == 'Core') {
670
-            return EE_System::instance()->detect_req_type();
671
-        } else {// it must be for an addon
672
-            $addon_name = $this->slug();
673
-            if (EE_Registry::instance()->get_addon_by_name($addon_name)) {
674
-                return EE_Registry::instance()->get_addon_by_name($addon_name)->detect_req_type();
675
-            } else {
676
-                throw new EE_Error(
677
-                    sprintf(
678
-                        __(
679
-                            "The DMS slug '%s' should correspond to the addon's name, which should also be '%s', but no such addon was registered. These are the registered addons' names: %s",
680
-                            "event_espresso"
681
-                        ),
682
-                        $this->slug(),
683
-                        $addon_name,
684
-                        implode(",", array_keys(EE_Registry::instance()->get_addons_by_name()))
685
-                    )
686
-                );
687
-            }
688
-        }
689
-    }
690
-
691
-
692
-    /**
693
-     * returns an array of strings describing errors by all the script's stages
694
-     *
695
-     * @return array
696
-     */
697
-    public function get_errors()
698
-    {
699
-        $all_errors = $this->_errors;
700
-        if (! is_array($all_errors)) {
701
-            $all_errors = array();
702
-        }
703
-        foreach ($this->stages() as $stage) {
704
-            $all_errors = array_merge($stage->get_errors(), $all_errors);
705
-        }
706
-        return $all_errors;
707
-    }
708
-
709
-
710
-    /**
711
-     * Indicates whether or not this migration script should continue
712
-     *
713
-     * @return boolean
714
-     */
715
-    public function can_continue()
716
-    {
717
-        return in_array(
718
-            $this->get_status(),
719
-            EE_Data_Migration_Manager::instance()->stati_that_indicate_to_continue_single_migration_script
720
-        );
721
-    }
722
-
723
-
724
-    /**
725
-     * Gets all the data migration stages associated with this script. Note:
726
-     * addons can filter this list to add their own stages, and because the list is
727
-     * numerically-indexed, they can insert their stage wherever they like and it will
728
-     * get ordered by the indexes
729
-     *
730
-     * @return EE_Data_Migration_Script_Stage[]
731
-     */
732
-    protected function stages()
733
-    {
734
-        $stages = apply_filters('FHEE__' . get_class($this) . '__stages', $this->_migration_stages);
735
-        ksort($stages);
736
-        return $stages;
737
-    }
738
-
739
-
740
-    /**
741
-     * Gets a string which should describe what's going on currently with this migration, which
742
-     * can be displayed to the user
743
-     *
744
-     * @return string
745
-     */
746
-    public function get_feedback_message()
747
-    {
748
-        return $this->_feedback_message;
749
-    }
750
-
751
-
752
-    /**
753
-     * A lot like "__sleep()" magic method in purpose, this is meant for persisting this class'
754
-     * properties to the DB. However, we don't want to use __sleep() because its quite
755
-     * possible that this class is defined when it goes to sleep, but NOT available when it
756
-     * awakes (eg, this class is part of an addon that is deactivated at some point).
757
-     */
758
-    public function properties_as_array()
759
-    {
760
-        $properties = parent::properties_as_array();
761
-        $properties['_migration_stages'] = array();
762
-        foreach ($this->_migration_stages as $migration_stage_priority => $migration_stage_class) {
763
-            $properties['_migration_stages'][ $migration_stage_priority ] = $migration_stage_class->properties_as_array(
764
-            );
765
-        }
766
-        unset($properties['_mappings']);
767
-        unset($properties['previous_dms']);
768
-
769
-        foreach ($this->_mappings as $old_table_name => $mapping_to_new_table) {
770
-            foreach ($mapping_to_new_table as $new_table_name => $mapping) {
771
-                $this->_set_mapping_option($old_table_name, $new_table_name, $mapping);
772
-            }
773
-        }
774
-        return $properties;
775
-    }
776
-
777
-
778
-    /**
779
-     * Sets all of the properties of this script stage to match what's in the array, which is assumed
780
-     * to have been made from the properties_as_array() function.
781
-     *
782
-     * @param array $array_of_properties like what's produced from properties_as_array() method
783
-     * @return void
784
-     */
785
-    public function instantiate_from_array_of_properties($array_of_properties)
786
-    {
787
-        $stages_properties_arrays = $array_of_properties['_migration_stages'];
788
-        unset($array_of_properties['_migration_stages']);
789
-        unset($array_of_properties['class']);
790
-        foreach ($array_of_properties as $property_name => $property_value) {
791
-            $this->{$property_name} = $property_value;
792
-        }
793
-        // _migration_stages are already instantiated, but have only default data
794
-        foreach ($this->_migration_stages as $stage) {
795
-            $stage_data = $this->_find_migration_stage_data_with_classname(
796
-                get_class($stage),
797
-                $stages_properties_arrays
798
-            );
799
-            // SO, if we found the stage data that was saved, use it. Otherwise, I guess the stage is new? (maybe added by
800
-            // an addon? Unlikely... not sure why it wouldn't exist, but if it doesn't just treat it like it was never started yet)
801
-            if ($stage_data) {
802
-                $stage->instantiate_from_array_of_properties($stage_data);
803
-            }
804
-        }
805
-    }
806
-
807
-
808
-    /**
809
-     * Gets the migration data from the array $migration_stage_data_arrays (which is an array of arrays, each of which
810
-     * is pretty well identical to EE_Data_Migration_Stage objects except all their properties are array indexes)
811
-     * for the given classname
812
-     *
813
-     * @param string $classname
814
-     * @param array  $migration_stage_data_arrays
815
-     * @return null
816
-     */
817
-    private function _find_migration_stage_data_with_classname($classname, $migration_stage_data_arrays)
818
-    {
819
-        foreach ($migration_stage_data_arrays as $migration_stage_data_array) {
820
-            if (isset($migration_stage_data_array['class']) && $migration_stage_data_array['class'] == $classname) {
821
-                return $migration_stage_data_array;
822
-            }
823
-        }
824
-        return null;
825
-    }
826
-
827
-
828
-    /**
829
-     * Returns the version that this script migrates to, based on the script's name.
830
-     * Cannot be overwritten because lots of code needs to know which version a script
831
-     * migrates to knowing only its name.
832
-     *
833
-     * @return array where the first key is the plugin's slug, the 2nd is the version of that plugin
834
-     * that will be updated to. Eg array('Core','4.1.0')
835
-     */
836
-    final public function migrates_to_version()
837
-    {
838
-        return EE_Data_Migration_Manager::instance()->script_migrates_to_version(get_class($this));
839
-    }
840
-
841
-
842
-    /**
843
-     * Gets this addon's slug as it would appear in the current_db_state wp option,
844
-     * and if this migration script is for an addon, it SHOULD match the addon's slug
845
-     * (and also the addon's classname, minus the 'EE_' prefix.). Eg, 'Calendar' for the EE_Calendar addon.
846
-     * Or 'Core' for core (non-addon).
847
-     *
848
-     * @return string
849
-     */
850
-    public function slug()
851
-    {
852
-        $migrates_to_version_info = $this->migrates_to_version();
853
-        // the slug is the first part of the array
854
-        return $migrates_to_version_info['slug'];
855
-    }
856
-
857
-
858
-    /**
859
-     * Returns the script's priority relative to DMSs from other addons. However, when
860
-     * two DMSs from the same addon/core apply, this is ignored (and instead the version that
861
-     * the script migrates to is used to determine which to run first). The default is 5, but all core DMSs
862
-     * normally have priority 10. (So if you want a DMS "A" to run before DMS "B", both of which are from addons,
863
-     * and both of which CAN run at the same time (ie, "B" doesn't depend on "A" to set
864
-     * the database up so it can run), then you can set "A" to priority 3 or something.
865
-     *
866
-     * @return int
867
-     */
868
-    public function priority()
869
-    {
870
-        return $this->_priority;
871
-    }
872
-
873
-
874
-    /**
875
-     * Sets whether or not this DMS is being ran as part of a migration, instead of
876
-     * just being used to setup (or verify) the current database structure matches
877
-     * what the latest DMS indicates it should be
878
-     *
879
-     * @param boolean $migrating
880
-     * @return void
881
-     */
882
-    public function set_migrating($migrating = true)
883
-    {
884
-        $this->_migrating = $migrating;
885
-    }
886
-
887
-    /**
888
-     * Marks that we think this migration class can continue to migrate
889
-     */
890
-    public function reattempt()
891
-    {
892
-        parent::reattempt();
893
-        // also, we want to reattempt any stages that were marked as borked
894
-        foreach ($this->stages() as $stage) {
895
-            if ($stage->is_broken()) {
896
-                $stage->reattempt();
897
-            }
898
-        }
899
-    }
18
+	/**
19
+	 * Set by client code to indicate this DMS is being ran as part of a proper migration,
20
+	 * instead of being used to merely setup (or verify) the database structure.
21
+	 * Defaults to TRUE, so client code that's NOT using this DMS as part of a proper migration
22
+	 * should call EE_Data_Migration_Script_Base::set_migrating( FALSE )
23
+	 *
24
+	 * @var boolean
25
+	 */
26
+	protected $_migrating = true;
27
+
28
+	/**
29
+	 * numerically-indexed array where each value is EE_Data_Migration_Script_Stage object
30
+	 *
31
+	 * @var EE_Data_Migration_Script_Stage[] $migration_functions
32
+	 */
33
+	protected $_migration_stages = array();
34
+
35
+	/**
36
+	 * Indicates we've already ran the schema changes that needed to happen BEFORE the data migration
37
+	 *
38
+	 * @var boolean
39
+	 */
40
+	protected $_schema_changes_before_migration_ran = null;
41
+
42
+	/**
43
+	 * Indicates we've already ran the schema changes that needed to happen AFTER the data migration
44
+	 *
45
+	 * @var boolean
46
+	 */
47
+	protected $_schema_changes_after_migration_ran = null;
48
+
49
+	/**
50
+	 * String which describes what's currently happening in this migration
51
+	 *
52
+	 * @var string
53
+	 */
54
+	protected $_feedback_message;
55
+
56
+	/**
57
+	 * Indicates the script's priority. Like wp's add_action and add_filter, lower numbers
58
+	 * correspond to earlier execution
59
+	 *
60
+	 * @var int
61
+	 */
62
+	protected $_priority = 5;
63
+
64
+	/**
65
+	 * Multi-dimensional array that defines the mapping from OLD table Primary Keys
66
+	 * to NEW table Primary Keys.
67
+	 * Top-level array keys are OLD table names (minus the "wp_" part),
68
+	 * 2nd-level array keys are NEW table names (again, minus the "wp_" part),
69
+	 * 3rd-level array keys are the OLD table primary keys
70
+	 * and 3rd-level array values are the NEW table primary keys
71
+	 *
72
+	 * @var array
73
+	 */
74
+	protected $_mappings = array();
75
+
76
+	/**
77
+	 * @var EE_Data_Migration_Script_Base
78
+	 */
79
+	protected $previous_dms;
80
+
81
+
82
+	/**
83
+	 * Returns whether or not this data migration script can operate on the given version of the database.
84
+	 * Eg, if this migration script can migrate from 3.1.26 or higher (but not anything after 4.0.0), and
85
+	 * it's passed a string like '3.1.38B', it should return true.
86
+	 * If this DMS is to migrate data from an EE3 addon, you will probably want to use
87
+	 * EventEspresso\core\services\database\TableAnalysis::tableExists() to check for old EE3 tables, and
88
+	 * EE_Data_Migration_Manager::get_migration_ran() to check that core was already
89
+	 * migrated from EE3 to EE4 (ie, this DMS probably relies on some migration data generated
90
+	 * during the Core 4.1.0 DMS. If core didn't run that DMS, you probably don't want
91
+	 * to run this DMS).
92
+	 * If this DMS migrates data from a previous version of this EE4 addon, just
93
+	 * comparing $current_database_state_of[ $this->slug() ] will probably suffice.
94
+	 * If this DMS should never migrate data, because it's only used to define the initial
95
+	 * database state, just return FALSE (and core's activation process will take care
96
+	 * of calling its schema_changes_before_migration() and
97
+	 * schema_changes_after_migration() for you. )
98
+	 *
99
+	 * @param array $current_database_state_of keys are EE plugin slugs (eg 'Core', 'Calendar', 'Mailchimp', etc)
100
+	 * @return boolean
101
+	 */
102
+	abstract public function can_migrate_from_version($current_database_state_of);
103
+
104
+
105
+	/**
106
+	 * Performs database schema changes that need to occur BEFORE the data is migrated.
107
+	 * Eg, if we were going to change user passwords from plaintext to encoded versions
108
+	 * during this migration, this would probably add a new column called something like
109
+	 * "encoded_password".
110
+	 *
111
+	 * @return boolean of success
112
+	 */
113
+	abstract public function schema_changes_before_migration();
114
+
115
+
116
+	/**
117
+	 * Performs the database schema changes that need to occur AFTER the data has been migrated.
118
+	 * Usually this will mean we'll be removing old columns. Eg, if we were changing passwords
119
+	 * from plaintext to encoded versions, and we had added a column called "encoded_password",
120
+	 * this function would probably remove the old column "password" (which still holds the plaintext password)
121
+	 * and possibly rename "encoded_password" to "password"
122
+	 *
123
+	 * @return boolean of success
124
+	 */
125
+	abstract public function schema_changes_after_migration();
126
+
127
+
128
+	/**
129
+	 * All children of this must call parent::__construct()
130
+	 * at the end of their constructor or suffer the consequences!
131
+	 *
132
+	 * @param TableManager  $table_manager
133
+	 * @param TableAnalysis $table_analysis
134
+	 */
135
+	public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
136
+	{
137
+		$this->_migration_stages = (array) apply_filters(
138
+			'FHEE__' . get_class($this) . '__construct__migration_stages',
139
+			$this->_migration_stages
140
+		);
141
+		foreach ($this->_migration_stages as $migration_stage) {
142
+			if ($migration_stage instanceof EE_Data_Migration_Script_Stage) {
143
+				$migration_stage->_construct_finalize($this);
144
+			}
145
+		}
146
+		parent::__construct($table_manager, $table_analysis);
147
+	}
148
+
149
+
150
+	/**
151
+	 * Place to add hooks and filters for tweaking the migrations page, in order
152
+	 * to customize it
153
+	 */
154
+	public function migration_page_hooks()
155
+	{
156
+		// by default none are added because we normally like the default look of the migration page
157
+	}
158
+
159
+
160
+	/**
161
+	 * Sets the mapping from old table primary keys to new table primary keys.
162
+	 * This mapping is automatically persisted as a property on the migration
163
+	 *
164
+	 * @param string     $old_table with wpdb prefix (wp_). Eg: wp_events_detail
165
+	 * @param int|string $old_pk    old primary key. Eg events_detail.id's value
166
+	 * @param string     $new_table with wpdb prefix (wp_). Eg: wp_posts
167
+	 * @param int|string $new_pk    eg posts.ID
168
+	 * @return void
169
+	 */
170
+	public function set_mapping($old_table, $old_pk, $new_table, $new_pk)
171
+	{
172
+		// make sure it has the needed keys
173
+		if (! isset($this->_mappings[ $old_table ]) || ! isset($this->_mappings[ $old_table ][ $new_table ])) {
174
+			$this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
175
+		}
176
+		$this->_mappings[ $old_table ][ $new_table ][ $old_pk ] = $new_pk;
177
+	}
178
+
179
+
180
+	/**
181
+	 * Gets the new primary key, if provided with the OLD table and the primary key
182
+	 * of an item in the old table, and the new table
183
+	 *
184
+	 * @param string     $old_table with wpdb prefix (wp_). Eg: wp_events_detail
185
+	 * @param int|string $old_pk    old primary key. Eg events_detail.id's value
186
+	 * @param string     $new_table with wpdb prefix (wp_). Eg: wp_posts
187
+	 * @return mixed the primary key on the new table
188
+	 */
189
+	public function get_mapping_new_pk($old_table, $old_pk, $new_table)
190
+	{
191
+		if (! isset($this->_mappings[ $old_table ]) ||
192
+			! isset($this->_mappings[ $old_table ][ $new_table ])) {
193
+			// try fetching the option
194
+			$this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
195
+		}
196
+		return isset($this->_mappings[ $old_table ][ $new_table ][ $old_pk ])
197
+			? $this->_mappings[ $old_table ][ $new_table ][ $old_pk ] : null;
198
+	}
199
+
200
+
201
+	/**
202
+	 * Gets the old primary key, if provided with the OLD table,
203
+	 * and the new table and the primary key of an item in the new table
204
+	 *
205
+	 * @param string $old_table with wpdb prefix (wp_). Eg: wp_events_detail
206
+	 * @param string $new_table with wpdb prefix (wp_). Eg: wp_posts
207
+	 * @param mixed  $new_pk
208
+	 * @return mixed
209
+	 */
210
+	public function get_mapping_old_pk($old_table, $new_table, $new_pk)
211
+	{
212
+		if (! isset($this->_mappings[ $old_table ]) ||
213
+			! isset($this->_mappings[ $old_table ][ $new_table ])) {
214
+			// try fetching the option
215
+			$this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
216
+		}
217
+		if (isset($this->_mappings[ $old_table ][ $new_table ])) {
218
+			$new_pk_to_old_pk = array_flip($this->_mappings[ $old_table ][ $new_table ]);
219
+			if (isset($new_pk_to_old_pk[ $new_pk ])) {
220
+				return $new_pk_to_old_pk[ $new_pk ];
221
+			}
222
+		}
223
+		return null;
224
+	}
225
+
226
+
227
+	/**
228
+	 * Gets the mapping array option specified by the table names
229
+	 *
230
+	 * @param string $old_table_name
231
+	 * @param string $new_table_name
232
+	 * @return array
233
+	 */
234
+	protected function _get_mapping_option($old_table_name, $new_table_name)
235
+	{
236
+		$option = get_option($this->_get_mapping_option_name($old_table_name, $new_table_name), array());
237
+		return $option;
238
+	}
239
+
240
+
241
+	/**
242
+	 * Updates the mapping option specified by the table names with the array provided
243
+	 *
244
+	 * @param string $old_table_name
245
+	 * @param string $new_table_name
246
+	 * @param array  $mapping_array
247
+	 * @return boolean success of updating option
248
+	 */
249
+	protected function _set_mapping_option($old_table_name, $new_table_name, $mapping_array)
250
+	{
251
+		$success = update_option($this->_get_mapping_option_name($old_table_name, $new_table_name), $mapping_array, false);
252
+		return $success;
253
+	}
254
+
255
+
256
+	/**
257
+	 * Gets the option name for this script to map from $old_table_name to $new_table_name
258
+	 *
259
+	 * @param string $old_table_name
260
+	 * @param string $new_table_name
261
+	 * @return string
262
+	 */
263
+	protected function _get_mapping_option_name($old_table_name, $new_table_name)
264
+	{
265
+		global $wpdb;
266
+		$old_table_name_sans_wp = str_replace($wpdb->prefix, "", $old_table_name);
267
+		$new_table_name_sans_wp = str_replace($wpdb->prefix, "", $new_table_name);
268
+		$migrates_to = EE_Data_Migration_Manager::instance()->script_migrates_to_version(get_class($this));
269
+		return substr(
270
+			EE_Data_Migration_Manager::data_migration_script_mapping_option_prefix . $migrates_to ['slug'] . '_' . $migrates_to['version'] . '_' . $old_table_name_sans_wp . '_' . $new_table_name_sans_wp,
271
+			0,
272
+			64
273
+		);
274
+	}
275
+
276
+
277
+	/**
278
+	 * Counts all the records that will be migrated during this data migration.
279
+	 * For example, if we were changing old user passwords from plaintext to encoded versions,
280
+	 * this would be a count of all users who have passwords. If we were going to also split
281
+	 * attendee records into transactions, registrations, and attendee records, this would include
282
+	 * the count of all attendees currently in existence in the DB (ie, users + attendees).
283
+	 * If you can't determine how many records there are to migrate, just provide a guess: this
284
+	 * number will only be used in calculating the percent complete. If you estimate there to be
285
+	 * 100 records to migrate, and it turns out there's 120, we'll just show the migration as being at
286
+	 * 99% until the function "migration_step" returns EE_Data_Migration_Script_Base::status_complete.
287
+	 *
288
+	 * @return int
289
+	 */
290
+	protected function _count_records_to_migrate()
291
+	{
292
+		$count = 0;
293
+		foreach ($this->stages() as $stage) {
294
+			$count += $stage->count_records_to_migrate();
295
+		}
296
+		return $count;
297
+	}
298
+
299
+
300
+	/**
301
+	 * Returns the number of records updated so far. Usually this is easiest to do
302
+	 * by just setting a transient and updating it after each migration_step
303
+	 *
304
+	 * @return int
305
+	 */
306
+	public function count_records_migrated()
307
+	{
308
+		$count = 0;
309
+		foreach ($this->stages() as $stage) {
310
+			$count += $stage->count_records_migrated();
311
+		}
312
+		$this->_records_migrated = $count;
313
+		return $count;
314
+	}
315
+
316
+
317
+	/**
318
+	 * @param int $num_records_to_migrate_limit
319
+	 * @return int
320
+	 * @throws EE_Error
321
+	 * @throws Exception
322
+	 */
323
+	public function migration_step($num_records_to_migrate_limit)
324
+	{
325
+		// reset the feedback message
326
+		$this->_feedback_message = '';
327
+		// if we haven't yet done the 1st schema changes, do them now. buffer any output
328
+		$this->_maybe_do_schema_changes(true);
329
+
330
+		$num_records_actually_migrated = 0;
331
+		$records_migrated_per_stage = array();
332
+		// setup the 'stage' variable, which should hold the last run stage of the migration  (or none at all if nothing runs)
333
+		$stage = null;
334
+		// get the next stage that isn't complete
335
+		foreach ($this->stages() as $stage) {
336
+			if ($stage->get_status() == EE_Data_Migration_Manager::status_continue) {
337
+				try {
338
+					$records_migrated_during_stage = $stage->migration_step(
339
+						$num_records_to_migrate_limit - $num_records_actually_migrated
340
+					);
341
+					$num_records_actually_migrated += $records_migrated_during_stage;
342
+					$records_migrated_per_stage[ $stage->pretty_name() ] = $records_migrated_during_stage;
343
+				} catch (Exception $e) {
344
+					// yes if we catch an exception here, we consider that migration stage borked.
345
+					$stage->set_status(EE_Data_Migration_Manager::status_fatal_error);
346
+					$this->set_status(EE_Data_Migration_Manager::status_fatal_error);
347
+					$stage->add_error($e->getMessage() . ". Stack-trace:" . $e->getTraceAsString());
348
+					throw $e;
349
+				}
350
+				// check that the migration stage didn't mark itself as having a fatal error
351
+				if ($stage->is_broken()) {
352
+					$this->set_broken();
353
+					throw new EE_Error($stage->get_last_error());
354
+				}
355
+			}
356
+			// once we've migrated all the number we intended to (possibly from different stages), stop migrating
357
+			// or if we had a fatal error
358
+			// or if the current script stopped early- its not done, but it's done all it thinks we should do on this step
359
+			if ($num_records_actually_migrated >= $num_records_to_migrate_limit
360
+				|| $stage->is_broken()
361
+				|| $stage->has_more_to_do()
362
+			) {
363
+				break;
364
+			}
365
+		}
366
+		// check if we're all done this data migration...
367
+		// which is indicated by being done early AND the last stage claims to be done
368
+		if ($stage == null) {
369
+			// this migration script apparently has NO stages... which is super weird, but whatever
370
+			$this->set_completed();
371
+			$this->_maybe_do_schema_changes(false);
372
+		} elseif ($num_records_actually_migrated < $num_records_to_migrate_limit && ! $stage->has_more_to_do()) {
373
+			// apparently we're done, because we couldn't migrate the number we intended to
374
+			$this->set_completed();
375
+			$this->_update_feedback_message(array_reverse($records_migrated_per_stage));
376
+			// do schema changes for after the migration now
377
+			// first double-check we haven't already done this
378
+			$this->_maybe_do_schema_changes(false);
379
+		} else {
380
+			// update feedback message, keeping in mind that we show them with the most recent at the top
381
+			$this->_update_feedback_message(array_reverse($records_migrated_per_stage));
382
+		}
383
+		return $num_records_actually_migrated;
384
+	}
385
+
386
+
387
+	/**
388
+	 * Updates the feedback message according to what was done during this migration stage.
389
+	 *
390
+	 * @param array $records_migrated_per_stage KEYS are pretty names for each stage; values are the count of records
391
+	 *                                          migrated from that stage
392
+	 * @return void
393
+	 */
394
+	private function _update_feedback_message($records_migrated_per_stage)
395
+	{
396
+		$feedback_message_array = array();
397
+		foreach ($records_migrated_per_stage as $migration_stage_name => $num_records_migrated) {
398
+			$feedback_message_array[] = sprintf(
399
+				__("Migrated %d records successfully during %s", "event_espresso"),
400
+				$num_records_migrated,
401
+				$migration_stage_name
402
+			);
403
+		}
404
+		$this->_feedback_message .= implode("<br>", $feedback_message_array);
405
+	}
406
+
407
+
408
+	/**
409
+	 * Calls either schema_changes_before_migration() (if $before==true) or schema_changes_after_migration
410
+	 * (if $before==false). Buffers their outputs and stores them on the class.
411
+	 *
412
+	 * @param boolean $before
413
+	 * @throws Exception
414
+	 * @return void
415
+	 */
416
+	private function _maybe_do_schema_changes($before = true)
417
+	{
418
+		// so this property will be either _schema_changes_after_migration_ran or _schema_changes_before_migration_ran
419
+		$property_name = '_schema_changes_' . ($before ? 'before' : 'after') . '_migration_ran';
420
+		if (! $this->{$property_name}) {
421
+			try {
422
+				ob_start();
423
+				if ($before) {
424
+					$this->schema_changes_before_migration();
425
+				} else {
426
+					$this->schema_changes_after_migration();
427
+				}
428
+				$output = ob_get_contents();
429
+				ob_end_clean();
430
+			} catch (Exception $e) {
431
+				$this->set_status(EE_Data_Migration_Manager::status_fatal_error);
432
+				throw $e;
433
+			}
434
+			// record that we've done these schema changes
435
+			$this->{$property_name} = true;
436
+			// if there were any warnings etc, record them as non-fatal errors
437
+			if ($output) {
438
+				// there were some warnings
439
+				$this->_errors[] = $output;
440
+			}
441
+		}
442
+	}
443
+
444
+
445
+	/**
446
+	 * Wrapper for EEH_Activation::create_table. However, takes into account the request type when
447
+	 * deciding what to pass for its 4th arg, $drop_pre_existing_tables. Using this function, instead
448
+	 * of _table_should_exist_previously, indicates that this table should be new to the EE version being migrated to
449
+	 * or
450
+	 * activated currently. If this is a brand new activation or a migration, and we're indicating this table should
451
+	 * not
452
+	 * previously exist, then we want to set $drop_pre_existing_tables to TRUE (ie, we shouldn't discover that this
453
+	 * table exists in the DB in EEH_Activation::create_table- if it DOES exist, something's wrong and the old table
454
+	 * should be nuked.
455
+	 *
456
+	 * Just for a bit of context, the migration script's db_schema_changes_* methods
457
+	 * are called basically in 3 cases: on brand new activation of EE4 (ie no previous version of EE existed and the
458
+	 * plugin is being activated and we want to add all the brand new tables), upon reactivation of EE4 (it was
459
+	 * deactivated and then reactivated, in which case we want to just verify the DB structure is ok) that table should
460
+	 * be dropped), and during a migration when we're moving the DB to the state of the migration script
461
+	 *
462
+	 * @param string $table_name
463
+	 * @param string $table_definition_sql
464
+	 * @param string $engine_string
465
+	 */
466
+	protected function _table_is_new_in_this_version(
467
+		$table_name,
468
+		$table_definition_sql,
469
+		$engine_string = 'ENGINE=InnoDB '
470
+	) {
471
+		$this->_create_table_and_catch_errors(
472
+			$table_name,
473
+			$table_definition_sql,
474
+			$engine_string,
475
+			$this->_pre_existing_table_should_be_dropped(true)
476
+		);
477
+	}
478
+
479
+	/**
480
+	 * Like _table_is_new_in_this_version and _table_should_exist_previously, this function verifies the given table
481
+	 * exists. But we understand that this table has CHANGED in this version since the previous version. So it's not
482
+	 * completely new, but it's different. So we need to treat it like a new table in terms of verifying it's schema is
483
+	 * correct on activations, migrations, upgrades; but if it exists when it shouldn't, we need to be as lenient as
484
+	 * _table_should_exist_previously.
485
+	 * 8656]{Assumes only this plugin could have added this table (ie, if its a new activation of this plugin, the
486
+	 * table shouldn't exist).
487
+	 *
488
+	 * @param string $table_name
489
+	 * @param string $table_definition_sql
490
+	 * @param string $engine_string
491
+	 */
492
+	protected function _table_is_changed_in_this_version(
493
+		$table_name,
494
+		$table_definition_sql,
495
+		$engine_string = 'ENGINE=MyISAM'
496
+	) {
497
+		$this->_create_table_and_catch_errors(
498
+			$table_name,
499
+			$table_definition_sql,
500
+			$engine_string,
501
+			$this->_pre_existing_table_should_be_dropped(false)
502
+		);
503
+	}
504
+
505
+
506
+	/**
507
+	 * _old_table_exists
508
+	 * returns TRUE if the requested table exists in the current database
509
+	 *
510
+	 * @param string $table_name
511
+	 * @return boolean
512
+	 */
513
+	protected function _old_table_exists($table_name)
514
+	{
515
+		return $this->_get_table_analysis()->tableExists($table_name);
516
+	}
517
+
518
+
519
+	/**
520
+	 * _delete_table_if_empty
521
+	 * returns TRUE if the requested table was empty and successfully empty
522
+	 *
523
+	 * @param string $table_name
524
+	 * @return boolean
525
+	 */
526
+	protected function _delete_table_if_empty($table_name)
527
+	{
528
+		return EEH_Activation::delete_db_table_if_empty($table_name);
529
+	}
530
+
531
+
532
+	/**
533
+	 * It is preferred to use _table_has_not_changed_since_previous or _table_is_changed_in_this_version
534
+	 * as these are significantly more efficient or explicit.
535
+	 * Please see description of _table_is_new_in_this_version. This function will only set
536
+	 * EEH_Activation::create_table's $drop_pre_existing_tables to TRUE if it's a brand
537
+	 * new activation. ie, a more accurate name for this method would be "_table_added_previously_by_this_plugin"
538
+	 * because the table will be cleared out if this is a new activation (ie, if its a new activation, it actually
539
+	 * should exist previously). Otherwise, we'll always set $drop_pre_existing_tables to FALSE because the table
540
+	 * should have existed. Note, if the table is being MODIFIED in this version being activated or migrated to, then
541
+	 * you want _table_is_changed_in_this_version NOT this one. We don't check this table's structure during migrations
542
+	 * because apparently it hasn't changed since the previous one, right?
543
+	 *
544
+	 * @param string $table_name
545
+	 * @param string $table_definition_sql
546
+	 * @param string $engine_string
547
+	 */
548
+	protected function _table_should_exist_previously(
549
+		$table_name,
550
+		$table_definition_sql,
551
+		$engine_string = 'ENGINE=MyISAM'
552
+	) {
553
+		$this->_create_table_and_catch_errors(
554
+			$table_name,
555
+			$table_definition_sql,
556
+			$engine_string,
557
+			$this->_pre_existing_table_should_be_dropped(false)
558
+		);
559
+	}
560
+
561
+	/**
562
+	 * Exactly the same as _table_should_exist_previously(), except if this migration script is currently doing
563
+	 * a migration, we skip checking this table's structure in the database and just assume it's correct.
564
+	 * So this is useful only to improve efficiency when doing migrations (not a big deal for single site installs,
565
+	 * but important for multisite where migrations can take a very long time otherwise).
566
+	 * If the table is known to have changed since previous version, use _table_is_changed_in_this_version().
567
+	 * Assumes only this plugin could have added this table (ie, if its a new activation of this plugin, the table
568
+	 * shouldn't exist).
569
+	 *
570
+	 * @param string $table_name
571
+	 * @param string $table_definition_sql
572
+	 * @param string $engine_string
573
+	 */
574
+	protected function _table_has_not_changed_since_previous(
575
+		$table_name,
576
+		$table_definition_sql,
577
+		$engine_string = 'ENGINE=MyISAM'
578
+	) {
579
+		if ($this->_currently_migrating()) {
580
+			// if we're doing a migration, and this table apparently already exists, then we don't need do anything right?
581
+			return;
582
+		}
583
+		$this->_create_table_and_catch_errors(
584
+			$table_name,
585
+			$table_definition_sql,
586
+			$engine_string,
587
+			$this->_pre_existing_table_should_be_dropped(false)
588
+		);
589
+	}
590
+
591
+	/**
592
+	 * Returns whether or not this migration script is being used as part of an actual migration
593
+	 *
594
+	 * @return boolean
595
+	 */
596
+	protected function _currently_migrating()
597
+	{
598
+		// we want to know if we are currently performing a migration. We could just believe what was set on the _migrating property, but let's double-check (ie the script should apply and we should be in MM)
599
+		return $this->_migrating &&
600
+			   $this->can_migrate_from_version(
601
+				   EE_Data_Migration_Manager::instance()->ensure_current_database_state_is_set()
602
+			   ) &&
603
+			   EE_Maintenance_Mode::instance()->real_level() == EE_Maintenance_Mode::level_2_complete_maintenance;
604
+	}
605
+
606
+	/**
607
+	 * Determines if a table should be dropped, based on whether it's reported to be new in $table_is_new,
608
+	 * and the plugin's request type.
609
+	 * Assumes only this plugin could have added the table (ie, if its a new activation of this plugin, the table
610
+	 * shouldn't exist no matter what).
611
+	 *
612
+	 * @param boolean $table_is_new
613
+	 * @return boolean
614
+	 */
615
+	protected function _pre_existing_table_should_be_dropped($table_is_new)
616
+	{
617
+		if ($table_is_new) {
618
+			if ($this->_get_req_type_for_plugin_corresponding_to_this_dms() == EE_System::req_type_new_activation
619
+				|| $this->_currently_migrating()
620
+			) {
621
+				return true;
622
+			} else {
623
+				return false;
624
+			}
625
+		} else {
626
+			if (in_array(
627
+				$this->_get_req_type_for_plugin_corresponding_to_this_dms(),
628
+				array(EE_System::req_type_new_activation)
629
+			)) {
630
+				return true;
631
+			} else {
632
+				return false;
633
+			}
634
+		}
635
+	}
636
+
637
+	/**
638
+	 * Just wraps EEH_Activation::create_table, but catches any errors it may throw and adds them as errors on the DMS
639
+	 *
640
+	 * @param string  $table_name
641
+	 * @param string  $table_definition_sql
642
+	 * @param string  $engine_string
643
+	 * @param boolean $drop_pre_existing_tables
644
+	 */
645
+	private function _create_table_and_catch_errors(
646
+		$table_name,
647
+		$table_definition_sql,
648
+		$engine_string = 'ENGINE=MyISAM',
649
+		$drop_pre_existing_tables = false
650
+	) {
651
+		try {
652
+			EEH_Activation::create_table($table_name, $table_definition_sql, $engine_string, $drop_pre_existing_tables);
653
+		} catch (EE_Error $e) {
654
+			$message = $e->getMessage() . '<br>Stack Trace:' . $e->getTraceAsString();
655
+			$this->add_error($message);
656
+			$this->_feedback_message .= $message;
657
+		}
658
+	}
659
+
660
+
661
+	/**
662
+	 * Gets the request type for the plugin (core or addon) that corresponds to this DMS
663
+	 *
664
+	 * @return int one of EE_System::_req_type_* constants
665
+	 * @throws EE_Error
666
+	 */
667
+	private function _get_req_type_for_plugin_corresponding_to_this_dms()
668
+	{
669
+		if ($this->slug() == 'Core') {
670
+			return EE_System::instance()->detect_req_type();
671
+		} else {// it must be for an addon
672
+			$addon_name = $this->slug();
673
+			if (EE_Registry::instance()->get_addon_by_name($addon_name)) {
674
+				return EE_Registry::instance()->get_addon_by_name($addon_name)->detect_req_type();
675
+			} else {
676
+				throw new EE_Error(
677
+					sprintf(
678
+						__(
679
+							"The DMS slug '%s' should correspond to the addon's name, which should also be '%s', but no such addon was registered. These are the registered addons' names: %s",
680
+							"event_espresso"
681
+						),
682
+						$this->slug(),
683
+						$addon_name,
684
+						implode(",", array_keys(EE_Registry::instance()->get_addons_by_name()))
685
+					)
686
+				);
687
+			}
688
+		}
689
+	}
690
+
691
+
692
+	/**
693
+	 * returns an array of strings describing errors by all the script's stages
694
+	 *
695
+	 * @return array
696
+	 */
697
+	public function get_errors()
698
+	{
699
+		$all_errors = $this->_errors;
700
+		if (! is_array($all_errors)) {
701
+			$all_errors = array();
702
+		}
703
+		foreach ($this->stages() as $stage) {
704
+			$all_errors = array_merge($stage->get_errors(), $all_errors);
705
+		}
706
+		return $all_errors;
707
+	}
708
+
709
+
710
+	/**
711
+	 * Indicates whether or not this migration script should continue
712
+	 *
713
+	 * @return boolean
714
+	 */
715
+	public function can_continue()
716
+	{
717
+		return in_array(
718
+			$this->get_status(),
719
+			EE_Data_Migration_Manager::instance()->stati_that_indicate_to_continue_single_migration_script
720
+		);
721
+	}
722
+
723
+
724
+	/**
725
+	 * Gets all the data migration stages associated with this script. Note:
726
+	 * addons can filter this list to add their own stages, and because the list is
727
+	 * numerically-indexed, they can insert their stage wherever they like and it will
728
+	 * get ordered by the indexes
729
+	 *
730
+	 * @return EE_Data_Migration_Script_Stage[]
731
+	 */
732
+	protected function stages()
733
+	{
734
+		$stages = apply_filters('FHEE__' . get_class($this) . '__stages', $this->_migration_stages);
735
+		ksort($stages);
736
+		return $stages;
737
+	}
738
+
739
+
740
+	/**
741
+	 * Gets a string which should describe what's going on currently with this migration, which
742
+	 * can be displayed to the user
743
+	 *
744
+	 * @return string
745
+	 */
746
+	public function get_feedback_message()
747
+	{
748
+		return $this->_feedback_message;
749
+	}
750
+
751
+
752
+	/**
753
+	 * A lot like "__sleep()" magic method in purpose, this is meant for persisting this class'
754
+	 * properties to the DB. However, we don't want to use __sleep() because its quite
755
+	 * possible that this class is defined when it goes to sleep, but NOT available when it
756
+	 * awakes (eg, this class is part of an addon that is deactivated at some point).
757
+	 */
758
+	public function properties_as_array()
759
+	{
760
+		$properties = parent::properties_as_array();
761
+		$properties['_migration_stages'] = array();
762
+		foreach ($this->_migration_stages as $migration_stage_priority => $migration_stage_class) {
763
+			$properties['_migration_stages'][ $migration_stage_priority ] = $migration_stage_class->properties_as_array(
764
+			);
765
+		}
766
+		unset($properties['_mappings']);
767
+		unset($properties['previous_dms']);
768
+
769
+		foreach ($this->_mappings as $old_table_name => $mapping_to_new_table) {
770
+			foreach ($mapping_to_new_table as $new_table_name => $mapping) {
771
+				$this->_set_mapping_option($old_table_name, $new_table_name, $mapping);
772
+			}
773
+		}
774
+		return $properties;
775
+	}
776
+
777
+
778
+	/**
779
+	 * Sets all of the properties of this script stage to match what's in the array, which is assumed
780
+	 * to have been made from the properties_as_array() function.
781
+	 *
782
+	 * @param array $array_of_properties like what's produced from properties_as_array() method
783
+	 * @return void
784
+	 */
785
+	public function instantiate_from_array_of_properties($array_of_properties)
786
+	{
787
+		$stages_properties_arrays = $array_of_properties['_migration_stages'];
788
+		unset($array_of_properties['_migration_stages']);
789
+		unset($array_of_properties['class']);
790
+		foreach ($array_of_properties as $property_name => $property_value) {
791
+			$this->{$property_name} = $property_value;
792
+		}
793
+		// _migration_stages are already instantiated, but have only default data
794
+		foreach ($this->_migration_stages as $stage) {
795
+			$stage_data = $this->_find_migration_stage_data_with_classname(
796
+				get_class($stage),
797
+				$stages_properties_arrays
798
+			);
799
+			// SO, if we found the stage data that was saved, use it. Otherwise, I guess the stage is new? (maybe added by
800
+			// an addon? Unlikely... not sure why it wouldn't exist, but if it doesn't just treat it like it was never started yet)
801
+			if ($stage_data) {
802
+				$stage->instantiate_from_array_of_properties($stage_data);
803
+			}
804
+		}
805
+	}
806
+
807
+
808
+	/**
809
+	 * Gets the migration data from the array $migration_stage_data_arrays (which is an array of arrays, each of which
810
+	 * is pretty well identical to EE_Data_Migration_Stage objects except all their properties are array indexes)
811
+	 * for the given classname
812
+	 *
813
+	 * @param string $classname
814
+	 * @param array  $migration_stage_data_arrays
815
+	 * @return null
816
+	 */
817
+	private function _find_migration_stage_data_with_classname($classname, $migration_stage_data_arrays)
818
+	{
819
+		foreach ($migration_stage_data_arrays as $migration_stage_data_array) {
820
+			if (isset($migration_stage_data_array['class']) && $migration_stage_data_array['class'] == $classname) {
821
+				return $migration_stage_data_array;
822
+			}
823
+		}
824
+		return null;
825
+	}
826
+
827
+
828
+	/**
829
+	 * Returns the version that this script migrates to, based on the script's name.
830
+	 * Cannot be overwritten because lots of code needs to know which version a script
831
+	 * migrates to knowing only its name.
832
+	 *
833
+	 * @return array where the first key is the plugin's slug, the 2nd is the version of that plugin
834
+	 * that will be updated to. Eg array('Core','4.1.0')
835
+	 */
836
+	final public function migrates_to_version()
837
+	{
838
+		return EE_Data_Migration_Manager::instance()->script_migrates_to_version(get_class($this));
839
+	}
840
+
841
+
842
+	/**
843
+	 * Gets this addon's slug as it would appear in the current_db_state wp option,
844
+	 * and if this migration script is for an addon, it SHOULD match the addon's slug
845
+	 * (and also the addon's classname, minus the 'EE_' prefix.). Eg, 'Calendar' for the EE_Calendar addon.
846
+	 * Or 'Core' for core (non-addon).
847
+	 *
848
+	 * @return string
849
+	 */
850
+	public function slug()
851
+	{
852
+		$migrates_to_version_info = $this->migrates_to_version();
853
+		// the slug is the first part of the array
854
+		return $migrates_to_version_info['slug'];
855
+	}
856
+
857
+
858
+	/**
859
+	 * Returns the script's priority relative to DMSs from other addons. However, when
860
+	 * two DMSs from the same addon/core apply, this is ignored (and instead the version that
861
+	 * the script migrates to is used to determine which to run first). The default is 5, but all core DMSs
862
+	 * normally have priority 10. (So if you want a DMS "A" to run before DMS "B", both of which are from addons,
863
+	 * and both of which CAN run at the same time (ie, "B" doesn't depend on "A" to set
864
+	 * the database up so it can run), then you can set "A" to priority 3 or something.
865
+	 *
866
+	 * @return int
867
+	 */
868
+	public function priority()
869
+	{
870
+		return $this->_priority;
871
+	}
872
+
873
+
874
+	/**
875
+	 * Sets whether or not this DMS is being ran as part of a migration, instead of
876
+	 * just being used to setup (or verify) the current database structure matches
877
+	 * what the latest DMS indicates it should be
878
+	 *
879
+	 * @param boolean $migrating
880
+	 * @return void
881
+	 */
882
+	public function set_migrating($migrating = true)
883
+	{
884
+		$this->_migrating = $migrating;
885
+	}
886
+
887
+	/**
888
+	 * Marks that we think this migration class can continue to migrate
889
+	 */
890
+	public function reattempt()
891
+	{
892
+		parent::reattempt();
893
+		// also, we want to reattempt any stages that were marked as borked
894
+		foreach ($this->stages() as $stage) {
895
+			if ($stage->is_broken()) {
896
+				$stage->reattempt();
897
+			}
898
+		}
899
+	}
900 900
 }
Please login to merge, or discard this patch.