Completed
Branch FET-10416-autoload-b4-bootstra... (f7c64f)
by
unknown
36:48 queued 23:43
created
core/db_models/EEM_Event.model.php 2 patches
Indentation   +784 added lines, -784 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php use EventEspresso\core\services\orm\ModelFieldFactory;
2 2
 
3 3
 if (! defined('EVENT_ESPRESSO_VERSION')) {
4
-    exit('No direct script access allowed');
4
+	exit('No direct script access allowed');
5 5
 }
6 6
 require_once(EE_MODELS . 'EEM_CPT_Base.model.php');
7 7
 
@@ -18,789 +18,789 @@  discard block
 block discarded – undo
18 18
 class EEM_Event extends EEM_CPT_Base
19 19
 {
20 20
 
21
-    /**
22
-     * constant used by status(), indicating that no more tickets can be purchased for any of the datetimes for the
23
-     * event
24
-     */
25
-    const sold_out = 'sold_out';
26
-
27
-    /**
28
-     * constant used by status(), indicating that upcoming event dates have been postponed (may be pushed to a later
29
-     * date)
30
-     */
31
-    const postponed = 'postponed';
32
-
33
-    /**
34
-     * constant used by status(), indicating that the event will no longer occur
35
-     */
36
-    const cancelled = 'cancelled';
37
-
38
-
39
-    /**
40
-     * @var string
41
-     */
42
-    protected static $_default_reg_status;
43
-
44
-
45
-    /**
46
-     * This is the default for the additional limit field.
47
-     * @var int
48
-     */
49
-    protected static $_default_additional_limit = 10;
50
-
51
-
52
-    /**
53
-     * private instance of the Event object
54
-     *
55
-     * @var EEM_Event
56
-     */
57
-    protected static $_instance;
58
-
59
-
60
-
61
-
62
-    /**
63
-     * Adds a relationship to Term_Taxonomy for each CPT_Base
64
-     *
65
-     * @param string $timezone
66
-     * @throws \EE_Error
67
-     */
68
-    protected function __construct($timezone = null)
69
-    {
70
-        EE_Registry::instance()->load_model('Registration');
71
-        $this->singular_item = esc_html__('Event', 'event_espresso');
72
-        $this->plural_item = esc_html__('Events', 'event_espresso');
73
-        // to remove Cancelled events from the frontend, copy the following filter to your functions.php file
74
-        // add_filter( 'AFEE__EEM_Event__construct___custom_stati__cancelled__Public', '__return_false' );
75
-        // to remove Postponed events from the frontend, copy the following filter to your functions.php file
76
-        // add_filter( 'AFEE__EEM_Event__construct___custom_stati__postponed__Public', '__return_false' );
77
-        // to remove Sold Out events from the frontend, copy the following filter to your functions.php file
78
-        //	add_filter( 'AFEE__EEM_Event__construct___custom_stati__sold_out__Public', '__return_false' );
79
-        $this->_custom_stati = apply_filters(
80
-            'AFEE__EEM_Event__construct___custom_stati',
81
-            array(
82
-                EEM_Event::cancelled => array(
83
-                    'label'  => esc_html__('Cancelled', 'event_espresso'),
84
-                    'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__cancelled__Public', true),
85
-                ),
86
-                EEM_Event::postponed => array(
87
-                    'label'  => esc_html__('Postponed', 'event_espresso'),
88
-                    'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__postponed__Public', true),
89
-                ),
90
-                EEM_Event::sold_out  => array(
91
-                    'label'  => esc_html__('Sold Out', 'event_espresso'),
92
-                    'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__sold_out__Public', true),
93
-                ),
94
-            )
95
-        );
96
-        self::$_default_reg_status = empty(self::$_default_reg_status) ? EEM_Registration::status_id_pending_payment
97
-            : self::$_default_reg_status;
98
-        $this->_tables = array(
99
-            'Event_CPT'  => new EE_Primary_Table('posts', 'ID'),
100
-            'Event_Meta' => new EE_Secondary_Table('esp_event_meta', 'EVTM_ID', 'EVT_ID'),
101
-        );
102
-        $this->_fields = array(
103
-            'Event_CPT'  => array(
104
-                'EVT_ID'         => new EE_Primary_Key_Int_Field('ID',
105
-                    esc_html__('Post ID for Event', 'event_espresso')),
106
-                'EVT_name'       => new EE_Plain_Text_Field('post_title', esc_html__('Event Name', 'event_espresso'),
107
-                    false,
108
-                    ''),
109
-                'EVT_desc'       => new EE_Post_Content_Field('post_content',
110
-                    esc_html__('Event Description', 'event_espresso'),
111
-                    false, ''),
112
-                'EVT_slug'       => new EE_Slug_Field('post_name', esc_html__('Event Slug', 'event_espresso'), false,
113
-                    ''),
114
-                'EVT_created'    => new EE_Datetime_Field('post_date',
115
-                    esc_html__('Date/Time Event Created', 'event_espresso'),
116
-                    false, EE_Datetime_Field::now),
117
-                'EVT_short_desc' => new EE_Simple_HTML_Field('post_excerpt',
118
-                    esc_html__('Event Short Description', 'event_espresso'), false, ''),
119
-                'EVT_modified'   => new EE_Datetime_Field('post_modified',
120
-                    esc_html__('Date/Time Event Modified', 'event_espresso'), false, EE_Datetime_Field::now),
121
-                'EVT_wp_user'    => new EE_WP_User_Field('post_author',
122
-                    esc_html__('Event Creator ID', 'event_espresso'),
123
-                    false),
124
-                'parent'         => new EE_Integer_Field('post_parent', esc_html__('Event Parent ID', 'event_espresso'),
125
-                    false,
126
-                    0),
127
-                'EVT_order'      => new EE_Integer_Field('menu_order', esc_html__('Event Menu Order', 'event_espresso'),
128
-                    false,
129
-                    1),
130
-                'post_type'      => new EE_WP_Post_Type_Field('espresso_events'),
131
-                // EE_Plain_Text_Field( 'post_type', esc_html__( 'Event Post Type', 'event_espresso' ), FALSE, 'espresso_events' ),
132
-                'status'         => new EE_WP_Post_Status_Field('post_status',
133
-                    esc_html__('Event Status', 'event_espresso'),
134
-                    false, 'draft', $this->_custom_stati),
135
-            ),
136
-            'Event_Meta' => array(
137
-                'EVTM_ID'                         => new EE_DB_Only_Float_Field('EVTM_ID',
138
-                    esc_html__('Event Meta Row ID', 'event_espresso'), false),
139
-                'EVT_ID_fk'                       => new EE_DB_Only_Int_Field('EVT_ID',
140
-                    esc_html__('Foreign key to Event ID from Event Meta table', 'event_espresso'), false),
141
-                'EVT_display_desc'                => new EE_Boolean_Field('EVT_display_desc',
142
-                    esc_html__('Display Description Flag', 'event_espresso'), false, 1),
143
-                'EVT_display_ticket_selector'     => new EE_Boolean_Field('EVT_display_ticket_selector',
144
-                    esc_html__('Display Ticket Selector Flag', 'event_espresso'), false, 1),
145
-                'EVT_visible_on'                  => new EE_Datetime_Field('EVT_visible_on',
146
-                    esc_html__('Event Visible Date', 'event_espresso'), true, EE_Datetime_Field::now),
147
-                'EVT_additional_limit'            => new EE_Integer_Field(
148
-                    'EVT_additional_limit',
149
-                    esc_html__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
150
-                    true,
151
-                    self::$_default_additional_limit
152
-                ),
153
-                'EVT_default_registration_status' => new EE_Enum_Text_Field(
154
-                    'EVT_default_registration_status',
155
-                    esc_html__('Default Registration Status on this Event', 'event_espresso'), false,
156
-                    EEM_Event::$_default_reg_status, EEM_Registration::reg_status_array()
157
-                ),
158
-                'EVT_member_only'                 => new EE_Boolean_Field('EVT_member_only',
159
-                    esc_html__('Member-Only Event Flag', 'event_espresso'), false, false),
160
-                'EVT_phone'                       => new EE_Plain_Text_Field('EVT_phone',
161
-                    esc_html__('Event Phone Number', 'event_espresso'), false,''),
162
-                'EVT_allow_overflow'              => new EE_Boolean_Field('EVT_allow_overflow',
163
-                    esc_html__('Allow Overflow on Event', 'event_espresso'), false, false),
164
-                'EVT_timezone_string'             => new EE_Plain_Text_Field('EVT_timezone_string',
165
-                    esc_html__('Timezone (name) for Event times', 'event_espresso'), false,''),
166
-                'EVT_external_URL'                => new EE_Plain_Text_Field('EVT_external_URL',
167
-                    esc_html__('URL of Event Page if hosted elsewhere', 'event_espresso'), true),
168
-                'EVT_donations'                   => new EE_Boolean_Field('EVT_donations',
169
-                    esc_html__('Accept Donations?', 'event_espresso'), false, false),
170
-            ),
171
-        );
172
-        $this->_model_relations = array(
173
-            'Registration'           => new EE_Has_Many_Relation(),
174
-            'Datetime'               => new EE_Has_Many_Relation(),
175
-            'Question_Group'         => new EE_HABTM_Relation('Event_Question_Group'),
176
-            'Venue'                  => new EE_HABTM_Relation('Event_Venue'),
177
-            'Term_Relationship'      => new EE_Has_Many_Relation(),
178
-            'Term_Taxonomy'          => new EE_HABTM_Relation('Term_Relationship'),
179
-            'Message_Template_Group' => new EE_HABTM_Relation('Event_Message_Template'),
180
-            'Attendee'               => new EE_HABTM_Relation('Registration'),
181
-            'WP_User'                => new EE_Belongs_To_Relation(),
182
-        );
183
-        //this model is generally available for reading
184
-        $this->_cap_restriction_generators[EEM_Base::caps_read] = new EE_Restriction_Generator_Public();
185
-        parent::__construct($timezone);
186
-    }
187
-
188
-
189
-
190
-    /**
191
-     * @param string $default_reg_status
192
-     */
193
-    public static function set_default_reg_status($default_reg_status)
194
-    {
195
-        self::$_default_reg_status = $default_reg_status;
196
-        // if EEM_Event has already been instantiated,
197
-        // then we need to reset the `EVT_default_reg_status` field to use the new default.
198
-        if (self::$_instance instanceof EEM_Event) {
199
-            $default_reg_status = new EE_Enum_Text_Field(
200
-                'EVT_default_registration_status',
201
-                esc_html__('Default Registration Status on this Event', 'event_espresso'),
202
-                false,
203
-                $default_reg_status,
204
-                EEM_Registration::reg_status_array()
205
-            );
206
-            $default_reg_status->_construct_finalize(
207
-                'Event_Meta',
208
-                'EVT_default_registration_status',
209
-                'EEM_Event'
210
-            );
211
-            self::$_instance->_fields['Event_Meta']['EVT_default_registration_status'] = $default_reg_status;
212
-        }
213
-    }
214
-
215
-
216
-    /**
217
-     * Used to override the default for the additional limit field.
218
-     * @param $additional_limit
219
-     */
220
-    public static function set_default_additional_limit($additional_limit)
221
-    {
222
-        self::$_default_additional_limit = (int) $additional_limit;
223
-        if (self::$_instance instanceof EEM_Event) {
224
-            self::$_instance->_fields['Event_Meta']['EVT_additional_limit'] = new EE_Integer_Field(
225
-                'EVT_additional_limit',
226
-                __('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
227
-                true,
228
-                self::$_default_additional_limit
229
-            );
230
-            self::$_instance->_fields['Event_Meta']['EVT_additional_limit']->_construct_finalize(
231
-                'Event_Meta',
232
-                'EVT_additional_limit',
233
-                'EEM_Event'
234
-            );
235
-        }
236
-    }
237
-
238
-
239
-    /**
240
-     * Return what is currently set as the default additional limit for the event.
241
-     * @return int
242
-     */
243
-    public static function get_default_additional_limit()
244
-    {
245
-        return apply_filters('FHEE__EEM_Event__get_default_additional_limit', self::$_default_additional_limit);
246
-    }
247
-
248
-
249
-    /**
250
-     * get_question_groups
251
-     *
252
-     * @return array
253
-     * @throws \EE_Error
254
-     */
255
-    public function get_all_question_groups()
256
-    {
257
-        return EE_Registry::instance()->load_model('Question_Group')->get_all(
258
-            array(
259
-                array('QSG_deleted' => false),
260
-                'order_by' => array('QSG_order' => 'ASC'),
261
-            )
262
-        );
263
-    }
264
-
265
-
266
-
267
-    /**
268
-     * get_question_groups
269
-     *
270
-     * @param int $EVT_ID
271
-     * @return array|bool
272
-     * @throws \EE_Error
273
-     */
274
-    public function get_all_event_question_groups($EVT_ID = 0)
275
-    {
276
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
277
-            EE_Error::add_error(
278
-                esc_html__(
279
-                    'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
280
-                    'event_espresso'
281
-                ),
282
-                __FILE__, __FUNCTION__, __LINE__
283
-            );
284
-            return false;
285
-        }
286
-        return EE_Registry::instance()->load_model('Event_Question_Group')->get_all(
287
-            array(
288
-                array('EVT_ID' => $EVT_ID),
289
-            )
290
-        );
291
-    }
292
-
293
-
294
-
295
-    /**
296
-     * get_question_groups
297
-     *
298
-     * @param int     $EVT_ID
299
-     * @param boolean $for_primary_attendee
300
-     * @return array|bool
301
-     * @throws \EE_Error
302
-     */
303
-    public function get_event_question_groups($EVT_ID = 0, $for_primary_attendee = true)
304
-    {
305
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
306
-            EE_Error::add_error(
307
-                esc_html__(
308
-                    'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
309
-                    'event_espresso'
310
-                ),
311
-                __FILE__, __FUNCTION__, __LINE__
312
-            );
313
-            return false;
314
-        }
315
-        return EE_Registry::instance()->load_model('Event_Question_Group')->get_all(
316
-            array(
317
-                array(
318
-                    'EVT_ID'      => $EVT_ID,
319
-                    'EQG_primary' => $for_primary_attendee,
320
-                ),
321
-            )
322
-        );
323
-    }
324
-
325
-
326
-
327
-    /**
328
-     * get_question_groups
329
-     *
330
-     * @param int             $EVT_ID
331
-     * @param EE_Registration $registration
332
-     * @return array|bool
333
-     * @throws \EE_Error
334
-     */
335
-    public function get_question_groups_for_event($EVT_ID = 0, EE_Registration $registration)
336
-    {
337
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
338
-            EE_Error::add_error(
339
-                esc_html__(
340
-                    'An error occurred. No Question Groups could be retrieved because an Event ID was not received.',
341
-                    'event_espresso'
342
-                ),
343
-                __FILE__, __FUNCTION__, __LINE__
344
-            );
345
-            return false;
346
-        }
347
-        $where_params = array(
348
-            'Event_Question_Group.EVT_ID'      => $EVT_ID,
349
-            'Event_Question_Group.EQG_primary' => $registration->count() === 1 ? true : false,
350
-            'QSG_deleted'                      => false,
351
-        );
352
-        return EE_Registry::instance()->load_model('Question_Group')->get_all(
353
-            array(
354
-                $where_params,
355
-                'order_by' => array('QSG_order' => 'ASC'),
356
-            )
357
-        );
358
-    }
359
-
360
-
361
-
362
-    /**
363
-     * get_question_target_db_column
364
-     *
365
-     * @param string $QSG_IDs csv list of $QSG IDs
366
-     * @return array|bool
367
-     * @throws \EE_Error
368
-     */
369
-    public function get_questions_in_groups($QSG_IDs = '')
370
-    {
371
-        if (empty($QSG_IDs)) {
372
-            EE_Error::add_error(
373
-                esc_html__('An error occurred. No Question Group IDs were received.', 'event_espresso'),
374
-                __FILE__, __FUNCTION__, __LINE__
375
-            );
376
-            return false;
377
-        }
378
-        return EE_Registry::instance()->load_model('Question')->get_all(
379
-            array(
380
-                array(
381
-                    'Question_Group.QSG_ID' => array('IN', $QSG_IDs),
382
-                    'QST_deleted'           => false,
383
-                    'QST_admin_only'        => is_admin(),
384
-                ),
385
-                'order_by' => 'QST_order',
386
-            )
387
-        );
388
-    }
389
-
390
-
391
-
392
-    /**
393
-     * get_options_for_question
394
-     *
395
-     * @param string $QST_IDs csv list of $QST IDs
396
-     * @return array|bool
397
-     * @throws \EE_Error
398
-     */
399
-    public function get_options_for_question($QST_IDs)
400
-    {
401
-        if (empty($QST_IDs)) {
402
-            EE_Error::add_error(
403
-                esc_html__('An error occurred. No Question IDs were received.', 'event_espresso'),
404
-                __FILE__, __FUNCTION__, __LINE__
405
-            );
406
-            return false;
407
-        }
408
-        return EE_Registry::instance()->load_model('Question_Option')->get_all(
409
-            array(
410
-                array(
411
-                    'Question.QST_ID' => array('IN', $QST_IDs),
412
-                    'QSO_deleted'     => false,
413
-                ),
414
-                'order_by' => 'QSO_ID',
415
-            )
416
-        );
417
-    }
418
-
419
-
420
-
421
-
422
-
423
-
424
-
425
-    /**
426
-     * Gets all events that are published
427
-     * and have event start time earlier than now and an event end time later than now
428
-     *
429
-     * @param  array $query_params An array of query params to further filter on
430
-     *                             (note that status and DTT_EVT_start and DTT_EVT_end will be overridden)
431
-     * @param bool   $count        whether to return the count or not (default FALSE)
432
-     * @return EE_Event[]|int
433
-     * @throws \EE_Error
434
-     */
435
-    public function get_active_events($query_params, $count = false)
436
-    {
437
-        if (array_key_exists(0, $query_params)) {
438
-            $where_params = $query_params[0];
439
-            unset($query_params[0]);
440
-        } else {
441
-            $where_params = array();
442
-        }
443
-        // if we have count make sure we don't include group by
444
-        if ($count && isset($query_params['group_by'])) {
445
-            unset($query_params['group_by']);
446
-        }
447
-        // let's add specific query_params for active_events
448
-        // keep in mind this will override any sent status in the query AND any date queries.
449
-        $where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
450
-        //if already have where params for DTT_EVT_start or DTT_EVT_end then append these conditions
451
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
452
-            $where_params['Datetime.DTT_EVT_start******'] = array(
453
-                '<',
454
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
455
-            );
456
-        } else {
457
-            $where_params['Datetime.DTT_EVT_start'] = array(
458
-                '<',
459
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
460
-            );
461
-        }
462
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
463
-            $where_params['Datetime.DTT_EVT_end*****'] = array(
464
-                '>',
465
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
466
-            );
467
-        } else {
468
-            $where_params['Datetime.DTT_EVT_end'] = array(
469
-                '>',
470
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
471
-            );
472
-        }
473
-        $query_params[0] = $where_params;
474
-        // don't use $query_params with count()
475
-        // because we don't want to include additional query clauses like "GROUP BY"
476
-        return $count
477
-            ? $this->count(array($where_params), 'EVT_ID', true)
478
-            : $this->get_all($query_params);
479
-    }
480
-
481
-
482
-
483
-    /**
484
-     * get all events that are published and have an event start time later than now
485
-     *
486
-     * @param  array $query_params An array of query params to further filter on
487
-     *                             (Note that status and DTT_EVT_start will be overridden)
488
-     * @param bool   $count        whether to return the count or not (default FALSE)
489
-     * @return EE_Event[]|int
490
-     * @throws \EE_Error
491
-     */
492
-    public function get_upcoming_events($query_params, $count = false)
493
-    {
494
-        if (array_key_exists(0, $query_params)) {
495
-            $where_params = $query_params[0];
496
-            unset($query_params[0]);
497
-        } else {
498
-            $where_params = array();
499
-        }
500
-        // if we have count make sure we don't include group by
501
-        if ($count && isset($query_params['group_by'])) {
502
-            unset($query_params['group_by']);
503
-        }
504
-        // let's add specific query_params for active_events
505
-        // keep in mind this will override any sent status in the query AND any date queries.
506
-        $where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
507
-        // if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
508
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
509
-            $where_params['Datetime.DTT_EVT_start*****'] = array(
510
-                '>',
511
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
512
-            );
513
-        } else {
514
-            $where_params['Datetime.DTT_EVT_start'] = array(
515
-                '>',
516
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
517
-            );
518
-        }
519
-        $query_params[0] = $where_params;
520
-        // don't use $query_params with count()
521
-        // because we don't want to include additional query clauses like "GROUP BY"
522
-        return $count
523
-            ? $this->count(array($where_params), 'EVT_ID', true)
524
-            : $this->get_all($query_params);
525
-    }
526
-
527
-
528
-
529
-    /**
530
-     * Gets all events that are published
531
-     * and have an event end time later than now
532
-     *
533
-     * @param  array $query_params An array of query params to further filter on
534
-     *                             (note that status and DTT_EVT_end will be overridden)
535
-     * @param bool   $count        whether to return the count or not (default FALSE)
536
-     * @return EE_Event[]|int
537
-     * @throws \EE_Error
538
-     */
539
-    public function get_active_and_upcoming_events($query_params, $count = false)
540
-    {
541
-        if (array_key_exists(0, $query_params)) {
542
-            $where_params = $query_params[0];
543
-            unset($query_params[0]);
544
-        } else {
545
-            $where_params = array();
546
-        }
547
-        // if we have count make sure we don't include group by
548
-        if ($count && isset($query_params['group_by'])) {
549
-            unset($query_params['group_by']);
550
-        }
551
-        // let's add specific query_params for active_events
552
-        // keep in mind this will override any sent status in the query AND any date queries.
553
-        $where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
554
-        // add where params for DTT_EVT_end
555
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
556
-            $where_params['Datetime.DTT_EVT_end*****'] = array(
557
-                '>',
558
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
559
-            );
560
-        } else {
561
-            $where_params['Datetime.DTT_EVT_end'] = array(
562
-                '>',
563
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
564
-            );
565
-        }
566
-        $query_params[0] = $where_params;
567
-        // don't use $query_params with count()
568
-        // because we don't want to include additional query clauses like "GROUP BY"
569
-        return $count
570
-            ? $this->count(array($where_params), 'EVT_ID', true)
571
-            : $this->get_all($query_params);
572
-    }
573
-
574
-
575
-
576
-    /**
577
-     * This only returns events that are expired.
578
-     * They may still be published but all their datetimes have expired.
579
-     *
580
-     * @param  array $query_params An array of query params to further filter on
581
-     *                             (note that status and DTT_EVT_end will be overridden)
582
-     * @param bool   $count        whether to return the count or not (default FALSE)
583
-     * @return EE_Event[]|int
584
-     * @throws \EE_Error
585
-     */
586
-    public function get_expired_events($query_params, $count = false)
587
-    {
588
-        $where_params = isset($query_params[0]) ? $query_params[0] : array();
589
-        // if we have count make sure we don't include group by
590
-        if ($count && isset($query_params['group_by'])) {
591
-            unset($query_params['group_by']);
592
-        }
593
-        // let's add specific query_params for active_events
594
-        // keep in mind this will override any sent status in the query AND any date queries.
595
-        if (isset($where_params['status'])) {
596
-            unset($where_params['status']);
597
-        }
598
-        $exclude_query = $query_params;
599
-        if (isset($exclude_query[0])) {
600
-            unset($exclude_query[0]);
601
-        }
602
-        $exclude_query[0] = array(
603
-            'Datetime.DTT_EVT_end' => array(
604
-                '>',
605
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
606
-            ),
607
-        );
608
-        // first get all events that have datetimes where its not expired.
609
-        $event_ids = $this->_get_all_wpdb_results($exclude_query, OBJECT_K, 'Event_CPT.ID');
610
-        $event_ids = array_keys($event_ids);
611
-        // if we have any additional query_params, let's add them to the 'AND' condition
612
-        $and_condition = array(
613
-            'Datetime.DTT_EVT_end' => array('<', EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end')),
614
-            'EVT_ID'               => array('NOT IN', $event_ids),
615
-        );
616
-        if (isset($where_params['OR'])) {
617
-            $and_condition['OR'] = $where_params['OR'];
618
-            unset($where_params['OR']);
619
-        }
620
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
621
-            $and_condition['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
622
-            unset($where_params['Datetime.DTT_EVT_end']);
623
-        }
624
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
625
-            $and_condition['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
626
-            unset($where_params['Datetime.DTT_EVT_start']);
627
-        }
628
-        // merge remaining $where params with the and conditions.
629
-        $where_params['AND'] = array_merge($and_condition, $where_params);
630
-        $query_params[0] = $where_params;
631
-        // don't use $query_params with count()
632
-        // because we don't want to include additional query clauses like "GROUP BY"
633
-        return $count
634
-            ? $this->count(array($where_params), 'EVT_ID', true)
635
-            : $this->get_all($query_params);
636
-    }
637
-
638
-
639
-
640
-    /**
641
-     * This basically just returns the events that do not have the publish status.
642
-     *
643
-     * @param  array   $query_params An array of query params to further filter on
644
-     *                               (note that status will be overwritten)
645
-     * @param  boolean $count        whether to return the count or not (default FALSE)
646
-     * @return EE_Event[]|int
647
-     * @throws \EE_Error
648
-     */
649
-    public function get_inactive_events($query_params, $count = false)
650
-    {
651
-        $where_params = isset($query_params[0]) ? $query_params[0] : array();
652
-        // let's add in specific query_params for inactive events.
653
-        if (isset($where_params['status'])) {
654
-            unset($where_params['status']);
655
-        }
656
-        // if we have count make sure we don't include group by
657
-        if ($count && isset($query_params['group_by'])) {
658
-            unset($query_params['group_by']);
659
-        }
660
-        // if we have any additional query_params, let's add them to the 'AND' condition
661
-        $where_params['AND']['status'] = array('!=', 'publish');
662
-        if (isset($where_params['OR'])) {
663
-            $where_params['AND']['OR'] = $where_params['OR'];
664
-            unset($where_params['OR']);
665
-        }
666
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
667
-            $where_params['AND']['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
668
-            unset($where_params['Datetime.DTT_EVT_end']);
669
-        }
670
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
671
-            $where_params['AND']['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
672
-            unset($where_params['Datetime.DTT_EVT_start']);
673
-        }
674
-        $query_params[0] = $where_params;
675
-        // don't use $query_params with count()
676
-        // because we don't want to include additional query clauses like "GROUP BY"
677
-        return $count
678
-            ? $this->count(array($where_params), 'EVT_ID', true)
679
-            : $this->get_all($query_params);
680
-    }
681
-
682
-
683
-
684
-    /**
685
-     * This is just injecting into the parent add_relationship_to so we do special handling on price relationships
686
-     * because we don't want to override any existing global default prices but instead insert NEW prices that get
687
-     * attached to the event. See parent for param descriptions
688
-     *
689
-     * @param        $id_or_obj
690
-     * @param        $other_model_id_or_obj
691
-     * @param string $relationName
692
-     * @param array  $where_query
693
-     * @return EE_Base_Class
694
-     * @throws EE_Error
695
-     */
696
-    public function add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query = array())
697
-    {
698
-        if ($relationName === 'Price') {
699
-            //let's get the PRC object for the given ID to make sure that we aren't dealing with a default
700
-            $prc_chk = $this->get_related_model_obj($relationName)->ensure_is_obj($other_model_id_or_obj);
701
-            //if EVT_ID = 0, then this is a default
702
-            if ((int) $prc_chk->get('EVT_ID') === 0) {
703
-                //let's set the prc_id as 0 so we force an insert on the add_relation_to carried out by relation
704
-                $prc_chk->set('PRC_ID', 0);
705
-            }
706
-            //run parent
707
-            return parent::add_relationship_to($id_or_obj, $prc_chk, $relationName, $where_query);
708
-        }
709
-        //otherwise carry on as normal
710
-        return parent::add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query);
711
-    }
712
-
713
-
714
-
715
-    /******************** DEPRECATED METHODS ********************/
716
-
717
-
718
-
719
-    /**
720
-     * _get_question_target_db_column
721
-     *
722
-     * @deprecated as of 4.8.32.rc.001. Instead consider using
723
-     *             EE_Registration_Custom_Questions_Form located in
724
-     *             admin_pages/registrations/form_sections/EE_Registration_Custom_Questions_Form.form.php
725
-     * @access     public
726
-     * @param    EE_Registration $registration (so existing answers for registration are included)
727
-     * @param    int             $EVT_ID       so all question groups are included for event (not just answers from
728
-     *                                         registration).
729
-     * @throws EE_Error
730
-     * @return    array
731
-     */
732
-    public function assemble_array_of_groups_questions_and_options(EE_Registration $registration, $EVT_ID = 0)
733
-    {
734
-        if (empty($EVT_ID)) {
735
-            throw new EE_Error(__('An error occurred. No EVT_ID is included.  Needed to know which question groups to retrieve.',
736
-                'event_espresso'));
737
-        }
738
-        $questions = array();
739
-        // get all question groups for event
740
-        $qgs = $this->get_question_groups_for_event($EVT_ID, $registration);
741
-        if (! empty($qgs)) {
742
-            foreach ($qgs as $qg) {
743
-                $qsts = $qg->questions();
744
-                $questions[$qg->ID()] = $qg->model_field_array();
745
-                $questions[$qg->ID()]['QSG_questions'] = array();
746
-                foreach ($qsts as $qst) {
747
-                    if ($qst->is_system_question()) {
748
-                        continue;
749
-                    }
750
-                    $answer = EEM_Answer::instance()->get_one(array(
751
-                        array(
752
-                            'QST_ID' => $qst->ID(),
753
-                            'REG_ID' => $registration->ID(),
754
-                        ),
755
-                    ));
756
-                    $answer = $answer instanceof EE_Answer ? $answer : EEM_Answer::instance()->create_default_object();
757
-                    $qst_name = $qstn_id = $qst->ID();
758
-                    $ans_id = $answer->ID();
759
-                    $qst_name = ! empty($ans_id) ? '[' . $qst_name . '][' . $ans_id . ']' : '[' . $qst_name . ']';
760
-                    $input_name = '';
761
-                    $input_id = sanitize_key($qst->display_text());
762
-                    $input_class = '';
763
-                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()] = $qst->model_field_array();
764
-                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_name'] = 'qstn'
765
-                                                                                           . $input_name
766
-                                                                                           . $qst_name;
767
-                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_id'] = $input_id . '-' . $qstn_id;
768
-                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_class'] = $input_class;
769
-                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_options'] = array();
770
-                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['qst_obj'] = $qst;
771
-                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['ans_obj'] = $answer;
772
-                    //leave responses as-is, don't convert stuff into html entities please!
773
-                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['htmlentities'] = false;
774
-                    if ($qst->type() == 'RADIO_BTN' || $qst->type() == 'CHECKBOX' || $qst->type() == 'DROPDOWN') {
775
-                        $QSOs = $qst->options(true, $answer->value());
776
-                        if (is_array($QSOs)) {
777
-                            foreach ($QSOs as $QSO_ID => $QSO) {
778
-                                $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_options'][$QSO_ID] = $QSO->model_field_array();
779
-                            }
780
-                        }
781
-                    }
782
-                }
783
-            }
784
-        }
785
-        return $questions;
786
-    }
787
-
788
-
789
-    /**
790
-     * @param mixed $cols_n_values either an array of where each key is the name of a field, and the value is its value
791
-     *                             or an stdClass where each property is the name of a column,
792
-     * @return EE_Base_Class
793
-     * @throws \EE_Error
794
-     */
795
-    public function instantiate_class_from_array_or_object($cols_n_values)
796
-    {
797
-        $classInstance = parent::instantiate_class_from_array_or_object($cols_n_values);
798
-        if($classInstance instanceof EE_Event) {
799
-            //events have their timezone defined in the DB, so use it immediately
800
-            $this->set_timezone($classInstance->get_timezone());
801
-        }
802
-        return $classInstance;
803
-    }
21
+	/**
22
+	 * constant used by status(), indicating that no more tickets can be purchased for any of the datetimes for the
23
+	 * event
24
+	 */
25
+	const sold_out = 'sold_out';
26
+
27
+	/**
28
+	 * constant used by status(), indicating that upcoming event dates have been postponed (may be pushed to a later
29
+	 * date)
30
+	 */
31
+	const postponed = 'postponed';
32
+
33
+	/**
34
+	 * constant used by status(), indicating that the event will no longer occur
35
+	 */
36
+	const cancelled = 'cancelled';
37
+
38
+
39
+	/**
40
+	 * @var string
41
+	 */
42
+	protected static $_default_reg_status;
43
+
44
+
45
+	/**
46
+	 * This is the default for the additional limit field.
47
+	 * @var int
48
+	 */
49
+	protected static $_default_additional_limit = 10;
50
+
51
+
52
+	/**
53
+	 * private instance of the Event object
54
+	 *
55
+	 * @var EEM_Event
56
+	 */
57
+	protected static $_instance;
58
+
59
+
60
+
61
+
62
+	/**
63
+	 * Adds a relationship to Term_Taxonomy for each CPT_Base
64
+	 *
65
+	 * @param string $timezone
66
+	 * @throws \EE_Error
67
+	 */
68
+	protected function __construct($timezone = null)
69
+	{
70
+		EE_Registry::instance()->load_model('Registration');
71
+		$this->singular_item = esc_html__('Event', 'event_espresso');
72
+		$this->plural_item = esc_html__('Events', 'event_espresso');
73
+		// to remove Cancelled events from the frontend, copy the following filter to your functions.php file
74
+		// add_filter( 'AFEE__EEM_Event__construct___custom_stati__cancelled__Public', '__return_false' );
75
+		// to remove Postponed events from the frontend, copy the following filter to your functions.php file
76
+		// add_filter( 'AFEE__EEM_Event__construct___custom_stati__postponed__Public', '__return_false' );
77
+		// to remove Sold Out events from the frontend, copy the following filter to your functions.php file
78
+		//	add_filter( 'AFEE__EEM_Event__construct___custom_stati__sold_out__Public', '__return_false' );
79
+		$this->_custom_stati = apply_filters(
80
+			'AFEE__EEM_Event__construct___custom_stati',
81
+			array(
82
+				EEM_Event::cancelled => array(
83
+					'label'  => esc_html__('Cancelled', 'event_espresso'),
84
+					'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__cancelled__Public', true),
85
+				),
86
+				EEM_Event::postponed => array(
87
+					'label'  => esc_html__('Postponed', 'event_espresso'),
88
+					'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__postponed__Public', true),
89
+				),
90
+				EEM_Event::sold_out  => array(
91
+					'label'  => esc_html__('Sold Out', 'event_espresso'),
92
+					'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__sold_out__Public', true),
93
+				),
94
+			)
95
+		);
96
+		self::$_default_reg_status = empty(self::$_default_reg_status) ? EEM_Registration::status_id_pending_payment
97
+			: self::$_default_reg_status;
98
+		$this->_tables = array(
99
+			'Event_CPT'  => new EE_Primary_Table('posts', 'ID'),
100
+			'Event_Meta' => new EE_Secondary_Table('esp_event_meta', 'EVTM_ID', 'EVT_ID'),
101
+		);
102
+		$this->_fields = array(
103
+			'Event_CPT'  => array(
104
+				'EVT_ID'         => new EE_Primary_Key_Int_Field('ID',
105
+					esc_html__('Post ID for Event', 'event_espresso')),
106
+				'EVT_name'       => new EE_Plain_Text_Field('post_title', esc_html__('Event Name', 'event_espresso'),
107
+					false,
108
+					''),
109
+				'EVT_desc'       => new EE_Post_Content_Field('post_content',
110
+					esc_html__('Event Description', 'event_espresso'),
111
+					false, ''),
112
+				'EVT_slug'       => new EE_Slug_Field('post_name', esc_html__('Event Slug', 'event_espresso'), false,
113
+					''),
114
+				'EVT_created'    => new EE_Datetime_Field('post_date',
115
+					esc_html__('Date/Time Event Created', 'event_espresso'),
116
+					false, EE_Datetime_Field::now),
117
+				'EVT_short_desc' => new EE_Simple_HTML_Field('post_excerpt',
118
+					esc_html__('Event Short Description', 'event_espresso'), false, ''),
119
+				'EVT_modified'   => new EE_Datetime_Field('post_modified',
120
+					esc_html__('Date/Time Event Modified', 'event_espresso'), false, EE_Datetime_Field::now),
121
+				'EVT_wp_user'    => new EE_WP_User_Field('post_author',
122
+					esc_html__('Event Creator ID', 'event_espresso'),
123
+					false),
124
+				'parent'         => new EE_Integer_Field('post_parent', esc_html__('Event Parent ID', 'event_espresso'),
125
+					false,
126
+					0),
127
+				'EVT_order'      => new EE_Integer_Field('menu_order', esc_html__('Event Menu Order', 'event_espresso'),
128
+					false,
129
+					1),
130
+				'post_type'      => new EE_WP_Post_Type_Field('espresso_events'),
131
+				// EE_Plain_Text_Field( 'post_type', esc_html__( 'Event Post Type', 'event_espresso' ), FALSE, 'espresso_events' ),
132
+				'status'         => new EE_WP_Post_Status_Field('post_status',
133
+					esc_html__('Event Status', 'event_espresso'),
134
+					false, 'draft', $this->_custom_stati),
135
+			),
136
+			'Event_Meta' => array(
137
+				'EVTM_ID'                         => new EE_DB_Only_Float_Field('EVTM_ID',
138
+					esc_html__('Event Meta Row ID', 'event_espresso'), false),
139
+				'EVT_ID_fk'                       => new EE_DB_Only_Int_Field('EVT_ID',
140
+					esc_html__('Foreign key to Event ID from Event Meta table', 'event_espresso'), false),
141
+				'EVT_display_desc'                => new EE_Boolean_Field('EVT_display_desc',
142
+					esc_html__('Display Description Flag', 'event_espresso'), false, 1),
143
+				'EVT_display_ticket_selector'     => new EE_Boolean_Field('EVT_display_ticket_selector',
144
+					esc_html__('Display Ticket Selector Flag', 'event_espresso'), false, 1),
145
+				'EVT_visible_on'                  => new EE_Datetime_Field('EVT_visible_on',
146
+					esc_html__('Event Visible Date', 'event_espresso'), true, EE_Datetime_Field::now),
147
+				'EVT_additional_limit'            => new EE_Integer_Field(
148
+					'EVT_additional_limit',
149
+					esc_html__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
150
+					true,
151
+					self::$_default_additional_limit
152
+				),
153
+				'EVT_default_registration_status' => new EE_Enum_Text_Field(
154
+					'EVT_default_registration_status',
155
+					esc_html__('Default Registration Status on this Event', 'event_espresso'), false,
156
+					EEM_Event::$_default_reg_status, EEM_Registration::reg_status_array()
157
+				),
158
+				'EVT_member_only'                 => new EE_Boolean_Field('EVT_member_only',
159
+					esc_html__('Member-Only Event Flag', 'event_espresso'), false, false),
160
+				'EVT_phone'                       => new EE_Plain_Text_Field('EVT_phone',
161
+					esc_html__('Event Phone Number', 'event_espresso'), false,''),
162
+				'EVT_allow_overflow'              => new EE_Boolean_Field('EVT_allow_overflow',
163
+					esc_html__('Allow Overflow on Event', 'event_espresso'), false, false),
164
+				'EVT_timezone_string'             => new EE_Plain_Text_Field('EVT_timezone_string',
165
+					esc_html__('Timezone (name) for Event times', 'event_espresso'), false,''),
166
+				'EVT_external_URL'                => new EE_Plain_Text_Field('EVT_external_URL',
167
+					esc_html__('URL of Event Page if hosted elsewhere', 'event_espresso'), true),
168
+				'EVT_donations'                   => new EE_Boolean_Field('EVT_donations',
169
+					esc_html__('Accept Donations?', 'event_espresso'), false, false),
170
+			),
171
+		);
172
+		$this->_model_relations = array(
173
+			'Registration'           => new EE_Has_Many_Relation(),
174
+			'Datetime'               => new EE_Has_Many_Relation(),
175
+			'Question_Group'         => new EE_HABTM_Relation('Event_Question_Group'),
176
+			'Venue'                  => new EE_HABTM_Relation('Event_Venue'),
177
+			'Term_Relationship'      => new EE_Has_Many_Relation(),
178
+			'Term_Taxonomy'          => new EE_HABTM_Relation('Term_Relationship'),
179
+			'Message_Template_Group' => new EE_HABTM_Relation('Event_Message_Template'),
180
+			'Attendee'               => new EE_HABTM_Relation('Registration'),
181
+			'WP_User'                => new EE_Belongs_To_Relation(),
182
+		);
183
+		//this model is generally available for reading
184
+		$this->_cap_restriction_generators[EEM_Base::caps_read] = new EE_Restriction_Generator_Public();
185
+		parent::__construct($timezone);
186
+	}
187
+
188
+
189
+
190
+	/**
191
+	 * @param string $default_reg_status
192
+	 */
193
+	public static function set_default_reg_status($default_reg_status)
194
+	{
195
+		self::$_default_reg_status = $default_reg_status;
196
+		// if EEM_Event has already been instantiated,
197
+		// then we need to reset the `EVT_default_reg_status` field to use the new default.
198
+		if (self::$_instance instanceof EEM_Event) {
199
+			$default_reg_status = new EE_Enum_Text_Field(
200
+				'EVT_default_registration_status',
201
+				esc_html__('Default Registration Status on this Event', 'event_espresso'),
202
+				false,
203
+				$default_reg_status,
204
+				EEM_Registration::reg_status_array()
205
+			);
206
+			$default_reg_status->_construct_finalize(
207
+				'Event_Meta',
208
+				'EVT_default_registration_status',
209
+				'EEM_Event'
210
+			);
211
+			self::$_instance->_fields['Event_Meta']['EVT_default_registration_status'] = $default_reg_status;
212
+		}
213
+	}
214
+
215
+
216
+	/**
217
+	 * Used to override the default for the additional limit field.
218
+	 * @param $additional_limit
219
+	 */
220
+	public static function set_default_additional_limit($additional_limit)
221
+	{
222
+		self::$_default_additional_limit = (int) $additional_limit;
223
+		if (self::$_instance instanceof EEM_Event) {
224
+			self::$_instance->_fields['Event_Meta']['EVT_additional_limit'] = new EE_Integer_Field(
225
+				'EVT_additional_limit',
226
+				__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
227
+				true,
228
+				self::$_default_additional_limit
229
+			);
230
+			self::$_instance->_fields['Event_Meta']['EVT_additional_limit']->_construct_finalize(
231
+				'Event_Meta',
232
+				'EVT_additional_limit',
233
+				'EEM_Event'
234
+			);
235
+		}
236
+	}
237
+
238
+
239
+	/**
240
+	 * Return what is currently set as the default additional limit for the event.
241
+	 * @return int
242
+	 */
243
+	public static function get_default_additional_limit()
244
+	{
245
+		return apply_filters('FHEE__EEM_Event__get_default_additional_limit', self::$_default_additional_limit);
246
+	}
247
+
248
+
249
+	/**
250
+	 * get_question_groups
251
+	 *
252
+	 * @return array
253
+	 * @throws \EE_Error
254
+	 */
255
+	public function get_all_question_groups()
256
+	{
257
+		return EE_Registry::instance()->load_model('Question_Group')->get_all(
258
+			array(
259
+				array('QSG_deleted' => false),
260
+				'order_by' => array('QSG_order' => 'ASC'),
261
+			)
262
+		);
263
+	}
264
+
265
+
266
+
267
+	/**
268
+	 * get_question_groups
269
+	 *
270
+	 * @param int $EVT_ID
271
+	 * @return array|bool
272
+	 * @throws \EE_Error
273
+	 */
274
+	public function get_all_event_question_groups($EVT_ID = 0)
275
+	{
276
+		if (! isset($EVT_ID) || ! absint($EVT_ID)) {
277
+			EE_Error::add_error(
278
+				esc_html__(
279
+					'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
280
+					'event_espresso'
281
+				),
282
+				__FILE__, __FUNCTION__, __LINE__
283
+			);
284
+			return false;
285
+		}
286
+		return EE_Registry::instance()->load_model('Event_Question_Group')->get_all(
287
+			array(
288
+				array('EVT_ID' => $EVT_ID),
289
+			)
290
+		);
291
+	}
292
+
293
+
294
+
295
+	/**
296
+	 * get_question_groups
297
+	 *
298
+	 * @param int     $EVT_ID
299
+	 * @param boolean $for_primary_attendee
300
+	 * @return array|bool
301
+	 * @throws \EE_Error
302
+	 */
303
+	public function get_event_question_groups($EVT_ID = 0, $for_primary_attendee = true)
304
+	{
305
+		if (! isset($EVT_ID) || ! absint($EVT_ID)) {
306
+			EE_Error::add_error(
307
+				esc_html__(
308
+					'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
309
+					'event_espresso'
310
+				),
311
+				__FILE__, __FUNCTION__, __LINE__
312
+			);
313
+			return false;
314
+		}
315
+		return EE_Registry::instance()->load_model('Event_Question_Group')->get_all(
316
+			array(
317
+				array(
318
+					'EVT_ID'      => $EVT_ID,
319
+					'EQG_primary' => $for_primary_attendee,
320
+				),
321
+			)
322
+		);
323
+	}
324
+
325
+
326
+
327
+	/**
328
+	 * get_question_groups
329
+	 *
330
+	 * @param int             $EVT_ID
331
+	 * @param EE_Registration $registration
332
+	 * @return array|bool
333
+	 * @throws \EE_Error
334
+	 */
335
+	public function get_question_groups_for_event($EVT_ID = 0, EE_Registration $registration)
336
+	{
337
+		if (! isset($EVT_ID) || ! absint($EVT_ID)) {
338
+			EE_Error::add_error(
339
+				esc_html__(
340
+					'An error occurred. No Question Groups could be retrieved because an Event ID was not received.',
341
+					'event_espresso'
342
+				),
343
+				__FILE__, __FUNCTION__, __LINE__
344
+			);
345
+			return false;
346
+		}
347
+		$where_params = array(
348
+			'Event_Question_Group.EVT_ID'      => $EVT_ID,
349
+			'Event_Question_Group.EQG_primary' => $registration->count() === 1 ? true : false,
350
+			'QSG_deleted'                      => false,
351
+		);
352
+		return EE_Registry::instance()->load_model('Question_Group')->get_all(
353
+			array(
354
+				$where_params,
355
+				'order_by' => array('QSG_order' => 'ASC'),
356
+			)
357
+		);
358
+	}
359
+
360
+
361
+
362
+	/**
363
+	 * get_question_target_db_column
364
+	 *
365
+	 * @param string $QSG_IDs csv list of $QSG IDs
366
+	 * @return array|bool
367
+	 * @throws \EE_Error
368
+	 */
369
+	public function get_questions_in_groups($QSG_IDs = '')
370
+	{
371
+		if (empty($QSG_IDs)) {
372
+			EE_Error::add_error(
373
+				esc_html__('An error occurred. No Question Group IDs were received.', 'event_espresso'),
374
+				__FILE__, __FUNCTION__, __LINE__
375
+			);
376
+			return false;
377
+		}
378
+		return EE_Registry::instance()->load_model('Question')->get_all(
379
+			array(
380
+				array(
381
+					'Question_Group.QSG_ID' => array('IN', $QSG_IDs),
382
+					'QST_deleted'           => false,
383
+					'QST_admin_only'        => is_admin(),
384
+				),
385
+				'order_by' => 'QST_order',
386
+			)
387
+		);
388
+	}
389
+
390
+
391
+
392
+	/**
393
+	 * get_options_for_question
394
+	 *
395
+	 * @param string $QST_IDs csv list of $QST IDs
396
+	 * @return array|bool
397
+	 * @throws \EE_Error
398
+	 */
399
+	public function get_options_for_question($QST_IDs)
400
+	{
401
+		if (empty($QST_IDs)) {
402
+			EE_Error::add_error(
403
+				esc_html__('An error occurred. No Question IDs were received.', 'event_espresso'),
404
+				__FILE__, __FUNCTION__, __LINE__
405
+			);
406
+			return false;
407
+		}
408
+		return EE_Registry::instance()->load_model('Question_Option')->get_all(
409
+			array(
410
+				array(
411
+					'Question.QST_ID' => array('IN', $QST_IDs),
412
+					'QSO_deleted'     => false,
413
+				),
414
+				'order_by' => 'QSO_ID',
415
+			)
416
+		);
417
+	}
418
+
419
+
420
+
421
+
422
+
423
+
424
+
425
+	/**
426
+	 * Gets all events that are published
427
+	 * and have event start time earlier than now and an event end time later than now
428
+	 *
429
+	 * @param  array $query_params An array of query params to further filter on
430
+	 *                             (note that status and DTT_EVT_start and DTT_EVT_end will be overridden)
431
+	 * @param bool   $count        whether to return the count or not (default FALSE)
432
+	 * @return EE_Event[]|int
433
+	 * @throws \EE_Error
434
+	 */
435
+	public function get_active_events($query_params, $count = false)
436
+	{
437
+		if (array_key_exists(0, $query_params)) {
438
+			$where_params = $query_params[0];
439
+			unset($query_params[0]);
440
+		} else {
441
+			$where_params = array();
442
+		}
443
+		// if we have count make sure we don't include group by
444
+		if ($count && isset($query_params['group_by'])) {
445
+			unset($query_params['group_by']);
446
+		}
447
+		// let's add specific query_params for active_events
448
+		// keep in mind this will override any sent status in the query AND any date queries.
449
+		$where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
450
+		//if already have where params for DTT_EVT_start or DTT_EVT_end then append these conditions
451
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
452
+			$where_params['Datetime.DTT_EVT_start******'] = array(
453
+				'<',
454
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
455
+			);
456
+		} else {
457
+			$where_params['Datetime.DTT_EVT_start'] = array(
458
+				'<',
459
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
460
+			);
461
+		}
462
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
463
+			$where_params['Datetime.DTT_EVT_end*****'] = array(
464
+				'>',
465
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
466
+			);
467
+		} else {
468
+			$where_params['Datetime.DTT_EVT_end'] = array(
469
+				'>',
470
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
471
+			);
472
+		}
473
+		$query_params[0] = $where_params;
474
+		// don't use $query_params with count()
475
+		// because we don't want to include additional query clauses like "GROUP BY"
476
+		return $count
477
+			? $this->count(array($where_params), 'EVT_ID', true)
478
+			: $this->get_all($query_params);
479
+	}
480
+
481
+
482
+
483
+	/**
484
+	 * get all events that are published and have an event start time later than now
485
+	 *
486
+	 * @param  array $query_params An array of query params to further filter on
487
+	 *                             (Note that status and DTT_EVT_start will be overridden)
488
+	 * @param bool   $count        whether to return the count or not (default FALSE)
489
+	 * @return EE_Event[]|int
490
+	 * @throws \EE_Error
491
+	 */
492
+	public function get_upcoming_events($query_params, $count = false)
493
+	{
494
+		if (array_key_exists(0, $query_params)) {
495
+			$where_params = $query_params[0];
496
+			unset($query_params[0]);
497
+		} else {
498
+			$where_params = array();
499
+		}
500
+		// if we have count make sure we don't include group by
501
+		if ($count && isset($query_params['group_by'])) {
502
+			unset($query_params['group_by']);
503
+		}
504
+		// let's add specific query_params for active_events
505
+		// keep in mind this will override any sent status in the query AND any date queries.
506
+		$where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
507
+		// if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
508
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
509
+			$where_params['Datetime.DTT_EVT_start*****'] = array(
510
+				'>',
511
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
512
+			);
513
+		} else {
514
+			$where_params['Datetime.DTT_EVT_start'] = array(
515
+				'>',
516
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
517
+			);
518
+		}
519
+		$query_params[0] = $where_params;
520
+		// don't use $query_params with count()
521
+		// because we don't want to include additional query clauses like "GROUP BY"
522
+		return $count
523
+			? $this->count(array($where_params), 'EVT_ID', true)
524
+			: $this->get_all($query_params);
525
+	}
526
+
527
+
528
+
529
+	/**
530
+	 * Gets all events that are published
531
+	 * and have an event end time later than now
532
+	 *
533
+	 * @param  array $query_params An array of query params to further filter on
534
+	 *                             (note that status and DTT_EVT_end will be overridden)
535
+	 * @param bool   $count        whether to return the count or not (default FALSE)
536
+	 * @return EE_Event[]|int
537
+	 * @throws \EE_Error
538
+	 */
539
+	public function get_active_and_upcoming_events($query_params, $count = false)
540
+	{
541
+		if (array_key_exists(0, $query_params)) {
542
+			$where_params = $query_params[0];
543
+			unset($query_params[0]);
544
+		} else {
545
+			$where_params = array();
546
+		}
547
+		// if we have count make sure we don't include group by
548
+		if ($count && isset($query_params['group_by'])) {
549
+			unset($query_params['group_by']);
550
+		}
551
+		// let's add specific query_params for active_events
552
+		// keep in mind this will override any sent status in the query AND any date queries.
553
+		$where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
554
+		// add where params for DTT_EVT_end
555
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
556
+			$where_params['Datetime.DTT_EVT_end*****'] = array(
557
+				'>',
558
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
559
+			);
560
+		} else {
561
+			$where_params['Datetime.DTT_EVT_end'] = array(
562
+				'>',
563
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
564
+			);
565
+		}
566
+		$query_params[0] = $where_params;
567
+		// don't use $query_params with count()
568
+		// because we don't want to include additional query clauses like "GROUP BY"
569
+		return $count
570
+			? $this->count(array($where_params), 'EVT_ID', true)
571
+			: $this->get_all($query_params);
572
+	}
573
+
574
+
575
+
576
+	/**
577
+	 * This only returns events that are expired.
578
+	 * They may still be published but all their datetimes have expired.
579
+	 *
580
+	 * @param  array $query_params An array of query params to further filter on
581
+	 *                             (note that status and DTT_EVT_end will be overridden)
582
+	 * @param bool   $count        whether to return the count or not (default FALSE)
583
+	 * @return EE_Event[]|int
584
+	 * @throws \EE_Error
585
+	 */
586
+	public function get_expired_events($query_params, $count = false)
587
+	{
588
+		$where_params = isset($query_params[0]) ? $query_params[0] : array();
589
+		// if we have count make sure we don't include group by
590
+		if ($count && isset($query_params['group_by'])) {
591
+			unset($query_params['group_by']);
592
+		}
593
+		// let's add specific query_params for active_events
594
+		// keep in mind this will override any sent status in the query AND any date queries.
595
+		if (isset($where_params['status'])) {
596
+			unset($where_params['status']);
597
+		}
598
+		$exclude_query = $query_params;
599
+		if (isset($exclude_query[0])) {
600
+			unset($exclude_query[0]);
601
+		}
602
+		$exclude_query[0] = array(
603
+			'Datetime.DTT_EVT_end' => array(
604
+				'>',
605
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
606
+			),
607
+		);
608
+		// first get all events that have datetimes where its not expired.
609
+		$event_ids = $this->_get_all_wpdb_results($exclude_query, OBJECT_K, 'Event_CPT.ID');
610
+		$event_ids = array_keys($event_ids);
611
+		// if we have any additional query_params, let's add them to the 'AND' condition
612
+		$and_condition = array(
613
+			'Datetime.DTT_EVT_end' => array('<', EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end')),
614
+			'EVT_ID'               => array('NOT IN', $event_ids),
615
+		);
616
+		if (isset($where_params['OR'])) {
617
+			$and_condition['OR'] = $where_params['OR'];
618
+			unset($where_params['OR']);
619
+		}
620
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
621
+			$and_condition['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
622
+			unset($where_params['Datetime.DTT_EVT_end']);
623
+		}
624
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
625
+			$and_condition['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
626
+			unset($where_params['Datetime.DTT_EVT_start']);
627
+		}
628
+		// merge remaining $where params with the and conditions.
629
+		$where_params['AND'] = array_merge($and_condition, $where_params);
630
+		$query_params[0] = $where_params;
631
+		// don't use $query_params with count()
632
+		// because we don't want to include additional query clauses like "GROUP BY"
633
+		return $count
634
+			? $this->count(array($where_params), 'EVT_ID', true)
635
+			: $this->get_all($query_params);
636
+	}
637
+
638
+
639
+
640
+	/**
641
+	 * This basically just returns the events that do not have the publish status.
642
+	 *
643
+	 * @param  array   $query_params An array of query params to further filter on
644
+	 *                               (note that status will be overwritten)
645
+	 * @param  boolean $count        whether to return the count or not (default FALSE)
646
+	 * @return EE_Event[]|int
647
+	 * @throws \EE_Error
648
+	 */
649
+	public function get_inactive_events($query_params, $count = false)
650
+	{
651
+		$where_params = isset($query_params[0]) ? $query_params[0] : array();
652
+		// let's add in specific query_params for inactive events.
653
+		if (isset($where_params['status'])) {
654
+			unset($where_params['status']);
655
+		}
656
+		// if we have count make sure we don't include group by
657
+		if ($count && isset($query_params['group_by'])) {
658
+			unset($query_params['group_by']);
659
+		}
660
+		// if we have any additional query_params, let's add them to the 'AND' condition
661
+		$where_params['AND']['status'] = array('!=', 'publish');
662
+		if (isset($where_params['OR'])) {
663
+			$where_params['AND']['OR'] = $where_params['OR'];
664
+			unset($where_params['OR']);
665
+		}
666
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
667
+			$where_params['AND']['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
668
+			unset($where_params['Datetime.DTT_EVT_end']);
669
+		}
670
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
671
+			$where_params['AND']['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
672
+			unset($where_params['Datetime.DTT_EVT_start']);
673
+		}
674
+		$query_params[0] = $where_params;
675
+		// don't use $query_params with count()
676
+		// because we don't want to include additional query clauses like "GROUP BY"
677
+		return $count
678
+			? $this->count(array($where_params), 'EVT_ID', true)
679
+			: $this->get_all($query_params);
680
+	}
681
+
682
+
683
+
684
+	/**
685
+	 * This is just injecting into the parent add_relationship_to so we do special handling on price relationships
686
+	 * because we don't want to override any existing global default prices but instead insert NEW prices that get
687
+	 * attached to the event. See parent for param descriptions
688
+	 *
689
+	 * @param        $id_or_obj
690
+	 * @param        $other_model_id_or_obj
691
+	 * @param string $relationName
692
+	 * @param array  $where_query
693
+	 * @return EE_Base_Class
694
+	 * @throws EE_Error
695
+	 */
696
+	public function add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query = array())
697
+	{
698
+		if ($relationName === 'Price') {
699
+			//let's get the PRC object for the given ID to make sure that we aren't dealing with a default
700
+			$prc_chk = $this->get_related_model_obj($relationName)->ensure_is_obj($other_model_id_or_obj);
701
+			//if EVT_ID = 0, then this is a default
702
+			if ((int) $prc_chk->get('EVT_ID') === 0) {
703
+				//let's set the prc_id as 0 so we force an insert on the add_relation_to carried out by relation
704
+				$prc_chk->set('PRC_ID', 0);
705
+			}
706
+			//run parent
707
+			return parent::add_relationship_to($id_or_obj, $prc_chk, $relationName, $where_query);
708
+		}
709
+		//otherwise carry on as normal
710
+		return parent::add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query);
711
+	}
712
+
713
+
714
+
715
+	/******************** DEPRECATED METHODS ********************/
716
+
717
+
718
+
719
+	/**
720
+	 * _get_question_target_db_column
721
+	 *
722
+	 * @deprecated as of 4.8.32.rc.001. Instead consider using
723
+	 *             EE_Registration_Custom_Questions_Form located in
724
+	 *             admin_pages/registrations/form_sections/EE_Registration_Custom_Questions_Form.form.php
725
+	 * @access     public
726
+	 * @param    EE_Registration $registration (so existing answers for registration are included)
727
+	 * @param    int             $EVT_ID       so all question groups are included for event (not just answers from
728
+	 *                                         registration).
729
+	 * @throws EE_Error
730
+	 * @return    array
731
+	 */
732
+	public function assemble_array_of_groups_questions_and_options(EE_Registration $registration, $EVT_ID = 0)
733
+	{
734
+		if (empty($EVT_ID)) {
735
+			throw new EE_Error(__('An error occurred. No EVT_ID is included.  Needed to know which question groups to retrieve.',
736
+				'event_espresso'));
737
+		}
738
+		$questions = array();
739
+		// get all question groups for event
740
+		$qgs = $this->get_question_groups_for_event($EVT_ID, $registration);
741
+		if (! empty($qgs)) {
742
+			foreach ($qgs as $qg) {
743
+				$qsts = $qg->questions();
744
+				$questions[$qg->ID()] = $qg->model_field_array();
745
+				$questions[$qg->ID()]['QSG_questions'] = array();
746
+				foreach ($qsts as $qst) {
747
+					if ($qst->is_system_question()) {
748
+						continue;
749
+					}
750
+					$answer = EEM_Answer::instance()->get_one(array(
751
+						array(
752
+							'QST_ID' => $qst->ID(),
753
+							'REG_ID' => $registration->ID(),
754
+						),
755
+					));
756
+					$answer = $answer instanceof EE_Answer ? $answer : EEM_Answer::instance()->create_default_object();
757
+					$qst_name = $qstn_id = $qst->ID();
758
+					$ans_id = $answer->ID();
759
+					$qst_name = ! empty($ans_id) ? '[' . $qst_name . '][' . $ans_id . ']' : '[' . $qst_name . ']';
760
+					$input_name = '';
761
+					$input_id = sanitize_key($qst->display_text());
762
+					$input_class = '';
763
+					$questions[$qg->ID()]['QSG_questions'][$qst->ID()] = $qst->model_field_array();
764
+					$questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_name'] = 'qstn'
765
+																						   . $input_name
766
+																						   . $qst_name;
767
+					$questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_id'] = $input_id . '-' . $qstn_id;
768
+					$questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_class'] = $input_class;
769
+					$questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_options'] = array();
770
+					$questions[$qg->ID()]['QSG_questions'][$qst->ID()]['qst_obj'] = $qst;
771
+					$questions[$qg->ID()]['QSG_questions'][$qst->ID()]['ans_obj'] = $answer;
772
+					//leave responses as-is, don't convert stuff into html entities please!
773
+					$questions[$qg->ID()]['QSG_questions'][$qst->ID()]['htmlentities'] = false;
774
+					if ($qst->type() == 'RADIO_BTN' || $qst->type() == 'CHECKBOX' || $qst->type() == 'DROPDOWN') {
775
+						$QSOs = $qst->options(true, $answer->value());
776
+						if (is_array($QSOs)) {
777
+							foreach ($QSOs as $QSO_ID => $QSO) {
778
+								$questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_options'][$QSO_ID] = $QSO->model_field_array();
779
+							}
780
+						}
781
+					}
782
+				}
783
+			}
784
+		}
785
+		return $questions;
786
+	}
787
+
788
+
789
+	/**
790
+	 * @param mixed $cols_n_values either an array of where each key is the name of a field, and the value is its value
791
+	 *                             or an stdClass where each property is the name of a column,
792
+	 * @return EE_Base_Class
793
+	 * @throws \EE_Error
794
+	 */
795
+	public function instantiate_class_from_array_or_object($cols_n_values)
796
+	{
797
+		$classInstance = parent::instantiate_class_from_array_or_object($cols_n_values);
798
+		if($classInstance instanceof EE_Event) {
799
+			//events have their timezone defined in the DB, so use it immediately
800
+			$this->set_timezone($classInstance->get_timezone());
801
+		}
802
+		return $classInstance;
803
+	}
804 804
 }
805 805
 // End of file EEM_Event.model.php
806 806
 // Location: /includes/models/EEM_Event.model.php
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -1,9 +1,9 @@  discard block
 block discarded – undo
1 1
 <?php use EventEspresso\core\services\orm\ModelFieldFactory;
2 2
 
3
-if (! defined('EVENT_ESPRESSO_VERSION')) {
3
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
4 4
     exit('No direct script access allowed');
5 5
 }
6
-require_once(EE_MODELS . 'EEM_CPT_Base.model.php');
6
+require_once(EE_MODELS.'EEM_CPT_Base.model.php');
7 7
 
8 8
 
9 9
 
@@ -158,11 +158,11 @@  discard block
 block discarded – undo
158 158
                 'EVT_member_only'                 => new EE_Boolean_Field('EVT_member_only',
159 159
                     esc_html__('Member-Only Event Flag', 'event_espresso'), false, false),
160 160
                 'EVT_phone'                       => new EE_Plain_Text_Field('EVT_phone',
161
-                    esc_html__('Event Phone Number', 'event_espresso'), false,''),
161
+                    esc_html__('Event Phone Number', 'event_espresso'), false, ''),
162 162
                 'EVT_allow_overflow'              => new EE_Boolean_Field('EVT_allow_overflow',
163 163
                     esc_html__('Allow Overflow on Event', 'event_espresso'), false, false),
164 164
                 'EVT_timezone_string'             => new EE_Plain_Text_Field('EVT_timezone_string',
165
-                    esc_html__('Timezone (name) for Event times', 'event_espresso'), false,''),
165
+                    esc_html__('Timezone (name) for Event times', 'event_espresso'), false, ''),
166 166
                 'EVT_external_URL'                => new EE_Plain_Text_Field('EVT_external_URL',
167 167
                     esc_html__('URL of Event Page if hosted elsewhere', 'event_espresso'), true),
168 168
                 'EVT_donations'                   => new EE_Boolean_Field('EVT_donations',
@@ -273,7 +273,7 @@  discard block
 block discarded – undo
273 273
      */
274 274
     public function get_all_event_question_groups($EVT_ID = 0)
275 275
     {
276
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
276
+        if ( ! isset($EVT_ID) || ! absint($EVT_ID)) {
277 277
             EE_Error::add_error(
278 278
                 esc_html__(
279 279
                     'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
@@ -302,7 +302,7 @@  discard block
 block discarded – undo
302 302
      */
303 303
     public function get_event_question_groups($EVT_ID = 0, $for_primary_attendee = true)
304 304
     {
305
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
305
+        if ( ! isset($EVT_ID) || ! absint($EVT_ID)) {
306 306
             EE_Error::add_error(
307 307
                 esc_html__(
308 308
                     'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
@@ -334,7 +334,7 @@  discard block
 block discarded – undo
334 334
      */
335 335
     public function get_question_groups_for_event($EVT_ID = 0, EE_Registration $registration)
336 336
     {
337
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
337
+        if ( ! isset($EVT_ID) || ! absint($EVT_ID)) {
338 338
             EE_Error::add_error(
339 339
                 esc_html__(
340 340
                     'An error occurred. No Question Groups could be retrieved because an Event ID was not received.',
@@ -738,7 +738,7 @@  discard block
 block discarded – undo
738 738
         $questions = array();
739 739
         // get all question groups for event
740 740
         $qgs = $this->get_question_groups_for_event($EVT_ID, $registration);
741
-        if (! empty($qgs)) {
741
+        if ( ! empty($qgs)) {
742 742
             foreach ($qgs as $qg) {
743 743
                 $qsts = $qg->questions();
744 744
                 $questions[$qg->ID()] = $qg->model_field_array();
@@ -756,7 +756,7 @@  discard block
 block discarded – undo
756 756
                     $answer = $answer instanceof EE_Answer ? $answer : EEM_Answer::instance()->create_default_object();
757 757
                     $qst_name = $qstn_id = $qst->ID();
758 758
                     $ans_id = $answer->ID();
759
-                    $qst_name = ! empty($ans_id) ? '[' . $qst_name . '][' . $ans_id . ']' : '[' . $qst_name . ']';
759
+                    $qst_name = ! empty($ans_id) ? '['.$qst_name.']['.$ans_id.']' : '['.$qst_name.']';
760 760
                     $input_name = '';
761 761
                     $input_id = sanitize_key($qst->display_text());
762 762
                     $input_class = '';
@@ -764,7 +764,7 @@  discard block
 block discarded – undo
764 764
                     $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_name'] = 'qstn'
765 765
                                                                                            . $input_name
766 766
                                                                                            . $qst_name;
767
-                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_id'] = $input_id . '-' . $qstn_id;
767
+                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_id'] = $input_id.'-'.$qstn_id;
768 768
                     $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_class'] = $input_class;
769 769
                     $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_options'] = array();
770 770
                     $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['qst_obj'] = $qst;
@@ -795,7 +795,7 @@  discard block
 block discarded – undo
795 795
     public function instantiate_class_from_array_or_object($cols_n_values)
796 796
     {
797 797
         $classInstance = parent::instantiate_class_from_array_or_object($cols_n_values);
798
-        if($classInstance instanceof EE_Event) {
798
+        if ($classInstance instanceof EE_Event) {
799 799
             //events have their timezone defined in the DB, so use it immediately
800 800
             $this->set_timezone($classInstance->get_timezone());
801 801
         }
Please login to merge, or discard this patch.
core/db_models/EEM_Base.model.php 1 patch
Indentation   +6004 added lines, -6004 removed lines patch added patch discarded remove patch
@@ -32,6012 +32,6012 @@
 block discarded – undo
32 32
 abstract class EEM_Base extends EE_Base implements ResettableInterface
33 33
 {
34 34
 
35
-    /**
36
-     * Flag to indicate whether the values provided to EEM_Base have already been prepared
37
-     * by the model object or not (ie, the model object has used the field's _prepare_for_set function on the values).
38
-     * They almost always WILL NOT, but it's not necessarily a requirement.
39
-     * For example, if you want to run EEM_Event::instance()->get_all(array(array('EVT_ID'=>$_GET['event_id'])));
40
-     *
41
-     * @var boolean
42
-     */
43
-    private $_values_already_prepared_by_model_object = 0;
44
-
45
-    /**
46
-     * when $_values_already_prepared_by_model_object equals this, we assume
47
-     * the data is just like form input that needs to have the model fields'
48
-     * prepare_for_set and prepare_for_use_in_db called on it
49
-     */
50
-    const not_prepared_by_model_object = 0;
51
-
52
-    /**
53
-     * when $_values_already_prepared_by_model_object equals this, we
54
-     * assume this value is coming from a model object and doesn't need to have
55
-     * prepare_for_set called on it, just prepare_for_use_in_db is used
56
-     */
57
-    const prepared_by_model_object = 1;
58
-
59
-    /**
60
-     * when $_values_already_prepared_by_model_object equals this, we assume
61
-     * the values are already to be used in the database (ie no processing is done
62
-     * on them by the model's fields)
63
-     */
64
-    const prepared_for_use_in_db = 2;
65
-
66
-
67
-    protected $singular_item = 'Item';
68
-
69
-    protected $plural_item   = 'Items';
70
-
71
-    /**
72
-     * @type \EE_Table_Base[] $_tables array of EE_Table objects for defining which tables comprise this model.
73
-     */
74
-    protected $_tables;
75
-
76
-    /**
77
-     * with two levels: top-level has array keys which are database table aliases (ie, keys in _tables)
78
-     * and the value is an array. Each of those sub-arrays have keys of field names (eg 'ATT_ID', which should also be
79
-     * variable names on the model objects (eg, EE_Attendee), and the keys should be children of EE_Model_Field
80
-     *
81
-     * @var \EE_Model_Field_Base[][] $_fields
82
-     */
83
-    protected $_fields;
84
-
85
-    /**
86
-     * array of different kinds of relations
87
-     *
88
-     * @var \EE_Model_Relation_Base[] $_model_relations
89
-     */
90
-    protected $_model_relations;
91
-
92
-    /**
93
-     * @var \EE_Index[] $_indexes
94
-     */
95
-    protected $_indexes = array();
96
-
97
-    /**
98
-     * Default strategy for getting where conditions on this model. This strategy is used to get default
99
-     * where conditions which are added to get_all, update, and delete queries. They can be overridden
100
-     * by setting the same columns as used in these queries in the query yourself.
101
-     *
102
-     * @var EE_Default_Where_Conditions
103
-     */
104
-    protected $_default_where_conditions_strategy;
105
-
106
-    /**
107
-     * Strategy for getting conditions on this model when 'default_where_conditions' equals 'minimum'.
108
-     * This is particularly useful when you want something between 'none' and 'default'
109
-     *
110
-     * @var EE_Default_Where_Conditions
111
-     */
112
-    protected $_minimum_where_conditions_strategy;
113
-
114
-    /**
115
-     * String describing how to find the "owner" of this model's objects.
116
-     * When there is a foreign key on this model to the wp_users table, this isn't needed.
117
-     * But when there isn't, this indicates which related model, or transiently-related model,
118
-     * has the foreign key to the wp_users table.
119
-     * Eg, for EEM_Registration this would be 'Event' because registrations are directly
120
-     * related to events, and events have a foreign key to wp_users.
121
-     * On EEM_Transaction, this would be 'Transaction.Event'
122
-     *
123
-     * @var string
124
-     */
125
-    protected $_model_chain_to_wp_user = '';
126
-
127
-    /**
128
-     * This is a flag typically set by updates so that we don't load the where strategy on updates because updates
129
-     * don't need it (particularly CPT models)
130
-     *
131
-     * @var bool
132
-     */
133
-    protected $_ignore_where_strategy = false;
134
-
135
-    /**
136
-     * String used in caps relating to this model. Eg, if the caps relating to this
137
-     * model are 'ee_edit_events', 'ee_read_events', etc, it would be 'events'.
138
-     *
139
-     * @var string. If null it hasn't been initialized yet. If false then we
140
-     * have indicated capabilities don't apply to this
141
-     */
142
-    protected $_caps_slug = null;
143
-
144
-    /**
145
-     * 2d array where top-level keys are one of EEM_Base::valid_cap_contexts(),
146
-     * and next-level keys are capability names, and each's value is a
147
-     * EE_Default_Where_Condition. If the requester requests to apply caps to the query,
148
-     * they specify which context to use (ie, frontend, backend, edit or delete)
149
-     * and then each capability in the corresponding sub-array that they're missing
150
-     * adds the where conditions onto the query.
151
-     *
152
-     * @var array
153
-     */
154
-    protected $_cap_restrictions = array(
155
-        self::caps_read       => array(),
156
-        self::caps_read_admin => array(),
157
-        self::caps_edit       => array(),
158
-        self::caps_delete     => array(),
159
-    );
160
-
161
-    /**
162
-     * Array defining which cap restriction generators to use to create default
163
-     * cap restrictions to put in EEM_Base::_cap_restrictions.
164
-     * Array-keys are one of EEM_Base::valid_cap_contexts(), and values are a child of
165
-     * EE_Restriction_Generator_Base. If you don't want any cap restrictions generated
166
-     * automatically set this to false (not just null).
167
-     *
168
-     * @var EE_Restriction_Generator_Base[]
169
-     */
170
-    protected $_cap_restriction_generators = array();
171
-
172
-    /**
173
-     * constants used to categorize capability restrictions on EEM_Base::_caps_restrictions
174
-     */
175
-    const caps_read       = 'read';
176
-
177
-    const caps_read_admin = 'read_admin';
178
-
179
-    const caps_edit       = 'edit';
180
-
181
-    const caps_delete     = 'delete';
182
-
183
-    /**
184
-     * Keys are all the cap contexts (ie constants EEM_Base::_caps_*) and values are their 'action'
185
-     * as how they'd be used in capability names. Eg EEM_Base::caps_read ('read_frontend')
186
-     * maps to 'read' because when looking for relevant permissions we're going to use
187
-     * 'read' in teh capabilities names like 'ee_read_events' etc.
188
-     *
189
-     * @var array
190
-     */
191
-    protected $_cap_contexts_to_cap_action_map = array(
192
-        self::caps_read       => 'read',
193
-        self::caps_read_admin => 'read',
194
-        self::caps_edit       => 'edit',
195
-        self::caps_delete     => 'delete',
196
-    );
197
-
198
-    /**
199
-     * Timezone
200
-     * This gets set via the constructor so that we know what timezone incoming strings|timestamps are in when there
201
-     * are EE_Datetime_Fields in use.  This can also be used before a get to set what timezone you want strings coming
202
-     * out of the created objects.  NOT all EEM_Base child classes use this property but any that use a
203
-     * EE_Datetime_Field data type will have access to it.
204
-     *
205
-     * @var string
206
-     */
207
-    protected $_timezone;
208
-
209
-
210
-    /**
211
-     * This holds the id of the blog currently making the query.  Has no bearing on single site but is used for
212
-     * multisite.
213
-     *
214
-     * @var int
215
-     */
216
-    protected static $_model_query_blog_id;
217
-
218
-    /**
219
-     * A copy of _fields, except the array keys are the model names pointed to by
220
-     * the field
221
-     *
222
-     * @var EE_Model_Field_Base[]
223
-     */
224
-    private $_cache_foreign_key_to_fields = array();
225
-
226
-    /**
227
-     * Cached list of all the fields on the model, indexed by their name
228
-     *
229
-     * @var EE_Model_Field_Base[]
230
-     */
231
-    private $_cached_fields = null;
232
-
233
-    /**
234
-     * Cached list of all the fields on the model, except those that are
235
-     * marked as only pertinent to the database
236
-     *
237
-     * @var EE_Model_Field_Base[]
238
-     */
239
-    private $_cached_fields_non_db_only = null;
240
-
241
-    /**
242
-     * A cached reference to the primary key for quick lookup
243
-     *
244
-     * @var EE_Model_Field_Base
245
-     */
246
-    private $_primary_key_field = null;
247
-
248
-    /**
249
-     * Flag indicating whether this model has a primary key or not
250
-     *
251
-     * @var boolean
252
-     */
253
-    protected $_has_primary_key_field = null;
254
-
255
-    /**
256
-     * Whether or not this model is based off a table in WP core only (CPTs should set
257
-     * this to FALSE, but if we were to make an EE_WP_Post model, it should set this to true).
258
-     * This should be true for models that deal with data that should exist independent of EE.
259
-     * For example, if the model can read and insert data that isn't used by EE, this should be true.
260
-     * It would be false, however, if you could guarantee the model would only interact with EE data,
261
-     * even if it uses a WP core table (eg event and venue models set this to false for that reason:
262
-     * they can only read and insert events and venues custom post types, not arbitrary post types)
263
-     * @var boolean
264
-     */
265
-    protected $_wp_core_model = false;
266
-
267
-    /**
268
-     *    List of valid operators that can be used for querying.
269
-     * The keys are all operators we'll accept, the values are the real SQL
270
-     * operators used
271
-     *
272
-     * @var array
273
-     */
274
-    protected $_valid_operators = array(
275
-        '='           => '=',
276
-        '<='          => '<=',
277
-        '<'           => '<',
278
-        '>='          => '>=',
279
-        '>'           => '>',
280
-        '!='          => '!=',
281
-        'LIKE'        => 'LIKE',
282
-        'like'        => 'LIKE',
283
-        'NOT_LIKE'    => 'NOT LIKE',
284
-        'not_like'    => 'NOT LIKE',
285
-        'NOT LIKE'    => 'NOT LIKE',
286
-        'not like'    => 'NOT LIKE',
287
-        'IN'          => 'IN',
288
-        'in'          => 'IN',
289
-        'NOT_IN'      => 'NOT IN',
290
-        'not_in'      => 'NOT IN',
291
-        'NOT IN'      => 'NOT IN',
292
-        'not in'      => 'NOT IN',
293
-        'between'     => 'BETWEEN',
294
-        'BETWEEN'     => 'BETWEEN',
295
-        'IS_NOT_NULL' => 'IS NOT NULL',
296
-        'is_not_null' => 'IS NOT NULL',
297
-        'IS NOT NULL' => 'IS NOT NULL',
298
-        'is not null' => 'IS NOT NULL',
299
-        'IS_NULL'     => 'IS NULL',
300
-        'is_null'     => 'IS NULL',
301
-        'IS NULL'     => 'IS NULL',
302
-        'is null'     => 'IS NULL',
303
-        'REGEXP'      => 'REGEXP',
304
-        'regexp'      => 'REGEXP',
305
-        'NOT_REGEXP'  => 'NOT REGEXP',
306
-        'not_regexp'  => 'NOT REGEXP',
307
-        'NOT REGEXP'  => 'NOT REGEXP',
308
-        'not regexp'  => 'NOT REGEXP',
309
-    );
310
-
311
-    /**
312
-     * operators that work like 'IN', accepting a comma-separated list of values inside brackets. Eg '(1,2,3)'
313
-     *
314
-     * @var array
315
-     */
316
-    protected $_in_style_operators = array('IN', 'NOT IN');
317
-
318
-    /**
319
-     * operators that work like 'BETWEEN'.  Typically used for datetime calculations, i.e. "BETWEEN '12-1-2011' AND
320
-     * '12-31-2012'"
321
-     *
322
-     * @var array
323
-     */
324
-    protected $_between_style_operators = array('BETWEEN');
325
-
326
-    /**
327
-     * Operators that work like SQL's like: input should be assumed to be a string, already prepared for a LIKE query.
328
-     * @var array
329
-     */
330
-    protected $_like_style_operators = array('LIKE', 'NOT LIKE');
331
-    /**
332
-     * operators that are used for handling NUll and !NULL queries.  Typically used for when checking if a row exists
333
-     * on a join table.
334
-     *
335
-     * @var array
336
-     */
337
-    protected $_null_style_operators = array('IS NOT NULL', 'IS NULL');
338
-
339
-    /**
340
-     * Allowed values for $query_params['order'] for ordering in queries
341
-     *
342
-     * @var array
343
-     */
344
-    protected $_allowed_order_values = array('asc', 'desc', 'ASC', 'DESC');
345
-
346
-    /**
347
-     * When these are keys in a WHERE or HAVING clause, they are handled much differently
348
-     * than regular field names. It is assumed that their values are an array of WHERE conditions
349
-     *
350
-     * @var array
351
-     */
352
-    private $_logic_query_param_keys = array('not', 'and', 'or', 'NOT', 'AND', 'OR');
353
-
354
-    /**
355
-     * Allowed keys in $query_params arrays passed into queries. Note that 0 is meant to always be a
356
-     * 'where', but 'where' clauses are so common that we thought we'd omit it
357
-     *
358
-     * @var array
359
-     */
360
-    private $_allowed_query_params = array(
361
-        0,
362
-        'limit',
363
-        'order_by',
364
-        'group_by',
365
-        'having',
366
-        'force_join',
367
-        'order',
368
-        'on_join_limit',
369
-        'default_where_conditions',
370
-        'caps',
371
-    );
372
-
373
-    /**
374
-     * All the data types that can be used in $wpdb->prepare statements.
375
-     *
376
-     * @var array
377
-     */
378
-    private $_valid_wpdb_data_types = array('%d', '%s', '%f');
379
-
380
-    /**
381
-     * @var EE_Registry $EE
382
-     */
383
-    protected $EE = null;
384
-
385
-
386
-    /**
387
-     * Property which, when set, will have this model echo out the next X queries to the page for debugging.
388
-     *
389
-     * @var int
390
-     */
391
-    protected $_show_next_x_db_queries = 0;
392
-
393
-    /**
394
-     * When using _get_all_wpdb_results, you can specify a custom selection. If you do so,
395
-     * it gets saved on this property so those selections can be used in WHERE, GROUP_BY, etc.
396
-     *
397
-     * @var array
398
-     */
399
-    protected $_custom_selections = array();
400
-
401
-    /**
402
-     * key => value Entity Map using  array( EEM_Base::$_model_query_blog_id => array( ID => model object ) )
403
-     * caches every model object we've fetched from the DB on this request
404
-     *
405
-     * @var array
406
-     */
407
-    protected $_entity_map;
408
-
409
-    /**
410
-     * @var LoaderInterface $loader
411
-     */
412
-    private static $loader;
413
-
414
-
415
-    /**
416
-     * constant used to show EEM_Base has not yet verified the db on this http request
417
-     */
418
-    const db_verified_none = 0;
419
-
420
-    /**
421
-     * constant used to show EEM_Base has verified the EE core db on this http request,
422
-     * but not the addons' dbs
423
-     */
424
-    const db_verified_core = 1;
425
-
426
-    /**
427
-     * constant used to show EEM_Base has verified the addons' dbs (and implicitly
428
-     * the EE core db too)
429
-     */
430
-    const db_verified_addons = 2;
431
-
432
-    /**
433
-     * indicates whether an EEM_Base child has already re-verified the DB
434
-     * is ok (we don't want to do it repetitively). Should be set to one the constants
435
-     * looking like EEM_Base::db_verified_*
436
-     *
437
-     * @var int - 0 = none, 1 = core, 2 = addons
438
-     */
439
-    protected static $_db_verification_level = EEM_Base::db_verified_none;
440
-
441
-    /**
442
-     * @const constant for 'default_where_conditions' to apply default where conditions to ALL queried models
443
-     *        (eg, if retrieving registrations ordered by their datetimes, this will only return non-trashed
444
-     *        registrations for non-trashed tickets for non-trashed datetimes)
445
-     */
446
-    const default_where_conditions_all = 'all';
447
-
448
-    /**
449
-     * @const constant for 'default_where_conditions' to apply default where conditions to THIS model only, but
450
-     *        no other models which are joined to (eg, if retrieving registrations ordered by their datetimes, this will
451
-     *        return non-trashed registrations, regardless of the related datetimes and tickets' statuses).
452
-     *        It is preferred to use EEM_Base::default_where_conditions_minimum_others because, when joining to
453
-     *        models which share tables with other models, this can return data for the wrong model.
454
-     */
455
-    const default_where_conditions_this_only = 'this_model_only';
456
-
457
-    /**
458
-     * @const constant for 'default_where_conditions' to apply default where conditions to other models queried,
459
-     *        but not the current model (eg, if retrieving registrations ordered by their datetimes, this will
460
-     *        return all registrations related to non-trashed tickets and non-trashed datetimes)
461
-     */
462
-    const default_where_conditions_others_only = 'other_models_only';
463
-
464
-    /**
465
-     * @const constant for 'default_where_conditions' to apply minimum where conditions to all models queried.
466
-     *        For most models this the same as EEM_Base::default_where_conditions_none, except for models which share
467
-     *        their table with other models, like the Event and Venue models. For example, when querying for events
468
-     *        ordered by their venues' name, this will be sure to only return real events with associated real venues
469
-     *        (regardless of whether those events and venues are trashed)
470
-     *        In contrast, using EEM_Base::default_where_conditions_none would could return WP posts other than EE
471
-     *        events.
472
-     */
473
-    const default_where_conditions_minimum_all = 'minimum';
474
-
475
-    /**
476
-     * @const constant for 'default_where_conditions' to apply apply where conditions to other models, and full default
477
-     *        where conditions for the queried model (eg, when querying events ordered by venues' names, this will
478
-     *        return non-trashed events for any venues, regardless of whether those associated venues are trashed or
479
-     *        not)
480
-     */
481
-    const default_where_conditions_minimum_others = 'full_this_minimum_others';
482
-
483
-    /**
484
-     * @const constant for 'default_where_conditions' to NOT apply any where conditions. This should very rarely be
485
-     *        used, because when querying from a model which shares its table with another model (eg Events and Venues)
486
-     *        it's possible it will return table entries for other models. You should use
487
-     *        EEM_Base::default_where_conditions_minimum_all instead.
488
-     */
489
-    const default_where_conditions_none = 'none';
490
-
491
-
492
-
493
-    /**
494
-     * About all child constructors:
495
-     * they should define the _tables, _fields and _model_relations arrays.
496
-     * Should ALWAYS be called after child constructor.
497
-     * In order to make the child constructors to be as simple as possible, this parent constructor
498
-     * finalizes constructing all the object's attributes.
499
-     * Generally, rather than requiring a child to code
500
-     * $this->_tables = array(
501
-     *        'Event_Post_Table' => new EE_Table('Event_Post_Table','wp_posts')
502
-     *        ...);
503
-     *  (thus repeating itself in the array key and in the constructor of the new EE_Table,)
504
-     * each EE_Table has a function to set the table's alias after the constructor, using
505
-     * the array key ('Event_Post_Table'), instead of repeating it. The model fields and model relations
506
-     * do something similar.
507
-     *
508
-     * @param null $timezone
509
-     * @throws EE_Error
510
-     */
511
-    protected function __construct($timezone = null)
512
-    {
513
-        // check that the model has not been loaded too soon
514
-        if (! did_action('AHEE__EE_System__load_espresso_addons')) {
515
-            throw new EE_Error (
516
-                sprintf(
517
-                    __('The %1$s model can not be loaded before the "AHEE__EE_System__load_espresso_addons" hook has been called. This gives other addons a chance to extend this model.',
518
-                        'event_espresso'),
519
-                    get_class($this)
520
-                )
521
-            );
522
-        }
523
-        /**
524
-         * Set blogid for models to current blog. However we ONLY do this if $_model_query_blog_id is not already set.
525
-         */
526
-        if (empty(EEM_Base::$_model_query_blog_id)) {
527
-            EEM_Base::set_model_query_blog_id();
528
-        }
529
-        /**
530
-         * Filters the list of tables on a model. It is best to NOT use this directly and instead
531
-         * just use EE_Register_Model_Extension
532
-         *
533
-         * @var EE_Table_Base[] $_tables
534
-         */
535
-        $this->_tables = (array)apply_filters('FHEE__' . get_class($this) . '__construct__tables', $this->_tables);
536
-        foreach ($this->_tables as $table_alias => $table_obj) {
537
-            /** @var $table_obj EE_Table_Base */
538
-            $table_obj->_construct_finalize_with_alias($table_alias);
539
-            if ($table_obj instanceof EE_Secondary_Table) {
540
-                /** @var $table_obj EE_Secondary_Table */
541
-                $table_obj->_construct_finalize_set_table_to_join_with($this->_get_main_table());
542
-            }
543
-        }
544
-        /**
545
-         * Filters the list of fields on a model. It is best to NOT use this directly and instead just use
546
-         * EE_Register_Model_Extension
547
-         *
548
-         * @param EE_Model_Field_Base[] $_fields
549
-         */
550
-        $this->_fields = (array)apply_filters('FHEE__' . get_class($this) . '__construct__fields', $this->_fields);
551
-        $this->_invalidate_field_caches();
552
-        foreach ($this->_fields as $table_alias => $fields_for_table) {
553
-            if (! array_key_exists($table_alias, $this->_tables)) {
554
-                throw new EE_Error(sprintf(__("Table alias %s does not exist in EEM_Base child's _tables array. Only tables defined are %s",
555
-                    'event_espresso'), $table_alias, implode(",", $this->_fields)));
556
-            }
557
-            foreach ($fields_for_table as $field_name => $field_obj) {
558
-                /** @var $field_obj EE_Model_Field_Base | EE_Primary_Key_Field_Base */
559
-                //primary key field base has a slightly different _construct_finalize
560
-                /** @var $field_obj EE_Model_Field_Base */
561
-                $field_obj->_construct_finalize($table_alias, $field_name, $this->get_this_model_name());
562
-            }
563
-        }
564
-        // everything is related to Extra_Meta
565
-        if (get_class($this) !== 'EEM_Extra_Meta') {
566
-            //make extra meta related to everything, but don't block deleting things just
567
-            //because they have related extra meta info. For now just orphan those extra meta
568
-            //in the future we should automatically delete them
569
-            $this->_model_relations['Extra_Meta'] = new EE_Has_Many_Any_Relation(false);
570
-        }
571
-        //and change logs
572
-        if (get_class($this) !== 'EEM_Change_Log') {
573
-            $this->_model_relations['Change_Log'] = new EE_Has_Many_Any_Relation(false);
574
-        }
575
-        /**
576
-         * Filters the list of relations on a model. It is best to NOT use this directly and instead just use
577
-         * EE_Register_Model_Extension
578
-         *
579
-         * @param EE_Model_Relation_Base[] $_model_relations
580
-         */
581
-        $this->_model_relations = (array)apply_filters('FHEE__' . get_class($this) . '__construct__model_relations',
582
-            $this->_model_relations);
583
-        foreach ($this->_model_relations as $model_name => $relation_obj) {
584
-            /** @var $relation_obj EE_Model_Relation_Base */
585
-            $relation_obj->_construct_finalize_set_models($this->get_this_model_name(), $model_name);
586
-        }
587
-        foreach ($this->_indexes as $index_name => $index_obj) {
588
-            /** @var $index_obj EE_Index */
589
-            $index_obj->_construct_finalize($index_name, $this->get_this_model_name());
590
-        }
591
-        $this->set_timezone($timezone);
592
-        //finalize default where condition strategy, or set default
593
-        if (! $this->_default_where_conditions_strategy) {
594
-            //nothing was set during child constructor, so set default
595
-            $this->_default_where_conditions_strategy = new EE_Default_Where_Conditions();
596
-        }
597
-        $this->_default_where_conditions_strategy->_finalize_construct($this);
598
-        if (! $this->_minimum_where_conditions_strategy) {
599
-            //nothing was set during child constructor, so set default
600
-            $this->_minimum_where_conditions_strategy = new EE_Default_Where_Conditions();
601
-        }
602
-        $this->_minimum_where_conditions_strategy->_finalize_construct($this);
603
-        //if the cap slug hasn't been set, and we haven't set it to false on purpose
604
-        //to indicate to NOT set it, set it to the logical default
605
-        if ($this->_caps_slug === null) {
606
-            $this->_caps_slug = EEH_Inflector::pluralize_and_lower($this->get_this_model_name());
607
-        }
608
-        //initialize the standard cap restriction generators if none were specified by the child constructor
609
-        if ($this->_cap_restriction_generators !== false) {
610
-            foreach ($this->cap_contexts_to_cap_action_map() as $cap_context => $action) {
611
-                if (! isset($this->_cap_restriction_generators[$cap_context])) {
612
-                    $this->_cap_restriction_generators[$cap_context] = apply_filters(
613
-                        'FHEE__EEM_Base___construct__standard_cap_restriction_generator',
614
-                        new EE_Restriction_Generator_Protected(),
615
-                        $cap_context,
616
-                        $this
617
-                    );
618
-                }
619
-            }
620
-        }
621
-        //if there are cap restriction generators, use them to make the default cap restrictions
622
-        if ($this->_cap_restriction_generators !== false) {
623
-            foreach ($this->_cap_restriction_generators as $context => $generator_object) {
624
-                if (! $generator_object) {
625
-                    continue;
626
-                }
627
-                if (! $generator_object instanceof EE_Restriction_Generator_Base) {
628
-                    throw new EE_Error(
629
-                        sprintf(
630
-                            __('Index "%1$s" in the model %2$s\'s _cap_restriction_generators is not a child of EE_Restriction_Generator_Base. It should be that or NULL.',
631
-                                'event_espresso'),
632
-                            $context,
633
-                            $this->get_this_model_name()
634
-                        )
635
-                    );
636
-                }
637
-                $action = $this->cap_action_for_context($context);
638
-                if (! $generator_object->construction_finalized()) {
639
-                    $generator_object->_construct_finalize($this, $action);
640
-                }
641
-            }
642
-        }
643
-        do_action('AHEE__' . get_class($this) . '__construct__end');
644
-    }
645
-
646
-
647
-
648
-    /**
649
-     * Used to set the $_model_query_blog_id static property.
650
-     *
651
-     * @param int $blog_id  If provided then will set the blog_id for the models to this id.  If not provided then the
652
-     *                      value for get_current_blog_id() will be used.
653
-     */
654
-    public static function set_model_query_blog_id($blog_id = 0)
655
-    {
656
-        EEM_Base::$_model_query_blog_id = $blog_id > 0 ? (int)$blog_id : get_current_blog_id();
657
-    }
658
-
659
-
660
-
661
-    /**
662
-     * Returns whatever is set as the internal $model_query_blog_id.
663
-     *
664
-     * @return int
665
-     */
666
-    public static function get_model_query_blog_id()
667
-    {
668
-        return EEM_Base::$_model_query_blog_id;
669
-    }
670
-
671
-
672
-
673
-    /**
674
-     * This function is a singleton method used to instantiate the Espresso_model object
675
-     *
676
-     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings
677
-     *                                (and any incoming timezone data that gets saved).
678
-     *                                Note this just sends the timezone info to the date time model field objects.
679
-     *                                Default is NULL
680
-     *                                (and will be assumed using the set timezone in the 'timezone_string' wp option)
681
-     * @return static (as in the concrete child class)
682
-     * @throws EE_Error
683
-     * @throws InvalidArgumentException
684
-     * @throws InvalidDataTypeException
685
-     * @throws InvalidInterfaceException
686
-     */
687
-    public static function instance($timezone = null)
688
-    {
689
-        // check if instance of Espresso_model already exists
690
-        if (! static::$_instance instanceof static) {
691
-            // instantiate Espresso_model
692
-            static::$_instance = new static(
693
-                $timezone,
694
-                LoaderFactory::getLoader()->load('EventEspresso\core\services\orm\ModelFieldFactory')
695
-            );
696
-        }
697
-        //we might have a timezone set, let set_timezone decide what to do with it
698
-        static::$_instance->set_timezone($timezone);
699
-        // Espresso_model object
700
-        return static::$_instance;
701
-    }
702
-
703
-
704
-
705
-    /**
706
-     * resets the model and returns it
707
-     *
708
-     * @param null | string $timezone
709
-     * @return EEM_Base|null (if the model was already instantiated, returns it, with
710
-     * all its properties reset; if it wasn't instantiated, returns null)
711
-     * @throws EE_Error
712
-     * @throws ReflectionException
713
-     * @throws InvalidArgumentException
714
-     * @throws InvalidDataTypeException
715
-     * @throws InvalidInterfaceException
716
-     */
717
-    public static function reset($timezone = null)
718
-    {
719
-        if (static::$_instance instanceof EEM_Base) {
720
-            //let's try to NOT swap out the current instance for a new one
721
-            //because if someone has a reference to it, we can't remove their reference
722
-            //so it's best to keep using the same reference, but change the original object
723
-            //reset all its properties to their original values as defined in the class
724
-            $r = new ReflectionClass(get_class(static::$_instance));
725
-            $static_properties = $r->getStaticProperties();
726
-            foreach ($r->getDefaultProperties() as $property => $value) {
727
-                //don't set instance to null like it was originally,
728
-                //but it's static anyways, and we're ignoring static properties (for now at least)
729
-                if (! isset($static_properties[$property])) {
730
-                    static::$_instance->{$property} = $value;
731
-                }
732
-            }
733
-            //and then directly call its constructor again, like we would if we were creating a new one
734
-            static::$_instance->__construct(
735
-                $timezone,
736
-                LoaderFactory::getLoader()->load('EventEspresso\core\services\orm\ModelFieldFactory')
737
-            );
738
-            return self::instance();
739
-        }
740
-        return null;
741
-    }
742
-
743
-
744
-
745
-    /**
746
-     * @return LoaderInterface
747
-     * @throws InvalidArgumentException
748
-     * @throws InvalidDataTypeException
749
-     * @throws InvalidInterfaceException
750
-     */
751
-    private static function getLoader()
752
-    {
753
-        if(! EEM_Base::$loader instanceof LoaderInterface) {
754
-            EEM_Base::$loader = LoaderFactory::getLoader();
755
-        }
756
-        return EEM_Base::$loader;
757
-    }
758
-
759
-
760
-
761
-    /**
762
-     * retrieve the status details from esp_status table as an array IF this model has the status table as a relation.
763
-     *
764
-     * @param  boolean $translated return localized strings or JUST the array.
765
-     * @return array
766
-     * @throws EE_Error
767
-     * @throws InvalidArgumentException
768
-     * @throws InvalidDataTypeException
769
-     * @throws InvalidInterfaceException
770
-     */
771
-    public function status_array($translated = false)
772
-    {
773
-        if (! array_key_exists('Status', $this->_model_relations)) {
774
-            return array();
775
-        }
776
-        $model_name = $this->get_this_model_name();
777
-        $status_type = str_replace(' ', '_', strtolower(str_replace('_', ' ', $model_name)));
778
-        $stati = EEM_Status::instance()->get_all(array(array('STS_type' => $status_type)));
779
-        $status_array = array();
780
-        foreach ($stati as $status) {
781
-            $status_array[$status->ID()] = $status->get('STS_code');
782
-        }
783
-        return $translated
784
-            ? EEM_Status::instance()->localized_status($status_array, false, 'sentence')
785
-            : $status_array;
786
-    }
787
-
788
-
789
-
790
-    /**
791
-     * Gets all the EE_Base_Class objects which match the $query_params, by querying the DB.
792
-     *
793
-     * @param array $query_params             {
794
-     * @var array $0 (where) array {
795
-     *                                        eg: array('QST_display_text'=>'Are you bob?','QST_admin_text'=>'Determine
796
-     *                                        if user is bob') becomes SQL >> "...WHERE QST_display_text = 'Are you
797
-     *                                        bob?' AND QST_admin_text = 'Determine if user is bob'...") To add WHERE
798
-     *                                        conditions based on related models (and even
799
-     *                                        models-related-to-related-models) prepend the model's name onto the field
800
-     *                                        name. Eg,
801
-     *                                        EEM_Event::instance()->get_all(array(array('Venue.VNU_ID'=>12))); becomes
802
-     *                                        SQL >> "SELECT * FROM wp_posts AS Event_CPT LEFT JOIN wp_esp_event_meta
803
-     *                                        AS Event_Meta ON Event_CPT.ID = Event_Meta.EVT_ID LEFT JOIN
804
-     *                                        wp_esp_event_venue AS Event_Venue ON Event_Venue.EVT_ID=Event_CPT.ID LEFT
805
-     *                                        JOIN wp_posts AS Venue_CPT ON Venue_CPT.ID=Event_Venue.VNU_ID LEFT JOIN
806
-     *                                        wp_esp_venue_meta AS Venue_Meta ON Venue_CPT.ID = Venue_Meta.VNU_ID WHERE
807
-     *                                        Venue_CPT.ID = 12 Notice that automatically took care of joining Events
808
-     *                                        to Venues (even when each of those models actually consisted of two
809
-     *                                        tables). Also, you may chain the model relations together. Eg instead of
810
-     *                                        just having
811
-     *                                        "Venue.VNU_ID", you could have
812
-     *                                        "Registration.Attendee.ATT_ID" as a field on a query for events (because
813
-     *                                        events are related to Registrations, which are related to Attendees). You
814
-     *                                        can take it even further with
815
-     *                                        "Registration.Transaction.Payment.PAY_amount" etc. To change the operator
816
-     *                                        (from the default of '='), change the value to an numerically-indexed
817
-     *                                        array, where the first item in the list is the operator. eg: array(
818
-     *                                        'QST_display_text' => array('LIKE','%bob%'), 'QST_ID' => array('<',34),
819
-     *                                        'QST_wp_user' => array('in',array(1,2,7,23))) becomes SQL >> "...WHERE
820
-     *                                        QST_display_text LIKE '%bob%' AND QST_ID < 34 AND QST_wp_user IN
821
-     *                                        (1,2,7,23)...". Valid operators so far: =, !=, <, <=, >, >=, LIKE, NOT
822
-     *                                        LIKE, IN (followed by numeric-indexed array), NOT IN (dido), BETWEEN
823
-     *                                        (followed by an array with exactly 2 date strings), IS NULL, and IS NOT
824
-     *                                        NULL Values can be a string, int, or float. They can also be arrays IFF
825
-     *                                        the operator is IN. Also, values can actually be field names. To indicate
826
-     *                                        the value is a field, simply provide a third array item (true) to the
827
-     *                                        operator-value array like so: eg: array( 'DTT_reg_limit' => array('>',
828
-     *                                        'DTT_sold', TRUE) ) becomes SQL >> "...WHERE DTT_reg_limit > DTT_sold"
829
-     *                                        Note: you can also use related model field names like you would any other
830
-     *                                        field name. eg:
831
-     *                                        array('Datetime.DTT_reg_limit'=>array('=','Datetime.DTT_sold',TRUE) could
832
-     *                                        be used if you were querying EEM_Tickets (because Datetime is directly related to tickets) Also, by default all the where conditions are AND'd together. To override this, add an array key 'OR' (or 'AND') and the array to be OR'd together eg: array('OR'=>array('TXN_ID' => 23 , 'TXN_timestamp__>' =>
833
-     *                                        345678912)) becomes SQL >> "...WHERE TXN_ID = 23 OR TXN_timestamp =
834
-     *                                        345678912...". Also, to negate an entire set of conditions, use 'NOT' as
835
-     *                                        an array key. eg: array('NOT'=>array('TXN_total' =>
836
-     *                                        50, 'TXN_paid'=>23) becomes SQL >> "...where ! (TXN_total =50 AND
837
-     *                                        TXN_paid =23) Note: the 'glue' used to join each condition will continue
838
-     *                                        to be what you last specified. IE, "AND"s by default, but if you had
839
-     *                                        previously specified to use ORs to join, ORs will continue to be used.
840
-     *                                        So, if you specify to use an "OR" to join conditions, it will continue to
841
-     *                                        "stick" until you specify an AND. eg
842
-     *                                        array('OR'=>array('NOT'=>array('TXN_total' => 50,
843
-     *                                        'TXN_paid'=>23)),AND=>array('TXN_ID'=>1,'STS_ID'=>'TIN') becomes SQL >>
844
-     *                                        "...where ! (TXN_total =50 OR TXN_paid =23) AND TXN_ID=1 AND
845
-     *                                        STS_ID='TIN'" They can be nested indefinitely. eg:
846
-     *                                        array('OR'=>array('TXN_total' => 23, 'NOT'=> array( 'TXN_timestamp'=> 345678912, 'AND'=>array('TXN_paid' => 53, 'STS_ID' => 'TIN')))) becomes SQL >> "...WHERE TXN_total = 23 OR ! (TXN_timestamp = 345678912 OR (TXN_paid = 53 AND STS_ID = 'TIN'))..." GOTCHA: because this is an array, array keys must be unique, making it impossible to place two or more where conditions applying to the same field. eg: array('PAY_timestamp'=>array('>',$start_date),'PAY_timestamp'=>array('<',$end_date),'PAY_timestamp'=>array('!=',$special_date)), as PHP enforces that the array keys must be unique, thus removing the first two array entries with key 'PAY_timestamp'. becomes SQL >> "PAY_timestamp !=  4234232", ignoring the first two PAY_timestamp conditions). To overcome this, you can add a '*' character to the end of the field's name, followed by anything. These will be removed when generating the SQL string, but allow for the array keys to be unique. eg: you could rewrite the previous query as: array('PAY_timestamp'=>array('>',$start_date),'PAY_timestamp*1st'=>array('<',$end_date),'PAY_timestamp*2nd'=>array('!=',$special_date)) which correctly becomes SQL >>
847
-     *                                        "PAY_timestamp > 123412341 AND PAY_timestamp < 2354235235234 AND
848
-     *                                        PAY_timestamp != 1241234123" This can be applied to condition operators
849
-     *                                        too, eg:
850
-     *                                        array('OR'=>array('REG_ID'=>3,'Transaction.TXN_ID'=>23),'OR*whatever'=>array('Attendee.ATT_fname'=>'bob','Attendee.ATT_lname'=>'wilson')));
851
-     * @var mixed   $limit                    int|array    adds a limit to the query just like the SQL limit clause, so
852
-     *                                        limits of "23", "25,50", and array(23,42) are all valid would become SQL
853
-     *                                        "...LIMIT 23", "...LIMIT 25,50", and "...LIMIT 23,42" respectively.
854
-     *                                        Remember when you provide two numbers for the limit, the 1st number is
855
-     *                                        the OFFSET, the 2nd is the LIMIT
856
-     * @var array   $on_join_limit            allows the setting of a special select join with a internal limit so you
857
-     *                                        can do paging on one-to-many multi-table-joins. Send an array in the
858
-     *                                        following format array('on_join_limit'
859
-     *                                        => array( 'table_alias', array(1,2) ) ).
860
-     * @var mixed   $order_by                 name of a column to order by, or an array where keys are field names and
861
-     *                                        values are either 'ASC' or 'DESC'.
862
-     *                                        'limit'=>array('STS_ID'=>'ASC','REG_date'=>'DESC'), which would becomes
863
-     *                                        SQL "...ORDER BY TXN_timestamp..." and "...ORDER BY STS_ID ASC, REG_date
864
-     *                                        DESC..." respectively. Like the
865
-     *                                        'where' conditions, these fields can be on related models. Eg
866
-     *                                        'order_by'=>array('Registration.Transaction.TXN_amount'=>'ASC') is
867
-     *                                        perfectly valid from any model related to 'Registration' (like Event,
868
-     *                                        Attendee, Price, Datetime, etc.)
869
-     * @var string  $order                    If 'order_by' is used and its value is a string (NOT an array), then
870
-     *                                        'order' specifies whether to order the field specified in 'order_by' in
871
-     *                                        ascending or descending order. Acceptable values are 'ASC' or 'DESC'. If,
872
-     *                                        'order_by' isn't used, but 'order' is, then it is assumed you want to
873
-     *                                        order by the primary key. Eg,
874
-     *                                        EEM_Event::instance()->get_all(array('order_by'=>'Datetime.DTT_EVT_start','order'=>'ASC');
875
-     *                                        //(will join with the Datetime model's table(s) and order by its field
876
-     *                                        DTT_EVT_start) or
877
-     *                                        EEM_Registration::instance()->get_all(array('order'=>'ASC'));//will make
878
-     *                                        SQL "SELECT * FROM wp_esp_registration ORDER BY REG_ID ASC"
879
-     * @var mixed   $group_by                 name of field to order by, or an array of fields. Eg either
880
-     *                                        'group_by'=>'VNU_ID', or
881
-     *                                        'group_by'=>array('EVT_name','Registration.Transaction.TXN_total') Note:
882
-     *                                        if no
883
-     *                                        $group_by is specified, and a limit is set, automatically groups by the
884
-     *                                        model's primary key (or combined primary keys). This avoids some
885
-     *                                        weirdness that results when using limits, tons of joins, and no group by,
886
-     *                                        see https://events.codebasehq.com/projects/event-espresso/tickets/9389
887
-     * @var array   $having                   exactly like WHERE parameters array, except these conditions apply to the
888
-     *                                        grouped results (whereas WHERE conditions apply to the pre-grouped
889
-     *                                        results)
890
-     * @var array   $force_join               forces a join with the models named. Should be a numerically-indexed
891
-     *                                        array where values are models to be joined in the query.Eg
892
-     *                                        array('Attendee','Payment','Datetime'). You may join with transient
893
-     *                                        models using period, eg "Registration.Transaction.Payment". You will
894
-     *                                        probably only want to do this in hopes of increasing efficiency, as
895
-     *                                        related models which belongs to the current model
896
-     *                                        (ie, the current model has a foreign key to them, like how Registration
897
-     *                                        belongs to Attendee) can be cached in order to avoid future queries
898
-     * @var string  $default_where_conditions can be set to 'none', 'this_model_only', 'other_models_only', or 'all'.
899
-     *                                        set this to 'none' to disable all default where conditions. Eg, usually
900
-     *                                        soft-deleted objects are filtered-out if you want to include them, set
901
-     *                                        this query param to 'none'. If you want to ONLY disable THIS model's
902
-     *                                        default where conditions set it to 'other_models_only'. If you only want
903
-     *                                        this model's default where conditions added to the query, use
904
-     *                                        'this_model_only'. If you want to use all default where conditions
905
-     *                                        (default), set to 'all'.
906
-     * @var string  $caps                     controls what capability requirements to apply to the query; ie, should
907
-     *                                        we just NOT apply any capabilities/permissions/restrictions and return
908
-     *                                        everything? Or should we only show the current user items they should be
909
-     *                                        able to view on the frontend, backend, edit, or delete? can be set to
910
-     *                                        'none' (default), 'read_frontend', 'read_backend', 'edit' or 'delete'
911
-     *                                        }
912
-     * @return EE_Base_Class[]  *note that there is NO option to pass the output type. If you want results different
913
-     *                                        from EE_Base_Class[], use _get_all_wpdb_results()and make it public
914
-     *                                        again. Array keys are object IDs (if there is a primary key on the model.
915
-     *                                        if not, numerically indexed) Some full examples: get 10 transactions
916
-     *                                        which have Scottish attendees: EEM_Transaction::instance()->get_all(
917
-     *                                        array( array(
918
-     *                                        'OR'=>array(
919
-     *                                        'Registration.Attendee.ATT_fname'=>array('like','Mc%'),
920
-     *                                        'Registration.Attendee.ATT_fname*other'=>array('like','Mac%')
921
-     *                                        )
922
-     *                                        ),
923
-     *                                        'limit'=>10,
924
-     *                                        'group_by'=>'TXN_ID'
925
-     *                                        ));
926
-     *                                        get all the answers to the question titled "shirt size" for event with id
927
-     *                                        12, ordered by their answer EEM_Answer::instance()->get_all(array( array(
928
-     *                                        'Question.QST_display_text'=>'shirt size',
929
-     *                                        'Registration.Event.EVT_ID'=>12
930
-     *                                        ),
931
-     *                                        'order_by'=>array('ANS_value'=>'ASC')
932
-     *                                        ));
933
-     * @throws EE_Error
934
-     */
935
-    public function get_all($query_params = array())
936
-    {
937
-        if (isset($query_params['limit'])
938
-            && ! isset($query_params['group_by'])
939
-        ) {
940
-            $query_params['group_by'] = array_keys($this->get_combined_primary_key_fields());
941
-        }
942
-        return $this->_create_objects($this->_get_all_wpdb_results($query_params, ARRAY_A, null));
943
-    }
944
-
945
-
946
-
947
-    /**
948
-     * Modifies the query parameters so we only get back model objects
949
-     * that "belong" to the current user
950
-     *
951
-     * @param array $query_params @see EEM_Base::get_all()
952
-     * @return array like EEM_Base::get_all
953
-     */
954
-    public function alter_query_params_to_only_include_mine($query_params = array())
955
-    {
956
-        $wp_user_field_name = $this->wp_user_field_name();
957
-        if ($wp_user_field_name) {
958
-            $query_params[0][$wp_user_field_name] = get_current_user_id();
959
-        }
960
-        return $query_params;
961
-    }
962
-
963
-
964
-
965
-    /**
966
-     * Returns the name of the field's name that points to the WP_User table
967
-     *  on this model (or follows the _model_chain_to_wp_user and uses that model's
968
-     * foreign key to the WP_User table)
969
-     *
970
-     * @return string|boolean string on success, boolean false when there is no
971
-     * foreign key to the WP_User table
972
-     */
973
-    public function wp_user_field_name()
974
-    {
975
-        try {
976
-            if (! empty($this->_model_chain_to_wp_user)) {
977
-                $models_to_follow_to_wp_users = explode('.', $this->_model_chain_to_wp_user);
978
-                $last_model_name = end($models_to_follow_to_wp_users);
979
-                $model_with_fk_to_wp_users = EE_Registry::instance()->load_model($last_model_name);
980
-                $model_chain_to_wp_user = $this->_model_chain_to_wp_user . '.';
981
-            } else {
982
-                $model_with_fk_to_wp_users = $this;
983
-                $model_chain_to_wp_user = '';
984
-            }
985
-            $wp_user_field = $model_with_fk_to_wp_users->get_foreign_key_to('WP_User');
986
-            return $model_chain_to_wp_user . $wp_user_field->get_name();
987
-        } catch (EE_Error $e) {
988
-            return false;
989
-        }
990
-    }
991
-
992
-
993
-
994
-    /**
995
-     * Returns the _model_chain_to_wp_user string, which indicates which related model
996
-     * (or transiently-related model) has a foreign key to the wp_users table;
997
-     * useful for finding if model objects of this type are 'owned' by the current user.
998
-     * This is an empty string when the foreign key is on this model and when it isn't,
999
-     * but is only non-empty when this model's ownership is indicated by a RELATED model
1000
-     * (or transiently-related model)
1001
-     *
1002
-     * @return string
1003
-     */
1004
-    public function model_chain_to_wp_user()
1005
-    {
1006
-        return $this->_model_chain_to_wp_user;
1007
-    }
1008
-
1009
-
1010
-
1011
-    /**
1012
-     * Whether this model is 'owned' by a specific wordpress user (even indirectly,
1013
-     * like how registrations don't have a foreign key to wp_users, but the
1014
-     * events they are for are), or is unrelated to wp users.
1015
-     * generally available
1016
-     *
1017
-     * @return boolean
1018
-     */
1019
-    public function is_owned()
1020
-    {
1021
-        if ($this->model_chain_to_wp_user()) {
1022
-            return true;
1023
-        }
1024
-        try {
1025
-            $this->get_foreign_key_to('WP_User');
1026
-            return true;
1027
-        } catch (EE_Error $e) {
1028
-            return false;
1029
-        }
1030
-    }
1031
-
1032
-
1033
-
1034
-    /**
1035
-     * Used internally to get WPDB results, because other functions, besides get_all, may want to do some queries, but
1036
-     * may want to preserve the WPDB results (eg, update, which first queries to make sure we have all the tables on
1037
-     * the model)
1038
-     *
1039
-     * @param array  $query_params      like EEM_Base::get_all's $query_params
1040
-     * @param string $output            ARRAY_A, OBJECT_K, etc. Just like
1041
-     * @param mixed  $columns_to_select , What columns to select. By default, we select all columns specified by the
1042
-     *                                  fields on the model, and the models we joined to in the query. However, you can
1043
-     *                                  override this and set the select to "*", or a specific column name, like
1044
-     *                                  "ATT_ID", etc. If you would like to use these custom selections in WHERE,
1045
-     *                                  GROUP_BY, or HAVING clauses, you must instead provide an array. Array keys are
1046
-     *                                  the aliases used to refer to this selection, and values are to be
1047
-     *                                  numerically-indexed arrays, where 0 is the selection and 1 is the data type.
1048
-     *                                  Eg, array('count'=>array('COUNT(REG_ID)','%d'))
1049
-     * @return array | stdClass[] like results of $wpdb->get_results($sql,OBJECT), (ie, output type is OBJECT)
1050
-     * @throws EE_Error
1051
-     */
1052
-    protected function _get_all_wpdb_results($query_params = array(), $output = ARRAY_A, $columns_to_select = null)
1053
-    {
1054
-        // remember the custom selections, if any, and type cast as array
1055
-        // (unless $columns_to_select is an object, then just set as an empty array)
1056
-        // Note: (array) 'some string' === array( 'some string' )
1057
-        $this->_custom_selections = ! is_object($columns_to_select) ? (array)$columns_to_select : array();
1058
-        $model_query_info = $this->_create_model_query_info_carrier($query_params);
1059
-        $select_expressions = $columns_to_select !== null
1060
-            ? $this->_construct_select_from_input($columns_to_select)
1061
-            : $this->_construct_default_select_sql($model_query_info);
1062
-        $SQL = "SELECT $select_expressions " . $this->_construct_2nd_half_of_select_query($model_query_info);
1063
-        return $this->_do_wpdb_query('get_results', array($SQL, $output));
1064
-    }
1065
-
1066
-
1067
-
1068
-    /**
1069
-     * Gets an array of rows from the database just like $wpdb->get_results would,
1070
-     * but you can use the $query_params like on EEM_Base::get_all() to more easily
1071
-     * take care of joins, field preparation etc.
1072
-     *
1073
-     * @param array  $query_params      like EEM_Base::get_all's $query_params
1074
-     * @param string $output            ARRAY_A, OBJECT_K, etc. Just like
1075
-     * @param mixed  $columns_to_select , What columns to select. By default, we select all columns specified by the
1076
-     *                                  fields on the model, and the models we joined to in the query. However, you can
1077
-     *                                  override this and set the select to "*", or a specific column name, like
1078
-     *                                  "ATT_ID", etc. If you would like to use these custom selections in WHERE,
1079
-     *                                  GROUP_BY, or HAVING clauses, you must instead provide an array. Array keys are
1080
-     *                                  the aliases used to refer to this selection, and values are to be
1081
-     *                                  numerically-indexed arrays, where 0 is the selection and 1 is the data type.
1082
-     *                                  Eg, array('count'=>array('COUNT(REG_ID)','%d'))
1083
-     * @return array|stdClass[] like results of $wpdb->get_results($sql,OBJECT), (ie, output type is OBJECT)
1084
-     * @throws EE_Error
1085
-     */
1086
-    public function get_all_wpdb_results($query_params = array(), $output = ARRAY_A, $columns_to_select = null)
1087
-    {
1088
-        return $this->_get_all_wpdb_results($query_params, $output, $columns_to_select);
1089
-    }
1090
-
1091
-
1092
-
1093
-    /**
1094
-     * For creating a custom select statement
1095
-     *
1096
-     * @param mixed $columns_to_select either a string to be inserted directly as the select statement,
1097
-     *                                 or an array where keys are aliases, and values are arrays where 0=>the selection
1098
-     *                                 SQL, and 1=>is the datatype
1099
-     * @throws EE_Error
1100
-     * @return string
1101
-     */
1102
-    private function _construct_select_from_input($columns_to_select)
1103
-    {
1104
-        if (is_array($columns_to_select)) {
1105
-            $select_sql_array = array();
1106
-            foreach ($columns_to_select as $alias => $selection_and_datatype) {
1107
-                if (! is_array($selection_and_datatype) || ! isset($selection_and_datatype[1])) {
1108
-                    throw new EE_Error(
1109
-                        sprintf(
1110
-                            __(
1111
-                                "Custom selection %s (alias %s) needs to be an array like array('COUNT(REG_ID)','%%d')",
1112
-                                'event_espresso'
1113
-                            ),
1114
-                            $selection_and_datatype,
1115
-                            $alias
1116
-                        )
1117
-                    );
1118
-                }
1119
-                if (! in_array($selection_and_datatype[1], $this->_valid_wpdb_data_types, true)) {
1120
-                    throw new EE_Error(
1121
-                        sprintf(
1122
-                            esc_html__(
1123
-                                "Datatype %s (for selection '%s' and alias '%s') is not a valid wpdb datatype (eg %%s)",
1124
-                                'event_espresso'
1125
-                            ),
1126
-                            $selection_and_datatype[1],
1127
-                            $selection_and_datatype[0],
1128
-                            $alias,
1129
-                            implode(', ', $this->_valid_wpdb_data_types)
1130
-                        )
1131
-                    );
1132
-                }
1133
-                $select_sql_array[] = "{$selection_and_datatype[0]} AS $alias";
1134
-            }
1135
-            $columns_to_select_string = implode(', ', $select_sql_array);
1136
-        } else {
1137
-            $columns_to_select_string = $columns_to_select;
1138
-        }
1139
-        return $columns_to_select_string;
1140
-    }
1141
-
1142
-
1143
-
1144
-    /**
1145
-     * Convenient wrapper for getting the primary key field's name. Eg, on Registration, this would be 'REG_ID'
1146
-     *
1147
-     * @return string
1148
-     * @throws EE_Error
1149
-     */
1150
-    public function primary_key_name()
1151
-    {
1152
-        return $this->get_primary_key_field()->get_name();
1153
-    }
1154
-
1155
-
1156
-
1157
-    /**
1158
-     * Gets a single item for this model from the DB, given only its ID (or null if none is found).
1159
-     * If there is no primary key on this model, $id is treated as primary key string
1160
-     *
1161
-     * @param mixed $id int or string, depending on the type of the model's primary key
1162
-     * @return EE_Base_Class
1163
-     */
1164
-    public function get_one_by_ID($id)
1165
-    {
1166
-        if ($this->get_from_entity_map($id)) {
1167
-            return $this->get_from_entity_map($id);
1168
-        }
1169
-        return $this->get_one(
1170
-            $this->alter_query_params_to_restrict_by_ID(
1171
-                $id,
1172
-                array('default_where_conditions' => EEM_Base::default_where_conditions_minimum_all)
1173
-            )
1174
-        );
1175
-    }
1176
-
1177
-
1178
-
1179
-    /**
1180
-     * Alters query parameters to only get items with this ID are returned.
1181
-     * Takes into account that the ID might be a string produced by EEM_Base::get_index_primary_key_string(),
1182
-     * or could just be a simple primary key ID
1183
-     *
1184
-     * @param int   $id
1185
-     * @param array $query_params
1186
-     * @return array of normal query params, @see EEM_Base::get_all
1187
-     * @throws EE_Error
1188
-     */
1189
-    public function alter_query_params_to_restrict_by_ID($id, $query_params = array())
1190
-    {
1191
-        if (! isset($query_params[0])) {
1192
-            $query_params[0] = array();
1193
-        }
1194
-        $conditions_from_id = $this->parse_index_primary_key_string($id);
1195
-        if ($conditions_from_id === null) {
1196
-            $query_params[0][$this->primary_key_name()] = $id;
1197
-        } else {
1198
-            //no primary key, so the $id must be from the get_index_primary_key_string()
1199
-            $query_params[0] = array_replace_recursive($query_params[0], $this->parse_index_primary_key_string($id));
1200
-        }
1201
-        return $query_params;
1202
-    }
1203
-
1204
-
1205
-
1206
-    /**
1207
-     * Gets a single item for this model from the DB, given the $query_params. Only returns a single class, not an
1208
-     * array. If no item is found, null is returned.
1209
-     *
1210
-     * @param array $query_params like EEM_Base's $query_params variable.
1211
-     * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1212
-     * @throws EE_Error
1213
-     */
1214
-    public function get_one($query_params = array())
1215
-    {
1216
-        if (! is_array($query_params)) {
1217
-            EE_Error::doing_it_wrong('EEM_Base::get_one',
1218
-                sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
1219
-                    gettype($query_params)), '4.6.0');
1220
-            $query_params = array();
1221
-        }
1222
-        $query_params['limit'] = 1;
1223
-        $items = $this->get_all($query_params);
1224
-        if (empty($items)) {
1225
-            return null;
1226
-        }
1227
-        return array_shift($items);
1228
-    }
1229
-
1230
-
1231
-
1232
-    /**
1233
-     * Returns the next x number of items in sequence from the given value as
1234
-     * found in the database matching the given query conditions.
1235
-     *
1236
-     * @param mixed $current_field_value    Value used for the reference point.
1237
-     * @param null  $field_to_order_by      What field is used for the
1238
-     *                                      reference point.
1239
-     * @param int   $limit                  How many to return.
1240
-     * @param array $query_params           Extra conditions on the query.
1241
-     * @param null  $columns_to_select      If left null, then an array of
1242
-     *                                      EE_Base_Class objects is returned,
1243
-     *                                      otherwise you can indicate just the
1244
-     *                                      columns you want returned.
1245
-     * @return EE_Base_Class[]|array
1246
-     * @throws EE_Error
1247
-     */
1248
-    public function next_x(
1249
-        $current_field_value,
1250
-        $field_to_order_by = null,
1251
-        $limit = 1,
1252
-        $query_params = array(),
1253
-        $columns_to_select = null
1254
-    ) {
1255
-        return $this->_get_consecutive(
1256
-            $current_field_value,
1257
-            '>',
1258
-            $field_to_order_by,
1259
-            $limit,
1260
-            $query_params,
1261
-            $columns_to_select
1262
-        );
1263
-    }
1264
-
1265
-
1266
-
1267
-    /**
1268
-     * Returns the previous x number of items in sequence from the given value
1269
-     * as found in the database matching the given query conditions.
1270
-     *
1271
-     * @param mixed $current_field_value    Value used for the reference point.
1272
-     * @param null  $field_to_order_by      What field is used for the
1273
-     *                                      reference point.
1274
-     * @param int   $limit                  How many to return.
1275
-     * @param array $query_params           Extra conditions on the query.
1276
-     * @param null  $columns_to_select      If left null, then an array of
1277
-     *                                      EE_Base_Class objects is returned,
1278
-     *                                      otherwise you can indicate just the
1279
-     *                                      columns you want returned.
1280
-     * @return EE_Base_Class[]|array
1281
-     * @throws EE_Error
1282
-     */
1283
-    public function previous_x(
1284
-        $current_field_value,
1285
-        $field_to_order_by = null,
1286
-        $limit = 1,
1287
-        $query_params = array(),
1288
-        $columns_to_select = null
1289
-    ) {
1290
-        return $this->_get_consecutive(
1291
-            $current_field_value,
1292
-            '<',
1293
-            $field_to_order_by,
1294
-            $limit,
1295
-            $query_params,
1296
-            $columns_to_select
1297
-        );
1298
-    }
1299
-
1300
-
1301
-
1302
-    /**
1303
-     * Returns the next item in sequence from the given value as found in the
1304
-     * database matching the given query conditions.
1305
-     *
1306
-     * @param mixed $current_field_value    Value used for the reference point.
1307
-     * @param null  $field_to_order_by      What field is used for the
1308
-     *                                      reference point.
1309
-     * @param array $query_params           Extra conditions on the query.
1310
-     * @param null  $columns_to_select      If left null, then an EE_Base_Class
1311
-     *                                      object is returned, otherwise you
1312
-     *                                      can indicate just the columns you
1313
-     *                                      want and a single array indexed by
1314
-     *                                      the columns will be returned.
1315
-     * @return EE_Base_Class|null|array()
1316
-     * @throws EE_Error
1317
-     */
1318
-    public function next(
1319
-        $current_field_value,
1320
-        $field_to_order_by = null,
1321
-        $query_params = array(),
1322
-        $columns_to_select = null
1323
-    ) {
1324
-        $results = $this->_get_consecutive(
1325
-            $current_field_value,
1326
-            '>',
1327
-            $field_to_order_by,
1328
-            1,
1329
-            $query_params,
1330
-            $columns_to_select
1331
-        );
1332
-        return empty($results) ? null : reset($results);
1333
-    }
1334
-
1335
-
1336
-
1337
-    /**
1338
-     * Returns the previous item in sequence from the given value as found in
1339
-     * the database matching the given query conditions.
1340
-     *
1341
-     * @param mixed $current_field_value    Value used for the reference point.
1342
-     * @param null  $field_to_order_by      What field is used for the
1343
-     *                                      reference point.
1344
-     * @param array $query_params           Extra conditions on the query.
1345
-     * @param null  $columns_to_select      If left null, then an EE_Base_Class
1346
-     *                                      object is returned, otherwise you
1347
-     *                                      can indicate just the columns you
1348
-     *                                      want and a single array indexed by
1349
-     *                                      the columns will be returned.
1350
-     * @return EE_Base_Class|null|array()
1351
-     * @throws EE_Error
1352
-     */
1353
-    public function previous(
1354
-        $current_field_value,
1355
-        $field_to_order_by = null,
1356
-        $query_params = array(),
1357
-        $columns_to_select = null
1358
-    ) {
1359
-        $results = $this->_get_consecutive(
1360
-            $current_field_value,
1361
-            '<',
1362
-            $field_to_order_by,
1363
-            1,
1364
-            $query_params,
1365
-            $columns_to_select
1366
-        );
1367
-        return empty($results) ? null : reset($results);
1368
-    }
1369
-
1370
-
1371
-
1372
-    /**
1373
-     * Returns the a consecutive number of items in sequence from the given
1374
-     * value as found in the database matching the given query conditions.
1375
-     *
1376
-     * @param mixed  $current_field_value   Value used for the reference point.
1377
-     * @param string $operand               What operand is used for the sequence.
1378
-     * @param string $field_to_order_by     What field is used for the reference point.
1379
-     * @param int    $limit                 How many to return.
1380
-     * @param array  $query_params          Extra conditions on the query.
1381
-     * @param null   $columns_to_select     If left null, then an array of EE_Base_Class objects is returned,
1382
-     *                                      otherwise you can indicate just the columns you want returned.
1383
-     * @return EE_Base_Class[]|array
1384
-     * @throws EE_Error
1385
-     */
1386
-    protected function _get_consecutive(
1387
-        $current_field_value,
1388
-        $operand = '>',
1389
-        $field_to_order_by = null,
1390
-        $limit = 1,
1391
-        $query_params = array(),
1392
-        $columns_to_select = null
1393
-    ) {
1394
-        //if $field_to_order_by is empty then let's assume we're ordering by the primary key.
1395
-        if (empty($field_to_order_by)) {
1396
-            if ($this->has_primary_key_field()) {
1397
-                $field_to_order_by = $this->get_primary_key_field()->get_name();
1398
-            } else {
1399
-                if (WP_DEBUG) {
1400
-                    throw new EE_Error(__('EEM_Base::_get_consecutive() has been called with no $field_to_order_by argument and there is no primary key on the field.  Please provide the field you would like to use as the base for retrieving the next item(s).',
1401
-                        'event_espresso'));
1402
-                }
1403
-                EE_Error::add_error(__('There was an error with the query.', 'event_espresso'));
1404
-                return array();
1405
-            }
1406
-        }
1407
-        if (! is_array($query_params)) {
1408
-            EE_Error::doing_it_wrong('EEM_Base::_get_consecutive',
1409
-                sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
1410
-                    gettype($query_params)), '4.6.0');
1411
-            $query_params = array();
1412
-        }
1413
-        //let's add the where query param for consecutive look up.
1414
-        $query_params[0][$field_to_order_by] = array($operand, $current_field_value);
1415
-        $query_params['limit'] = $limit;
1416
-        //set direction
1417
-        $incoming_orderby = isset($query_params['order_by']) ? (array)$query_params['order_by'] : array();
1418
-        $query_params['order_by'] = $operand === '>'
1419
-            ? array($field_to_order_by => 'ASC') + $incoming_orderby
1420
-            : array($field_to_order_by => 'DESC') + $incoming_orderby;
1421
-        //if $columns_to_select is empty then that means we're returning EE_Base_Class objects
1422
-        if (empty($columns_to_select)) {
1423
-            return $this->get_all($query_params);
1424
-        }
1425
-        //getting just the fields
1426
-        return $this->_get_all_wpdb_results($query_params, ARRAY_A, $columns_to_select);
1427
-    }
1428
-
1429
-
1430
-
1431
-    /**
1432
-     * This sets the _timezone property after model object has been instantiated.
1433
-     *
1434
-     * @param null | string $timezone valid PHP DateTimeZone timezone string
1435
-     */
1436
-    public function set_timezone($timezone)
1437
-    {
1438
-        if ($timezone !== null) {
1439
-            $this->_timezone = $timezone;
1440
-        }
1441
-        //note we need to loop through relations and set the timezone on those objects as well.
1442
-        foreach ($this->_model_relations as $relation) {
1443
-            $relation->set_timezone($timezone);
1444
-        }
1445
-        //and finally we do the same for any datetime fields
1446
-        foreach ($this->_fields as $field) {
1447
-            if ($field instanceof EE_Datetime_Field) {
1448
-                $field->set_timezone($timezone);
1449
-            }
1450
-        }
1451
-    }
1452
-
1453
-
1454
-
1455
-    /**
1456
-     * This just returns whatever is set for the current timezone.
1457
-     *
1458
-     * @access public
1459
-     * @return string
1460
-     */
1461
-    public function get_timezone()
1462
-    {
1463
-        //first validate if timezone is set.  If not, then let's set it be whatever is set on the model fields.
1464
-        if (empty($this->_timezone)) {
1465
-            foreach ($this->_fields as $field) {
1466
-                if ($field instanceof EE_Datetime_Field) {
1467
-                    $this->set_timezone($field->get_timezone());
1468
-                    break;
1469
-                }
1470
-            }
1471
-        }
1472
-        //if timezone STILL empty then return the default timezone for the site.
1473
-        if (empty($this->_timezone)) {
1474
-            $this->set_timezone(EEH_DTT_Helper::get_timezone());
1475
-        }
1476
-        return $this->_timezone;
1477
-    }
1478
-
1479
-
1480
-
1481
-    /**
1482
-     * This returns the date formats set for the given field name and also ensures that
1483
-     * $this->_timezone property is set correctly.
1484
-     *
1485
-     * @since 4.6.x
1486
-     * @param string $field_name The name of the field the formats are being retrieved for.
1487
-     * @param bool   $pretty     Whether to return the pretty formats (true) or not (false).
1488
-     * @throws EE_Error   If the given field_name is not of the EE_Datetime_Field type.
1489
-     * @return array formats in an array with the date format first, and the time format last.
1490
-     */
1491
-    public function get_formats_for($field_name, $pretty = false)
1492
-    {
1493
-        $field_settings = $this->field_settings_for($field_name);
1494
-        //if not a valid EE_Datetime_Field then throw error
1495
-        if (! $field_settings instanceof EE_Datetime_Field) {
1496
-            throw new EE_Error(sprintf(__('The field sent into EEM_Base::get_formats_for (%s) is not registered as a EE_Datetime_Field. Please check the spelling and make sure you are submitting the right field name to retrieve date_formats for.',
1497
-                'event_espresso'), $field_name));
1498
-        }
1499
-        //while we are here, let's make sure the timezone internally in EEM_Base matches what is stored on
1500
-        //the field.
1501
-        $this->_timezone = $field_settings->get_timezone();
1502
-        return array($field_settings->get_date_format($pretty), $field_settings->get_time_format($pretty));
1503
-    }
1504
-
1505
-
1506
-
1507
-    /**
1508
-     * This returns the current time in a format setup for a query on this model.
1509
-     * Usage of this method makes it easier to setup queries against EE_Datetime_Field columns because
1510
-     * it will return:
1511
-     *  - a formatted string in the timezone and format currently set on the EE_Datetime_Field for the given field for
1512
-     *  NOW
1513
-     *  - or a unix timestamp (equivalent to time())
1514
-     * Note: When requesting a formatted string, if the date or time format doesn't include seconds, for example,
1515
-     * the time returned, because it uses that format, will also NOT include seconds. For this reason, if you want
1516
-     * the time returned to be the current time down to the exact second, set $timestamp to true.
1517
-     * @since 4.6.x
1518
-     * @param string $field_name       The field the current time is needed for.
1519
-     * @param bool   $timestamp        True means to return a unix timestamp. Otherwise a
1520
-     *                                 formatted string matching the set format for the field in the set timezone will
1521
-     *                                 be returned.
1522
-     * @param string $what             Whether to return the string in just the time format, the date format, or both.
1523
-     * @throws EE_Error    If the given field_name is not of the EE_Datetime_Field type.
1524
-     * @return int|string  If the given field_name is not of the EE_Datetime_Field type, then an EE_Error
1525
-     *                                 exception is triggered.
1526
-     */
1527
-    public function current_time_for_query($field_name, $timestamp = false, $what = 'both')
1528
-    {
1529
-        $formats = $this->get_formats_for($field_name);
1530
-        $DateTime = new DateTime("now", new DateTimeZone($this->_timezone));
1531
-        if ($timestamp) {
1532
-            return $DateTime->format('U');
1533
-        }
1534
-        //not returning timestamp, so return formatted string in timezone.
1535
-        switch ($what) {
1536
-            case 'time' :
1537
-                return $DateTime->format($formats[1]);
1538
-                break;
1539
-            case 'date' :
1540
-                return $DateTime->format($formats[0]);
1541
-                break;
1542
-            default :
1543
-                return $DateTime->format(implode(' ', $formats));
1544
-                break;
1545
-        }
1546
-    }
1547
-
1548
-
1549
-
1550
-    /**
1551
-     * This receives a time string for a given field and ensures that it is setup to match what the internal settings
1552
-     * for the model are.  Returns a DateTime object.
1553
-     * Note: a gotcha for when you send in unix timestamp.  Remember a unix timestamp is already timezone agnostic,
1554
-     * (functionally the equivalent of UTC+0).  So when you send it in, whatever timezone string you include is
1555
-     * ignored.
1556
-     *
1557
-     * @param string $field_name      The field being setup.
1558
-     * @param string $timestring      The date time string being used.
1559
-     * @param string $incoming_format The format for the time string.
1560
-     * @param string $timezone        By default, it is assumed the incoming time string is in timezone for
1561
-     *                                the blog.  If this is not the case, then it can be specified here.  If incoming
1562
-     *                                format is
1563
-     *                                'U', this is ignored.
1564
-     * @return DateTime
1565
-     * @throws EE_Error
1566
-     */
1567
-    public function convert_datetime_for_query($field_name, $timestring, $incoming_format, $timezone = '')
1568
-    {
1569
-        //just using this to ensure the timezone is set correctly internally
1570
-        $this->get_formats_for($field_name);
1571
-        //load EEH_DTT_Helper
1572
-        $set_timezone = empty($timezone) ? EEH_DTT_Helper::get_timezone() : $timezone;
1573
-        $incomingDateTime = date_create_from_format($incoming_format, $timestring, new DateTimeZone($set_timezone));
1574
-        return \EventEspresso\core\domain\entities\DbSafeDateTime::createFromDateTime( $incomingDateTime->setTimezone(new DateTimeZone($this->_timezone)) );
1575
-    }
1576
-
1577
-
1578
-
1579
-    /**
1580
-     * Gets all the tables comprising this model. Array keys are the table aliases, and values are EE_Table objects
1581
-     *
1582
-     * @return EE_Table_Base[]
1583
-     */
1584
-    public function get_tables()
1585
-    {
1586
-        return $this->_tables;
1587
-    }
1588
-
1589
-
1590
-
1591
-    /**
1592
-     * Updates all the database entries (in each table for this model) according to $fields_n_values and optionally
1593
-     * also updates all the model objects, where the criteria expressed in $query_params are met..
1594
-     * Also note: if this model has multiple tables, this update verifies all the secondary tables have an entry for
1595
-     * each row (in the primary table) we're trying to update; if not, it inserts an entry in the secondary table. Eg:
1596
-     * if our model has 2 tables: wp_posts (primary), and wp_esp_event (secondary). Let's say we are trying to update a
1597
-     * model object with EVT_ID = 1
1598
-     * (which means where wp_posts has ID = 1, because wp_posts.ID is the primary key's column), which exists, but
1599
-     * there is no entry in wp_esp_event for this entry in wp_posts. So, this update script will insert a row into
1600
-     * wp_esp_event, using any available parameters from $fields_n_values (eg, if "EVT_limit" => 40 is in
1601
-     * $fields_n_values, the new entry in wp_esp_event will set EVT_limit = 40, and use default for other columns which
1602
-     * are not specified)
1603
-     *
1604
-     * @param array   $fields_n_values         keys are model fields (exactly like keys in EEM_Base::_fields, NOT db
1605
-     *                                         columns!), values are strings, ints, floats, and maybe arrays if they
1606
-     *                                         are to be serialized. Basically, the values are what you'd expect to be
1607
-     *                                         values on the model, NOT necessarily what's in the DB. For example, if
1608
-     *                                         we wanted to update only the TXN_details on any Transactions where its
1609
-     *                                         ID=34, we'd use this method as follows:
1610
-     *                                         EEM_Transaction::instance()->update(
1611
-     *                                         array('TXN_details'=>array('detail1'=>'monkey','detail2'=>'banana'),
1612
-     *                                         array(array('TXN_ID'=>34)));
1613
-     * @param array   $query_params            very much like EEM_Base::get_all's $query_params
1614
-     *                                         in client code into what's expected to be stored on each field. Eg,
1615
-     *                                         consider updating Question's QST_admin_label field is of type
1616
-     *                                         Simple_HTML. If you use this function to update that field to $new_value
1617
-     *                                         = (note replace 8's with appropriate opening and closing tags in the
1618
-     *                                         following example)"8script8alert('I hack all');8/script88b8boom
1619
-     *                                         baby8/b8", then if you set $values_already_prepared_by_model_object to
1620
-     *                                         TRUE, it is assumed that you've already called
1621
-     *                                         EE_Simple_HTML_Field->prepare_for_set($new_value), which removes the
1622
-     *                                         malicious javascript. However, if
1623
-     *                                         $values_already_prepared_by_model_object is left as FALSE, then
1624
-     *                                         EE_Simple_HTML_Field->prepare_for_set($new_value) will be called on it,
1625
-     *                                         and every other field, before insertion. We provide this parameter
1626
-     *                                         because model objects perform their prepare_for_set function on all
1627
-     *                                         their values, and so don't need to be called again (and in many cases,
1628
-     *                                         shouldn't be called again. Eg: if we escape HTML characters in the
1629
-     *                                         prepare_for_set method...)
1630
-     * @param boolean $keep_model_objs_in_sync if TRUE, makes sure we ALSO update model objects
1631
-     *                                         in this model's entity map according to $fields_n_values that match
1632
-     *                                         $query_params. This obviously has some overhead, so you can disable it
1633
-     *                                         by setting this to FALSE, but be aware that model objects being used
1634
-     *                                         could get out-of-sync with the database
1635
-     * @return int how many rows got updated or FALSE if something went wrong with the query (wp returns FALSE or num
1636
-     *                                         rows affected which *could* include 0 which DOES NOT mean the query was
1637
-     *                                         bad)
1638
-     * @throws EE_Error
1639
-     */
1640
-    public function update($fields_n_values, $query_params, $keep_model_objs_in_sync = true)
1641
-    {
1642
-        if (! is_array($query_params)) {
1643
-            EE_Error::doing_it_wrong('EEM_Base::update',
1644
-                sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
1645
-                    gettype($query_params)), '4.6.0');
1646
-            $query_params = array();
1647
-        }
1648
-        /**
1649
-         * Action called before a model update call has been made.
1650
-         *
1651
-         * @param EEM_Base $model
1652
-         * @param array    $fields_n_values the updated fields and their new values
1653
-         * @param array    $query_params    @see EEM_Base::get_all()
1654
-         */
1655
-        do_action('AHEE__EEM_Base__update__begin', $this, $fields_n_values, $query_params);
1656
-        /**
1657
-         * Filters the fields about to be updated given the query parameters. You can provide the
1658
-         * $query_params to $this->get_all() to find exactly which records will be updated
1659
-         *
1660
-         * @param array    $fields_n_values fields and their new values
1661
-         * @param EEM_Base $model           the model being queried
1662
-         * @param array    $query_params    see EEM_Base::get_all()
1663
-         */
1664
-        $fields_n_values = (array)apply_filters('FHEE__EEM_Base__update__fields_n_values', $fields_n_values, $this,
1665
-            $query_params);
1666
-        //need to verify that, for any entry we want to update, there are entries in each secondary table.
1667
-        //to do that, for each table, verify that it's PK isn't null.
1668
-        $tables = $this->get_tables();
1669
-        //and if the other tables don't have a row for each table-to-be-updated, we'll insert one with whatever values available in the current update query
1670
-        //NOTE: we should make this code more efficient by NOT querying twice
1671
-        //before the real update, but that needs to first go through ALPHA testing
1672
-        //as it's dangerous. says Mike August 8 2014
1673
-        //we want to make sure the default_where strategy is ignored
1674
-        $this->_ignore_where_strategy = true;
1675
-        $wpdb_select_results = $this->_get_all_wpdb_results($query_params);
1676
-        foreach ($wpdb_select_results as $wpdb_result) {
1677
-            // type cast stdClass as array
1678
-            $wpdb_result = (array)$wpdb_result;
1679
-            //get the model object's PK, as we'll want this if we need to insert a row into secondary tables
1680
-            if ($this->has_primary_key_field()) {
1681
-                $main_table_pk_value = $wpdb_result[$this->get_primary_key_field()->get_qualified_column()];
1682
-            } else {
1683
-                //if there's no primary key, we basically can't support having a 2nd table on the model (we could but it would be lots of work)
1684
-                $main_table_pk_value = null;
1685
-            }
1686
-            //if there are more than 1 tables, we'll want to verify that each table for this model has an entry in the other tables
1687
-            //and if the other tables don't have a row for each table-to-be-updated, we'll insert one with whatever values available in the current update query
1688
-            if (count($tables) > 1) {
1689
-                //foreach matching row in the DB, ensure that each table's PK isn't null. If so, there must not be an entry
1690
-                //in that table, and so we'll want to insert one
1691
-                foreach ($tables as $table_obj) {
1692
-                    $this_table_pk_column = $table_obj->get_fully_qualified_pk_column();
1693
-                    //if there is no private key for this table on the results, it means there's no entry
1694
-                    //in this table, right? so insert a row in the current table, using any fields available
1695
-                    if (! (array_key_exists($this_table_pk_column, $wpdb_result)
1696
-                           && $wpdb_result[$this_table_pk_column])
1697
-                    ) {
1698
-                        $success = $this->_insert_into_specific_table($table_obj, $fields_n_values,
1699
-                            $main_table_pk_value);
1700
-                        //if we died here, report the error
1701
-                        if (! $success) {
1702
-                            return false;
1703
-                        }
1704
-                    }
1705
-                }
1706
-            }
1707
-            //				//and now check that if we have cached any models by that ID on the model, that
1708
-            //				//they also get updated properly
1709
-            //				$model_object = $this->get_from_entity_map( $main_table_pk_value );
1710
-            //				if( $model_object ){
1711
-            //					foreach( $fields_n_values as $field => $value ){
1712
-            //						$model_object->set($field, $value);
1713
-            //let's make sure default_where strategy is followed now
1714
-            $this->_ignore_where_strategy = false;
1715
-        }
1716
-        //if we want to keep model objects in sync, AND
1717
-        //if this wasn't called from a model object (to update itself)
1718
-        //then we want to make sure we keep all the existing
1719
-        //model objects in sync with the db
1720
-        if ($keep_model_objs_in_sync && ! $this->_values_already_prepared_by_model_object) {
1721
-            if ($this->has_primary_key_field()) {
1722
-                $model_objs_affected_ids = $this->get_col($query_params);
1723
-            } else {
1724
-                //we need to select a bunch of columns and then combine them into the the "index primary key string"s
1725
-                $models_affected_key_columns = $this->_get_all_wpdb_results($query_params, ARRAY_A);
1726
-                $model_objs_affected_ids = array();
1727
-                foreach ($models_affected_key_columns as $row) {
1728
-                    $combined_index_key = $this->get_index_primary_key_string($row);
1729
-                    $model_objs_affected_ids[$combined_index_key] = $combined_index_key;
1730
-                }
1731
-            }
1732
-            if (! $model_objs_affected_ids) {
1733
-                //wait wait wait- if nothing was affected let's stop here
1734
-                return 0;
1735
-            }
1736
-            foreach ($model_objs_affected_ids as $id) {
1737
-                $model_obj_in_entity_map = $this->get_from_entity_map($id);
1738
-                if ($model_obj_in_entity_map) {
1739
-                    foreach ($fields_n_values as $field => $new_value) {
1740
-                        $model_obj_in_entity_map->set($field, $new_value);
1741
-                    }
1742
-                }
1743
-            }
1744
-            //if there is a primary key on this model, we can now do a slight optimization
1745
-            if ($this->has_primary_key_field()) {
1746
-                //we already know what we want to update. So let's make the query simpler so it's a little more efficient
1747
-                $query_params = array(
1748
-                    array($this->primary_key_name() => array('IN', $model_objs_affected_ids)),
1749
-                    'limit'                    => count($model_objs_affected_ids),
1750
-                    'default_where_conditions' => EEM_Base::default_where_conditions_none,
1751
-                );
1752
-            }
1753
-        }
1754
-        $model_query_info = $this->_create_model_query_info_carrier($query_params);
1755
-        $SQL = "UPDATE "
1756
-               . $model_query_info->get_full_join_sql()
1757
-               . " SET "
1758
-               . $this->_construct_update_sql($fields_n_values)
1759
-               . $model_query_info->get_where_sql();//note: doesn't use _construct_2nd_half_of_select_query() because doesn't accept LIMIT, ORDER BY, etc.
1760
-        $rows_affected = $this->_do_wpdb_query('query', array($SQL));
1761
-        /**
1762
-         * Action called after a model update call has been made.
1763
-         *
1764
-         * @param EEM_Base $model
1765
-         * @param array    $fields_n_values the updated fields and their new values
1766
-         * @param array    $query_params    @see EEM_Base::get_all()
1767
-         * @param int      $rows_affected
1768
-         */
1769
-        do_action('AHEE__EEM_Base__update__end', $this, $fields_n_values, $query_params, $rows_affected);
1770
-        return $rows_affected;//how many supposedly got updated
1771
-    }
1772
-
1773
-
1774
-
1775
-    /**
1776
-     * Analogous to $wpdb->get_col, returns a 1-dimensional array where teh values
1777
-     * are teh values of the field specified (or by default the primary key field)
1778
-     * that matched the query params. Note that you should pass the name of the
1779
-     * model FIELD, not the database table's column name.
1780
-     *
1781
-     * @param array  $query_params @see EEM_Base::get_all()
1782
-     * @param string $field_to_select
1783
-     * @return array just like $wpdb->get_col()
1784
-     * @throws EE_Error
1785
-     */
1786
-    public function get_col($query_params = array(), $field_to_select = null)
1787
-    {
1788
-        if ($field_to_select) {
1789
-            $field = $this->field_settings_for($field_to_select);
1790
-        } elseif ($this->has_primary_key_field()) {
1791
-            $field = $this->get_primary_key_field();
1792
-        } else {
1793
-            //no primary key, just grab the first column
1794
-            $field = reset($this->field_settings());
1795
-        }
1796
-        $model_query_info = $this->_create_model_query_info_carrier($query_params);
1797
-        $select_expressions = $field->get_qualified_column();
1798
-        $SQL = "SELECT $select_expressions " . $this->_construct_2nd_half_of_select_query($model_query_info);
1799
-        return $this->_do_wpdb_query('get_col', array($SQL));
1800
-    }
1801
-
1802
-
1803
-
1804
-    /**
1805
-     * Returns a single column value for a single row from the database
1806
-     *
1807
-     * @param array  $query_params    @see EEM_Base::get_all()
1808
-     * @param string $field_to_select @see EEM_Base::get_col()
1809
-     * @return string
1810
-     * @throws EE_Error
1811
-     */
1812
-    public function get_var($query_params = array(), $field_to_select = null)
1813
-    {
1814
-        $query_params['limit'] = 1;
1815
-        $col = $this->get_col($query_params, $field_to_select);
1816
-        if (! empty($col)) {
1817
-            return reset($col);
1818
-        }
1819
-        return null;
1820
-    }
1821
-
1822
-
1823
-
1824
-    /**
1825
-     * Makes the SQL for after "UPDATE table_X inner join table_Y..." and before "...WHERE". Eg "Question.name='party
1826
-     * time?', Question.desc='what do you think?',..." Values are filtered through wpdb->prepare to avoid against SQL
1827
-     * injection, but currently no further filtering is done
1828
-     *
1829
-     * @global      $wpdb
1830
-     * @param array $fields_n_values array keys are field names on this model, and values are what those fields should
1831
-     *                               be updated to in the DB
1832
-     * @return string of SQL
1833
-     * @throws EE_Error
1834
-     */
1835
-    public function _construct_update_sql($fields_n_values)
1836
-    {
1837
-        /** @type WPDB $wpdb */
1838
-        global $wpdb;
1839
-        $cols_n_values = array();
1840
-        foreach ($fields_n_values as $field_name => $value) {
1841
-            $field_obj = $this->field_settings_for($field_name);
1842
-            //if the value is NULL, we want to assign the value to that.
1843
-            //wpdb->prepare doesn't really handle that properly
1844
-            $prepared_value = $this->_prepare_value_or_use_default($field_obj, $fields_n_values);
1845
-            $value_sql = $prepared_value === null ? 'NULL'
1846
-                : $wpdb->prepare($field_obj->get_wpdb_data_type(), $prepared_value);
1847
-            $cols_n_values[] = $field_obj->get_qualified_column() . "=" . $value_sql;
1848
-        }
1849
-        return implode(",", $cols_n_values);
1850
-    }
1851
-
1852
-
1853
-
1854
-    /**
1855
-     * Deletes a single row from the DB given the model object's primary key value. (eg, EE_Attendee->ID()'s value).
1856
-     * Performs a HARD delete, meaning the database row should always be removed,
1857
-     * not just have a flag field on it switched
1858
-     * Wrapper for EEM_Base::delete_permanently()
1859
-     *
1860
-     * @param mixed $id
1861
-     * @param boolean $allow_blocking
1862
-     * @return int the number of rows deleted
1863
-     * @throws EE_Error
1864
-     */
1865
-    public function delete_permanently_by_ID($id, $allow_blocking = true)
1866
-    {
1867
-        return $this->delete_permanently(
1868
-            array(
1869
-                array($this->get_primary_key_field()->get_name() => $id),
1870
-                'limit' => 1,
1871
-            ),
1872
-            $allow_blocking
1873
-        );
1874
-    }
1875
-
1876
-
1877
-
1878
-    /**
1879
-     * Deletes a single row from the DB given the model object's primary key value. (eg, EE_Attendee->ID()'s value).
1880
-     * Wrapper for EEM_Base::delete()
1881
-     *
1882
-     * @param mixed $id
1883
-     * @param boolean $allow_blocking
1884
-     * @return int the number of rows deleted
1885
-     * @throws EE_Error
1886
-     */
1887
-    public function delete_by_ID($id, $allow_blocking = true)
1888
-    {
1889
-        return $this->delete(
1890
-            array(
1891
-                array($this->get_primary_key_field()->get_name() => $id),
1892
-                'limit' => 1,
1893
-            ),
1894
-            $allow_blocking
1895
-        );
1896
-    }
1897
-
1898
-
1899
-
1900
-    /**
1901
-     * Identical to delete_permanently, but does a "soft" delete if possible,
1902
-     * meaning if the model has a field that indicates its been "trashed" or
1903
-     * "soft deleted", we will just set that instead of actually deleting the rows.
1904
-     *
1905
-     * @see EEM_Base::delete_permanently
1906
-     * @param array   $query_params
1907
-     * @param boolean $allow_blocking
1908
-     * @return int how many rows got deleted
1909
-     * @throws EE_Error
1910
-     */
1911
-    public function delete($query_params, $allow_blocking = true)
1912
-    {
1913
-        return $this->delete_permanently($query_params, $allow_blocking);
1914
-    }
1915
-
1916
-
1917
-
1918
-    /**
1919
-     * Deletes the model objects that meet the query params. Note: this method is overridden
1920
-     * in EEM_Soft_Delete_Base so that soft-deleted model objects are instead only flagged
1921
-     * as archived, not actually deleted
1922
-     *
1923
-     * @param array   $query_params   very much like EEM_Base::get_all's $query_params
1924
-     * @param boolean $allow_blocking if TRUE, matched objects will only be deleted if there is no related model info
1925
-     *                                that blocks it (ie, there' sno other data that depends on this data); if false,
1926
-     *                                deletes regardless of other objects which may depend on it. Its generally
1927
-     *                                advisable to always leave this as TRUE, otherwise you could easily corrupt your
1928
-     *                                DB
1929
-     * @return int how many rows got deleted
1930
-     * @throws EE_Error
1931
-     */
1932
-    public function delete_permanently($query_params, $allow_blocking = true)
1933
-    {
1934
-        /**
1935
-         * Action called just before performing a real deletion query. You can use the
1936
-         * model and its $query_params to find exactly which items will be deleted
1937
-         *
1938
-         * @param EEM_Base $model
1939
-         * @param array    $query_params   @see EEM_Base::get_all()
1940
-         * @param boolean  $allow_blocking whether or not to allow related model objects
1941
-         *                                 to block (prevent) this deletion
1942
-         */
1943
-        do_action('AHEE__EEM_Base__delete__begin', $this, $query_params, $allow_blocking);
1944
-        //some MySQL databases may be running safe mode, which may restrict
1945
-        //deletion if there is no KEY column used in the WHERE statement of a deletion.
1946
-        //to get around this, we first do a SELECT, get all the IDs, and then run another query
1947
-        //to delete them
1948
-        $items_for_deletion = $this->_get_all_wpdb_results($query_params);
1949
-        $columns_and_ids_for_deleting = $this->_get_ids_for_delete($items_for_deletion, $allow_blocking);
1950
-        $deletion_where_query_part = $this->_build_query_part_for_deleting_from_columns_and_values(
1951
-            $columns_and_ids_for_deleting
1952
-        );
1953
-        /**
1954
-         * Allows client code to act on the items being deleted before the query is actually executed.
1955
-         *
1956
-         * @param EEM_Base $this  The model instance being acted on.
1957
-         * @param array    $query_params  The incoming array of query parameters influencing what gets deleted.
1958
-         * @param bool     $allow_blocking @see param description in method phpdoc block.
1959
-         * @param array $columns_and_ids_for_deleting       An array indicating what entities will get removed as
1960
-         *                                                  derived from the incoming query parameters.
1961
-         *                                                  @see details on the structure of this array in the phpdocs
1962
-         *                                                  for the `_get_ids_for_delete_method`
1963
-         *
1964
-         */
1965
-        do_action('AHEE__EEM_Base__delete__before_query',
1966
-            $this,
1967
-            $query_params,
1968
-            $allow_blocking,
1969
-            $columns_and_ids_for_deleting
1970
-        );
1971
-        if ($deletion_where_query_part) {
1972
-            $model_query_info = $this->_create_model_query_info_carrier($query_params);
1973
-            $table_aliases = array_keys($this->_tables);
1974
-            $SQL = "DELETE "
1975
-                   . implode(", ", $table_aliases)
1976
-                   . " FROM "
1977
-                   . $model_query_info->get_full_join_sql()
1978
-                   . " WHERE "
1979
-                   . $deletion_where_query_part;
1980
-            $rows_deleted = $this->_do_wpdb_query('query', array($SQL));
1981
-        } else {
1982
-            $rows_deleted = 0;
1983
-        }
1984
-
1985
-        //Next, make sure those items are removed from the entity map; if they could be put into it at all; and if
1986
-        //there was no error with the delete query.
1987
-        if ($this->has_primary_key_field()
1988
-            && $rows_deleted !== false
1989
-            && isset($columns_and_ids_for_deleting[$this->get_primary_key_field()->get_qualified_column()])
1990
-        ) {
1991
-            $ids_for_removal = $columns_and_ids_for_deleting[$this->get_primary_key_field()->get_qualified_column()];
1992
-            foreach ($ids_for_removal as $id) {
1993
-                if (isset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id])) {
1994
-                    unset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id]);
1995
-                }
1996
-            }
1997
-
1998
-            // delete any extra meta attached to the deleted entities but ONLY if this model is not an instance of
1999
-            //`EEM_Extra_Meta`.  In other words we want to prevent recursion on EEM_Extra_Meta::delete_permanently calls
2000
-            //unnecessarily.  It's very unlikely that users will have assigned Extra Meta to Extra Meta
2001
-            // (although it is possible).
2002
-            //Note this can be skipped by using the provided filter and returning false.
2003
-            if (apply_filters(
2004
-                'FHEE__EEM_Base__delete_permanently__dont_delete_extra_meta_for_extra_meta',
2005
-                ! $this instanceof EEM_Extra_Meta,
2006
-                $this
2007
-            )) {
2008
-                EEM_Extra_Meta::instance()->delete_permanently(array(
2009
-                    0 => array(
2010
-                        'EXM_type' => $this->get_this_model_name(),
2011
-                        'OBJ_ID'   => array(
2012
-                            'IN',
2013
-                            $ids_for_removal
2014
-                        )
2015
-                    )
2016
-                ));
2017
-            }
2018
-        }
2019
-
2020
-        /**
2021
-         * Action called just after performing a real deletion query. Although at this point the
2022
-         * items should have been deleted
2023
-         *
2024
-         * @param EEM_Base $model
2025
-         * @param array    $query_params @see EEM_Base::get_all()
2026
-         * @param int      $rows_deleted
2027
-         */
2028
-        do_action('AHEE__EEM_Base__delete__end', $this, $query_params, $rows_deleted, $columns_and_ids_for_deleting);
2029
-        return $rows_deleted;//how many supposedly got deleted
2030
-    }
2031
-
2032
-
2033
-
2034
-    /**
2035
-     * Checks all the relations that throw error messages when there are blocking related objects
2036
-     * for related model objects. If there are any related model objects on those relations,
2037
-     * adds an EE_Error, and return true
2038
-     *
2039
-     * @param EE_Base_Class|int $this_model_obj_or_id
2040
-     * @param EE_Base_Class     $ignore_this_model_obj a model object like 'EE_Event', or 'EE_Term_Taxonomy', which
2041
-     *                                                 should be ignored when determining whether there are related
2042
-     *                                                 model objects which block this model object's deletion. Useful
2043
-     *                                                 if you know A is related to B and are considering deleting A,
2044
-     *                                                 but want to see if A has any other objects blocking its deletion
2045
-     *                                                 before removing the relation between A and B
2046
-     * @return boolean
2047
-     * @throws EE_Error
2048
-     */
2049
-    public function delete_is_blocked_by_related_models($this_model_obj_or_id, $ignore_this_model_obj = null)
2050
-    {
2051
-        //first, if $ignore_this_model_obj was supplied, get its model
2052
-        if ($ignore_this_model_obj && $ignore_this_model_obj instanceof EE_Base_Class) {
2053
-            $ignored_model = $ignore_this_model_obj->get_model();
2054
-        } else {
2055
-            $ignored_model = null;
2056
-        }
2057
-        //now check all the relations of $this_model_obj_or_id and see if there
2058
-        //are any related model objects blocking it?
2059
-        $is_blocked = false;
2060
-        foreach ($this->_model_relations as $relation_name => $relation_obj) {
2061
-            if ($relation_obj->block_delete_if_related_models_exist()) {
2062
-                //if $ignore_this_model_obj was supplied, then for the query
2063
-                //on that model needs to be told to ignore $ignore_this_model_obj
2064
-                if ($ignored_model && $relation_name === $ignored_model->get_this_model_name()) {
2065
-                    $related_model_objects = $relation_obj->get_all_related($this_model_obj_or_id, array(
2066
-                        array(
2067
-                            $ignored_model->get_primary_key_field()->get_name() => array(
2068
-                                '!=',
2069
-                                $ignore_this_model_obj->ID(),
2070
-                            ),
2071
-                        ),
2072
-                    ));
2073
-                } else {
2074
-                    $related_model_objects = $relation_obj->get_all_related($this_model_obj_or_id);
2075
-                }
2076
-                if ($related_model_objects) {
2077
-                    EE_Error::add_error($relation_obj->get_deletion_error_message(), __FILE__, __FUNCTION__, __LINE__);
2078
-                    $is_blocked = true;
2079
-                }
2080
-            }
2081
-        }
2082
-        return $is_blocked;
2083
-    }
2084
-
2085
-
2086
-    /**
2087
-     * Builds the columns and values for items to delete from the incoming $row_results_for_deleting array.
2088
-     * @param array $row_results_for_deleting
2089
-     * @param bool  $allow_blocking
2090
-     * @return array   The shape of this array depends on whether the model `has_primary_key_field` or not.  If the
2091
-     *                 model DOES have a primary_key_field, then the array will be a simple single dimension array where
2092
-     *                 the key is the fully qualified primary key column and the value is an array of ids that will be
2093
-     *                 deleted. Example:
2094
-     *                      array('Event.EVT_ID' => array( 1,2,3))
2095
-     *                 If the model DOES NOT have a primary_key_field, then the array will be a two dimensional array
2096
-     *                 where each element is a group of columns and values that get deleted. Example:
2097
-     *                      array(
2098
-     *                          0 => array(
2099
-     *                              'Term_Relationship.object_id' => 1
2100
-     *                              'Term_Relationship.term_taxonomy_id' => 5
2101
-     *                          ),
2102
-     *                          1 => array(
2103
-     *                              'Term_Relationship.object_id' => 1
2104
-     *                              'Term_Relationship.term_taxonomy_id' => 6
2105
-     *                          )
2106
-     *                      )
2107
-     * @throws EE_Error
2108
-     */
2109
-    protected function _get_ids_for_delete(array $row_results_for_deleting, $allow_blocking = true)
2110
-    {
2111
-        $ids_to_delete_indexed_by_column = array();
2112
-        if ($this->has_primary_key_field()) {
2113
-            $primary_table = $this->_get_main_table();
2114
-            $primary_table_pk_field = $this->get_field_by_column($primary_table->get_fully_qualified_pk_column());
2115
-            $other_tables = $this->_get_other_tables();
2116
-            $ids_to_delete_indexed_by_column = $query = array();
2117
-            foreach ($row_results_for_deleting as $item_to_delete) {
2118
-                //before we mark this item for deletion,
2119
-                //make sure there's no related entities blocking its deletion (if we're checking)
2120
-                if (
2121
-                    $allow_blocking
2122
-                    && $this->delete_is_blocked_by_related_models(
2123
-                        $item_to_delete[$primary_table->get_fully_qualified_pk_column()]
2124
-                    )
2125
-                ) {
2126
-                    continue;
2127
-                }
2128
-                //primary table deletes
2129
-                if (isset($item_to_delete[$primary_table->get_fully_qualified_pk_column()])) {
2130
-                    $ids_to_delete_indexed_by_column[$primary_table->get_fully_qualified_pk_column()][] =
2131
-                        $item_to_delete[$primary_table->get_fully_qualified_pk_column()];
2132
-                }
2133
-            }
2134
-        } elseif (count($this->get_combined_primary_key_fields()) > 1) {
2135
-            $fields = $this->get_combined_primary_key_fields();
2136
-            foreach ($row_results_for_deleting as $item_to_delete) {
2137
-                $ids_to_delete_indexed_by_column_for_row = array();
2138
-                foreach ($fields as $cpk_field) {
2139
-                    if ($cpk_field instanceof EE_Model_Field_Base) {
2140
-                        $ids_to_delete_indexed_by_column_for_row[$cpk_field->get_qualified_column()] =
2141
-                            $item_to_delete[$cpk_field->get_qualified_column()];
2142
-                    }
2143
-                }
2144
-                $ids_to_delete_indexed_by_column[] = $ids_to_delete_indexed_by_column_for_row;
2145
-            }
2146
-        } else {
2147
-            //so there's no primary key and no combined key...
2148
-            //sorry, can't help you
2149
-            throw new EE_Error(
2150
-                sprintf(
2151
-                    __(
2152
-                        "Cannot delete objects of type %s because there is no primary key NOR combined key",
2153
-                        "event_espresso"
2154
-                    ), get_class($this)
2155
-                )
2156
-            );
2157
-        }
2158
-        return $ids_to_delete_indexed_by_column;
2159
-    }
2160
-
2161
-
2162
-    /**
2163
-     * This receives an array of columns and values set to be deleted (as prepared by _get_ids_for_delete) and prepares
2164
-     * the corresponding query_part for the query performing the delete.
2165
-     *
2166
-     * @param array $ids_to_delete_indexed_by_column @see _get_ids_for_delete for how this array might be shaped.
2167
-     * @return string
2168
-     * @throws EE_Error
2169
-     */
2170
-    protected function _build_query_part_for_deleting_from_columns_and_values(array $ids_to_delete_indexed_by_column) {
2171
-        $query_part = '';
2172
-        if (empty($ids_to_delete_indexed_by_column)) {
2173
-            return $query_part;
2174
-        } elseif ($this->has_primary_key_field()) {
2175
-            $query = array();
2176
-            foreach ($ids_to_delete_indexed_by_column as $column => $ids) {
2177
-                //make sure we have unique $ids
2178
-                $ids = array_unique($ids);
2179
-                $query[] = $column . ' IN(' . implode(',', $ids) . ')';
2180
-            }
2181
-            $query_part = ! empty($query) ? implode(' AND ', $query) : $query_part;
2182
-        } elseif (count($this->get_combined_primary_key_fields()) > 1) {
2183
-            $ways_to_identify_a_row = array();
2184
-            foreach ($ids_to_delete_indexed_by_column as $ids_to_delete_indexed_by_column_for_each_row) {
2185
-                $values_for_each_combined_primary_key_for_a_row = array();
2186
-                foreach ($ids_to_delete_indexed_by_column_for_each_row as $column => $id) {
2187
-                    $values_for_each_combined_primary_key_for_a_row[] = $column . '=' . $id;
2188
-                }
2189
-                $ways_to_identify_a_row[] = '(' . implode(' AND ', $values_for_each_combined_primary_key_for_a_row);
2190
-            }
2191
-            $query_part = implode(' OR ', $ways_to_identify_a_row);
2192
-        }
2193
-        return $query_part;
2194
-    }
2195
-
2196
-
2197
-
2198
-    /**
2199
-     * Gets the model field by the fully qualified name
2200
-     * @param string $qualified_column_name eg 'Event_CPT.post_name' or $field_obj->get_qualified_column()
2201
-     * @return EE_Model_Field_Base
2202
-     */
2203
-    public function get_field_by_column($qualified_column_name)
2204
-    {
2205
-       foreach($this->field_settings(true) as $field_name => $field_obj){
2206
-           if($field_obj->get_qualified_column() === $qualified_column_name){
2207
-               return $field_obj;
2208
-           }
2209
-       }
2210
-        throw new EE_Error(
2211
-            sprintf(
2212
-                esc_html__('Could not find a field on the model "%1$s" for qualified column "%2$s"', 'event_espresso'),
2213
-                $this->get_this_model_name(),
2214
-                $qualified_column_name
2215
-            )
2216
-        );
2217
-    }
2218
-
2219
-
2220
-
2221
-    /**
2222
-     * Count all the rows that match criteria expressed in $query_params (an array just like arg to EEM_Base::get_all).
2223
-     * If $field_to_count isn't provided, the model's primary key is used. Otherwise, we count by field_to_count's
2224
-     * column
2225
-     *
2226
-     * @param array  $query_params   like EEM_Base::get_all's
2227
-     * @param string $field_to_count field on model to count by (not column name)
2228
-     * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2229
-     *                               that by the setting $distinct to TRUE;
2230
-     * @return int
2231
-     * @throws EE_Error
2232
-     */
2233
-    public function count($query_params = array(), $field_to_count = null, $distinct = false)
2234
-    {
2235
-        $model_query_info = $this->_create_model_query_info_carrier($query_params);
2236
-        if ($field_to_count) {
2237
-            $field_obj = $this->field_settings_for($field_to_count);
2238
-            $column_to_count = $field_obj->get_qualified_column();
2239
-        } elseif ($this->has_primary_key_field()) {
2240
-            $pk_field_obj = $this->get_primary_key_field();
2241
-            $column_to_count = $pk_field_obj->get_qualified_column();
2242
-        } else {
2243
-            //there's no primary key
2244
-            //if we're counting distinct items, and there's no primary key,
2245
-            //we need to list out the columns for distinction;
2246
-            //otherwise we can just use star
2247
-            if ($distinct) {
2248
-                $columns_to_use = array();
2249
-                foreach ($this->get_combined_primary_key_fields() as $field_obj) {
2250
-                    $columns_to_use[] = $field_obj->get_qualified_column();
2251
-                }
2252
-                $column_to_count = implode(',', $columns_to_use);
2253
-            } else {
2254
-                $column_to_count = '*';
2255
-            }
2256
-        }
2257
-        $column_to_count = $distinct ? "DISTINCT " . $column_to_count : $column_to_count;
2258
-        $SQL = "SELECT COUNT(" . $column_to_count . ")" . $this->_construct_2nd_half_of_select_query($model_query_info);
2259
-        return (int)$this->_do_wpdb_query('get_var', array($SQL));
2260
-    }
2261
-
2262
-
2263
-
2264
-    /**
2265
-     * Sums up the value of the $field_to_sum (defaults to the primary key, which isn't terribly useful)
2266
-     *
2267
-     * @param array  $query_params like EEM_Base::get_all
2268
-     * @param string $field_to_sum name of field (array key in $_fields array)
2269
-     * @return float
2270
-     * @throws EE_Error
2271
-     */
2272
-    public function sum($query_params, $field_to_sum = null)
2273
-    {
2274
-        $model_query_info = $this->_create_model_query_info_carrier($query_params);
2275
-        if ($field_to_sum) {
2276
-            $field_obj = $this->field_settings_for($field_to_sum);
2277
-        } else {
2278
-            $field_obj = $this->get_primary_key_field();
2279
-        }
2280
-        $column_to_count = $field_obj->get_qualified_column();
2281
-        $SQL = "SELECT SUM(" . $column_to_count . ")" . $this->_construct_2nd_half_of_select_query($model_query_info);
2282
-        $return_value = $this->_do_wpdb_query('get_var', array($SQL));
2283
-        $data_type = $field_obj->get_wpdb_data_type();
2284
-        if ($data_type === '%d' || $data_type === '%s') {
2285
-            return (float)$return_value;
2286
-        }
2287
-        //must be %f
2288
-        return (float)$return_value;
2289
-    }
2290
-
2291
-
2292
-
2293
-    /**
2294
-     * Just calls the specified method on $wpdb with the given arguments
2295
-     * Consolidates a little extra error handling code
2296
-     *
2297
-     * @param string $wpdb_method
2298
-     * @param array  $arguments_to_provide
2299
-     * @throws EE_Error
2300
-     * @global wpdb  $wpdb
2301
-     * @return mixed
2302
-     */
2303
-    protected function _do_wpdb_query($wpdb_method, $arguments_to_provide)
2304
-    {
2305
-        //if we're in maintenance mode level 2, DON'T run any queries
2306
-        //because level 2 indicates the database needs updating and
2307
-        //is probably out of sync with the code
2308
-        if (! EE_Maintenance_Mode::instance()->models_can_query()) {
2309
-            throw new EE_Error(sprintf(__("Event Espresso Level 2 Maintenance mode is active. That means EE can not run ANY database queries until the necessary migration scripts have run which will take EE out of maintenance mode level 2. Please inform support of this error.",
2310
-                "event_espresso")));
2311
-        }
2312
-        /** @type WPDB $wpdb */
2313
-        global $wpdb;
2314
-        if (! method_exists($wpdb, $wpdb_method)) {
2315
-            throw new EE_Error(sprintf(__('There is no method named "%s" on Wordpress\' $wpdb object',
2316
-                'event_espresso'), $wpdb_method));
2317
-        }
2318
-        if (WP_DEBUG) {
2319
-            $old_show_errors_value = $wpdb->show_errors;
2320
-            $wpdb->show_errors(false);
2321
-        }
2322
-        $result = $this->_process_wpdb_query($wpdb_method, $arguments_to_provide);
2323
-        $this->show_db_query_if_previously_requested($wpdb->last_query);
2324
-        if (WP_DEBUG) {
2325
-            $wpdb->show_errors($old_show_errors_value);
2326
-            if (! empty($wpdb->last_error)) {
2327
-                throw new EE_Error(sprintf(__('WPDB Error: "%s"', 'event_espresso'), $wpdb->last_error));
2328
-            }
2329
-            if ($result === false) {
2330
-                throw new EE_Error(sprintf(__('WPDB Error occurred, but no error message was logged by wpdb! The wpdb method called was "%1$s" and the arguments were "%2$s"',
2331
-                    'event_espresso'), $wpdb_method, var_export($arguments_to_provide, true)));
2332
-            }
2333
-        } elseif ($result === false) {
2334
-            EE_Error::add_error(
2335
-                sprintf(
2336
-                    __('A database error has occurred. Turn on WP_DEBUG for more information.||A database error occurred doing wpdb method "%1$s", with arguments "%2$s". The error was "%3$s"',
2337
-                        'event_espresso'),
2338
-                    $wpdb_method,
2339
-                    var_export($arguments_to_provide, true),
2340
-                    $wpdb->last_error
2341
-                ),
2342
-                __FILE__,
2343
-                __FUNCTION__,
2344
-                __LINE__
2345
-            );
2346
-        }
2347
-        return $result;
2348
-    }
2349
-
2350
-
2351
-
2352
-    /**
2353
-     * Attempts to run the indicated WPDB method with the provided arguments,
2354
-     * and if there's an error tries to verify the DB is correct. Uses
2355
-     * the static property EEM_Base::$_db_verification_level to determine whether
2356
-     * we should try to fix the EE core db, the addons, or just give up
2357
-     *
2358
-     * @param string $wpdb_method
2359
-     * @param array  $arguments_to_provide
2360
-     * @return mixed
2361
-     */
2362
-    private function _process_wpdb_query($wpdb_method, $arguments_to_provide)
2363
-    {
2364
-        /** @type WPDB $wpdb */
2365
-        global $wpdb;
2366
-        $wpdb->last_error = null;
2367
-        $result = call_user_func_array(array($wpdb, $wpdb_method), $arguments_to_provide);
2368
-        // was there an error running the query? but we don't care on new activations
2369
-        // (we're going to setup the DB anyway on new activations)
2370
-        if (($result === false || ! empty($wpdb->last_error))
2371
-            && EE_System::instance()->detect_req_type() !== EE_System::req_type_new_activation
2372
-        ) {
2373
-            switch (EEM_Base::$_db_verification_level) {
2374
-                case EEM_Base::db_verified_none :
2375
-                    // let's double-check core's DB
2376
-                    $error_message = $this->_verify_core_db($wpdb_method, $arguments_to_provide);
2377
-                    break;
2378
-                case EEM_Base::db_verified_core :
2379
-                    // STILL NO LOVE?? verify all the addons too. Maybe they need to be fixed
2380
-                    $error_message = $this->_verify_addons_db($wpdb_method, $arguments_to_provide);
2381
-                    break;
2382
-                case EEM_Base::db_verified_addons :
2383
-                    // ummmm... you in trouble
2384
-                    return $result;
2385
-                    break;
2386
-            }
2387
-            if (! empty($error_message)) {
2388
-                EE_Log::instance()->log(__FILE__, __FUNCTION__, $error_message, 'error');
2389
-                trigger_error($error_message);
2390
-            }
2391
-            return $this->_process_wpdb_query($wpdb_method, $arguments_to_provide);
2392
-        }
2393
-        return $result;
2394
-    }
2395
-
2396
-
2397
-
2398
-    /**
2399
-     * Verifies the EE core database is up-to-date and records that we've done it on
2400
-     * EEM_Base::$_db_verification_level
2401
-     *
2402
-     * @param string $wpdb_method
2403
-     * @param array  $arguments_to_provide
2404
-     * @return string
2405
-     */
2406
-    private function _verify_core_db($wpdb_method, $arguments_to_provide)
2407
-    {
2408
-        /** @type WPDB $wpdb */
2409
-        global $wpdb;
2410
-        //ok remember that we've already attempted fixing the core db, in case the problem persists
2411
-        EEM_Base::$_db_verification_level = EEM_Base::db_verified_core;
2412
-        $error_message = sprintf(
2413
-            __('WPDB Error "%1$s" while running wpdb method "%2$s" with arguments %3$s. Automatically attempting to fix EE Core DB',
2414
-                'event_espresso'),
2415
-            $wpdb->last_error,
2416
-            $wpdb_method,
2417
-            wp_json_encode($arguments_to_provide)
2418
-        );
2419
-        EE_System::instance()->initialize_db_if_no_migrations_required(false, true);
2420
-        return $error_message;
2421
-    }
2422
-
2423
-
2424
-
2425
-    /**
2426
-     * Verifies the EE addons' database is up-to-date and records that we've done it on
2427
-     * EEM_Base::$_db_verification_level
2428
-     *
2429
-     * @param $wpdb_method
2430
-     * @param $arguments_to_provide
2431
-     * @return string
2432
-     */
2433
-    private function _verify_addons_db($wpdb_method, $arguments_to_provide)
2434
-    {
2435
-        /** @type WPDB $wpdb */
2436
-        global $wpdb;
2437
-        //ok remember that we've already attempted fixing the addons dbs, in case the problem persists
2438
-        EEM_Base::$_db_verification_level = EEM_Base::db_verified_addons;
2439
-        $error_message = sprintf(
2440
-            __('WPDB AGAIN: Error "%1$s" while running the same method and arguments as before. Automatically attempting to fix EE Addons DB',
2441
-                'event_espresso'),
2442
-            $wpdb->last_error,
2443
-            $wpdb_method,
2444
-            wp_json_encode($arguments_to_provide)
2445
-        );
2446
-        EE_System::instance()->initialize_addons();
2447
-        return $error_message;
2448
-    }
2449
-
2450
-
2451
-
2452
-    /**
2453
-     * In order to avoid repeating this code for the get_all, sum, and count functions, put the code parts
2454
-     * that are identical in here. Returns a string of SQL of everything in a SELECT query except the beginning
2455
-     * SELECT clause, eg " FROM wp_posts AS Event INNER JOIN ... WHERE ... ORDER BY ... LIMIT ... GROUP BY ... HAVING
2456
-     * ..."
2457
-     *
2458
-     * @param EE_Model_Query_Info_Carrier $model_query_info
2459
-     * @return string
2460
-     */
2461
-    private function _construct_2nd_half_of_select_query(EE_Model_Query_Info_Carrier $model_query_info)
2462
-    {
2463
-        return " FROM " . $model_query_info->get_full_join_sql() .
2464
-               $model_query_info->get_where_sql() .
2465
-               $model_query_info->get_group_by_sql() .
2466
-               $model_query_info->get_having_sql() .
2467
-               $model_query_info->get_order_by_sql() .
2468
-               $model_query_info->get_limit_sql();
2469
-    }
2470
-
2471
-
2472
-
2473
-    /**
2474
-     * Set to easily debug the next X queries ran from this model.
2475
-     *
2476
-     * @param int $count
2477
-     */
2478
-    public function show_next_x_db_queries($count = 1)
2479
-    {
2480
-        $this->_show_next_x_db_queries = $count;
2481
-    }
2482
-
2483
-
2484
-
2485
-    /**
2486
-     * @param $sql_query
2487
-     */
2488
-    public function show_db_query_if_previously_requested($sql_query)
2489
-    {
2490
-        if ($this->_show_next_x_db_queries > 0) {
2491
-            echo $sql_query;
2492
-            $this->_show_next_x_db_queries--;
2493
-        }
2494
-    }
2495
-
2496
-
2497
-
2498
-    /**
2499
-     * Adds a relationship of the correct type between $modelObject and $otherModelObject.
2500
-     * There are the 3 cases:
2501
-     * 'belongsTo' relationship: sets $id_or_obj's foreign_key to be $other_model_id_or_obj's primary_key. If
2502
-     * $otherModelObject has no ID, it is first saved.
2503
-     * 'hasMany' relationship: sets $other_model_id_or_obj's foreign_key to be $id_or_obj's primary_key. If $id_or_obj
2504
-     * has no ID, it is first saved.
2505
-     * 'hasAndBelongsToMany' relationships: checks that there isn't already an entry in the join table, and adds one.
2506
-     * If one of the model Objects has not yet been saved to the database, it is saved before adding the entry in the
2507
-     * join table
2508
-     *
2509
-     * @param        EE_Base_Class                     /int $thisModelObject
2510
-     * @param        EE_Base_Class                     /int $id_or_obj EE_base_Class or ID of other Model Object
2511
-     * @param string $relationName                     , key in EEM_Base::_relations
2512
-     *                                                 an attendee to a group, you also want to specify which role they
2513
-     *                                                 will have in that group. So you would use this parameter to
2514
-     *                                                 specify array('role-column-name'=>'role-id')
2515
-     * @param array  $extra_join_model_fields_n_values This allows you to enter further query params for the relation
2516
-     *                                                 to for relation to methods that allow you to further specify
2517
-     *                                                 extra columns to join by (such as HABTM).  Keep in mind that the
2518
-     *                                                 only acceptable query_params is strict "col" => "value" pairs
2519
-     *                                                 because these will be inserted in any new rows created as well.
2520
-     * @return EE_Base_Class which was added as a relation. Object referred to by $other_model_id_or_obj
2521
-     * @throws EE_Error
2522
-     */
2523
-    public function add_relationship_to(
2524
-        $id_or_obj,
2525
-        $other_model_id_or_obj,
2526
-        $relationName,
2527
-        $extra_join_model_fields_n_values = array()
2528
-    ) {
2529
-        $relation_obj = $this->related_settings_for($relationName);
2530
-        return $relation_obj->add_relation_to($id_or_obj, $other_model_id_or_obj, $extra_join_model_fields_n_values);
2531
-    }
2532
-
2533
-
2534
-
2535
-    /**
2536
-     * Removes a relationship of the correct type between $modelObject and $otherModelObject.
2537
-     * There are the 3 cases:
2538
-     * 'belongsTo' relationship: sets $modelObject's foreign_key to null, if that field is nullable.Otherwise throws an
2539
-     * error
2540
-     * 'hasMany' relationship: sets $otherModelObject's foreign_key to null,if that field is nullable.Otherwise throws
2541
-     * an error
2542
-     * 'hasAndBelongsToMany' relationships:removes any existing entry in the join table between the two models.
2543
-     *
2544
-     * @param        EE_Base_Class /int $id_or_obj
2545
-     * @param        EE_Base_Class /int $other_model_id_or_obj EE_Base_Class or ID of other Model Object
2546
-     * @param string $relationName key in EEM_Base::_relations
2547
-     * @return boolean of success
2548
-     * @throws EE_Error
2549
-     * @param array  $where_query  This allows you to enter further query params for the relation to for relation to
2550
-     *                             methods that allow you to further specify extra columns to join by (such as HABTM).
2551
-     *                             Keep in mind that the only acceptable query_params is strict "col" => "value" pairs
2552
-     *                             because these will be inserted in any new rows created as well.
2553
-     */
2554
-    public function remove_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query = array())
2555
-    {
2556
-        $relation_obj = $this->related_settings_for($relationName);
2557
-        return $relation_obj->remove_relation_to($id_or_obj, $other_model_id_or_obj, $where_query);
2558
-    }
2559
-
2560
-
2561
-
2562
-    /**
2563
-     * @param mixed           $id_or_obj
2564
-     * @param string          $relationName
2565
-     * @param array           $where_query_params
2566
-     * @param EE_Base_Class[] objects to which relations were removed
2567
-     * @return \EE_Base_Class[]
2568
-     * @throws EE_Error
2569
-     */
2570
-    public function remove_relations($id_or_obj, $relationName, $where_query_params = array())
2571
-    {
2572
-        $relation_obj = $this->related_settings_for($relationName);
2573
-        return $relation_obj->remove_relations($id_or_obj, $where_query_params);
2574
-    }
2575
-
2576
-
2577
-
2578
-    /**
2579
-     * Gets all the related items of the specified $model_name, using $query_params.
2580
-     * Note: by default, we remove the "default query params"
2581
-     * because we want to get even deleted items etc.
2582
-     *
2583
-     * @param mixed  $id_or_obj    EE_Base_Class child or its ID
2584
-     * @param string $model_name   like 'Event', 'Registration', etc. always singular
2585
-     * @param array  $query_params like EEM_Base::get_all
2586
-     * @return EE_Base_Class[]
2587
-     * @throws EE_Error
2588
-     */
2589
-    public function get_all_related($id_or_obj, $model_name, $query_params = null)
2590
-    {
2591
-        $model_obj = $this->ensure_is_obj($id_or_obj);
2592
-        $relation_settings = $this->related_settings_for($model_name);
2593
-        return $relation_settings->get_all_related($model_obj, $query_params);
2594
-    }
2595
-
2596
-
2597
-
2598
-    /**
2599
-     * Deletes all the model objects across the relation indicated by $model_name
2600
-     * which are related to $id_or_obj which meet the criteria set in $query_params.
2601
-     * However, if the model objects can't be deleted because of blocking related model objects, then
2602
-     * they aren't deleted. (Unless the thing that would have been deleted can be soft-deleted, that still happens).
2603
-     *
2604
-     * @param EE_Base_Class|int|string $id_or_obj
2605
-     * @param string                   $model_name
2606
-     * @param array                    $query_params
2607
-     * @return int how many deleted
2608
-     * @throws EE_Error
2609
-     */
2610
-    public function delete_related($id_or_obj, $model_name, $query_params = array())
2611
-    {
2612
-        $model_obj = $this->ensure_is_obj($id_or_obj);
2613
-        $relation_settings = $this->related_settings_for($model_name);
2614
-        return $relation_settings->delete_all_related($model_obj, $query_params);
2615
-    }
2616
-
2617
-
2618
-
2619
-    /**
2620
-     * Hard deletes all the model objects across the relation indicated by $model_name
2621
-     * which are related to $id_or_obj which meet the criteria set in $query_params. If
2622
-     * the model objects can't be hard deleted because of blocking related model objects,
2623
-     * just does a soft-delete on them instead.
2624
-     *
2625
-     * @param EE_Base_Class|int|string $id_or_obj
2626
-     * @param string                   $model_name
2627
-     * @param array                    $query_params
2628
-     * @return int how many deleted
2629
-     * @throws EE_Error
2630
-     */
2631
-    public function delete_related_permanently($id_or_obj, $model_name, $query_params = array())
2632
-    {
2633
-        $model_obj = $this->ensure_is_obj($id_or_obj);
2634
-        $relation_settings = $this->related_settings_for($model_name);
2635
-        return $relation_settings->delete_related_permanently($model_obj, $query_params);
2636
-    }
2637
-
2638
-
2639
-
2640
-    /**
2641
-     * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2642
-     * unless otherwise specified in the $query_params
2643
-     *
2644
-     * @param        int             /EE_Base_Class $id_or_obj
2645
-     * @param string $model_name     like 'Event', or 'Registration'
2646
-     * @param array  $query_params   like EEM_Base::get_all's
2647
-     * @param string $field_to_count name of field to count by. By default, uses primary key
2648
-     * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2649
-     *                               that by the setting $distinct to TRUE;
2650
-     * @return int
2651
-     * @throws EE_Error
2652
-     */
2653
-    public function count_related(
2654
-        $id_or_obj,
2655
-        $model_name,
2656
-        $query_params = array(),
2657
-        $field_to_count = null,
2658
-        $distinct = false
2659
-    ) {
2660
-        $related_model = $this->get_related_model_obj($model_name);
2661
-        //we're just going to use the query params on the related model's normal get_all query,
2662
-        //except add a condition to say to match the current mod
2663
-        if (! isset($query_params['default_where_conditions'])) {
2664
-            $query_params['default_where_conditions'] = EEM_Base::default_where_conditions_none;
2665
-        }
2666
-        $this_model_name = $this->get_this_model_name();
2667
-        $this_pk_field_name = $this->get_primary_key_field()->get_name();
2668
-        $query_params[0][$this_model_name . "." . $this_pk_field_name] = $id_or_obj;
2669
-        return $related_model->count($query_params, $field_to_count, $distinct);
2670
-    }
2671
-
2672
-
2673
-
2674
-    /**
2675
-     * Instead of getting the related model objects, simply sums up the values of the specified field.
2676
-     * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2677
-     *
2678
-     * @param        int           /EE_Base_Class $id_or_obj
2679
-     * @param string $model_name   like 'Event', or 'Registration'
2680
-     * @param array  $query_params like EEM_Base::get_all's
2681
-     * @param string $field_to_sum name of field to count by. By default, uses primary key
2682
-     * @return float
2683
-     * @throws EE_Error
2684
-     */
2685
-    public function sum_related($id_or_obj, $model_name, $query_params, $field_to_sum = null)
2686
-    {
2687
-        $related_model = $this->get_related_model_obj($model_name);
2688
-        if (! is_array($query_params)) {
2689
-            EE_Error::doing_it_wrong('EEM_Base::sum_related',
2690
-                sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
2691
-                    gettype($query_params)), '4.6.0');
2692
-            $query_params = array();
2693
-        }
2694
-        //we're just going to use the query params on the related model's normal get_all query,
2695
-        //except add a condition to say to match the current mod
2696
-        if (! isset($query_params['default_where_conditions'])) {
2697
-            $query_params['default_where_conditions'] = EEM_Base::default_where_conditions_none;
2698
-        }
2699
-        $this_model_name = $this->get_this_model_name();
2700
-        $this_pk_field_name = $this->get_primary_key_field()->get_name();
2701
-        $query_params[0][$this_model_name . "." . $this_pk_field_name] = $id_or_obj;
2702
-        return $related_model->sum($query_params, $field_to_sum);
2703
-    }
2704
-
2705
-
2706
-
2707
-    /**
2708
-     * Uses $this->_relatedModels info to find the first related model object of relation $relationName to the given
2709
-     * $modelObject
2710
-     *
2711
-     * @param int | EE_Base_Class $id_or_obj        EE_Base_Class child or its ID
2712
-     * @param string              $other_model_name , key in $this->_relatedModels, eg 'Registration', or 'Events'
2713
-     * @param array               $query_params     like EEM_Base::get_all's
2714
-     * @return EE_Base_Class
2715
-     * @throws EE_Error
2716
-     */
2717
-    public function get_first_related(EE_Base_Class $id_or_obj, $other_model_name, $query_params)
2718
-    {
2719
-        $query_params['limit'] = 1;
2720
-        $results = $this->get_all_related($id_or_obj, $other_model_name, $query_params);
2721
-        if ($results) {
2722
-            return array_shift($results);
2723
-        }
2724
-        return null;
2725
-    }
2726
-
2727
-
2728
-
2729
-    /**
2730
-     * Gets the model's name as it's expected in queries. For example, if this is EEM_Event model, that would be Event
2731
-     *
2732
-     * @return string
2733
-     */
2734
-    public function get_this_model_name()
2735
-    {
2736
-        return str_replace("EEM_", "", get_class($this));
2737
-    }
2738
-
2739
-
2740
-
2741
-    /**
2742
-     * Gets the model field on this model which is of type EE_Any_Foreign_Model_Name_Field
2743
-     *
2744
-     * @return EE_Any_Foreign_Model_Name_Field
2745
-     * @throws EE_Error
2746
-     */
2747
-    public function get_field_containing_related_model_name()
2748
-    {
2749
-        foreach ($this->field_settings(true) as $field) {
2750
-            if ($field instanceof EE_Any_Foreign_Model_Name_Field) {
2751
-                $field_with_model_name = $field;
2752
-            }
2753
-        }
2754
-        if (! isset($field_with_model_name) || ! $field_with_model_name) {
2755
-            throw new EE_Error(sprintf(__("There is no EE_Any_Foreign_Model_Name field on model %s", "event_espresso"),
2756
-                $this->get_this_model_name()));
2757
-        }
2758
-        return $field_with_model_name;
2759
-    }
2760
-
2761
-
2762
-
2763
-    /**
2764
-     * Inserts a new entry into the database, for each table.
2765
-     * Note: does not add the item to the entity map because that is done by EE_Base_Class::save() right after this.
2766
-     * If client code uses EEM_Base::insert() directly, then although the item isn't in the entity map,
2767
-     * we also know there is no model object with the newly inserted item's ID at the moment (because
2768
-     * if there were, then they would already be in the DB and this would fail); and in the future if someone
2769
-     * creates a model object with this ID (or grabs it from the DB) then it will be added to the
2770
-     * entity map at that time anyways. SO, no need for EEM_Base::insert ot add to the entity map
2771
-     *
2772
-     * @param array $field_n_values keys are field names, values are their values (in the client code's domain if
2773
-     *                              $values_already_prepared_by_model_object is false, in the model object's domain if
2774
-     *                              $values_already_prepared_by_model_object is true. See comment about this at the top
2775
-     *                              of EEM_Base)
2776
-     * @return int new primary key on main table that got inserted
2777
-     * @throws EE_Error
2778
-     */
2779
-    public function insert($field_n_values)
2780
-    {
2781
-        /**
2782
-         * Filters the fields and their values before inserting an item using the models
2783
-         *
2784
-         * @param array    $fields_n_values keys are the fields and values are their new values
2785
-         * @param EEM_Base $model           the model used
2786
-         */
2787
-        $field_n_values = (array)apply_filters('FHEE__EEM_Base__insert__fields_n_values', $field_n_values, $this);
2788
-        if ($this->_satisfies_unique_indexes($field_n_values)) {
2789
-            $main_table = $this->_get_main_table();
2790
-            $new_id = $this->_insert_into_specific_table($main_table, $field_n_values, false);
2791
-            if ($new_id !== false) {
2792
-                foreach ($this->_get_other_tables() as $other_table) {
2793
-                    $this->_insert_into_specific_table($other_table, $field_n_values, $new_id);
2794
-                }
2795
-            }
2796
-            /**
2797
-             * Done just after attempting to insert a new model object
2798
-             *
2799
-             * @param EEM_Base   $model           used
2800
-             * @param array      $fields_n_values fields and their values
2801
-             * @param int|string the              ID of the newly-inserted model object
2802
-             */
2803
-            do_action('AHEE__EEM_Base__insert__end', $this, $field_n_values, $new_id);
2804
-            return $new_id;
2805
-        }
2806
-        return false;
2807
-    }
2808
-
2809
-
2810
-
2811
-    /**
2812
-     * Checks that the result would satisfy the unique indexes on this model
2813
-     *
2814
-     * @param array  $field_n_values
2815
-     * @param string $action
2816
-     * @return boolean
2817
-     * @throws EE_Error
2818
-     */
2819
-    protected function _satisfies_unique_indexes($field_n_values, $action = 'insert')
2820
-    {
2821
-        foreach ($this->unique_indexes() as $index_name => $index) {
2822
-            $uniqueness_where_params = array_intersect_key($field_n_values, $index->fields());
2823
-            if ($this->exists(array($uniqueness_where_params))) {
2824
-                EE_Error::add_error(
2825
-                    sprintf(
2826
-                        __(
2827
-                            "Could not %s %s. %s uniqueness index failed. Fields %s must form a unique set, but an entry already exists with values %s.",
2828
-                            "event_espresso"
2829
-                        ),
2830
-                        $action,
2831
-                        $this->_get_class_name(),
2832
-                        $index_name,
2833
-                        implode(",", $index->field_names()),
2834
-                        http_build_query($uniqueness_where_params)
2835
-                    ),
2836
-                    __FILE__,
2837
-                    __FUNCTION__,
2838
-                    __LINE__
2839
-                );
2840
-                return false;
2841
-            }
2842
-        }
2843
-        return true;
2844
-    }
2845
-
2846
-
2847
-
2848
-    /**
2849
-     * Checks the database for an item that conflicts (ie, if this item were
2850
-     * saved to the DB would break some uniqueness requirement, like a primary key
2851
-     * or an index primary key set) with the item specified. $id_obj_or_fields_array
2852
-     * can be either an EE_Base_Class or an array of fields n values
2853
-     *
2854
-     * @param EE_Base_Class|array $obj_or_fields_array
2855
-     * @param boolean             $include_primary_key whether to use the model object's primary key
2856
-     *                                                 when looking for conflicts
2857
-     *                                                 (ie, if false, we ignore the model object's primary key
2858
-     *                                                 when finding "conflicts". If true, it's also considered).
2859
-     *                                                 Only works for INT primary key,
2860
-     *                                                 STRING primary keys cannot be ignored
2861
-     * @throws EE_Error
2862
-     * @return EE_Base_Class|array
2863
-     */
2864
-    public function get_one_conflicting($obj_or_fields_array, $include_primary_key = true)
2865
-    {
2866
-        if ($obj_or_fields_array instanceof EE_Base_Class) {
2867
-            $fields_n_values = $obj_or_fields_array->model_field_array();
2868
-        } elseif (is_array($obj_or_fields_array)) {
2869
-            $fields_n_values = $obj_or_fields_array;
2870
-        } else {
2871
-            throw new EE_Error(
2872
-                sprintf(
2873
-                    __(
2874
-                        "%s get_all_conflicting should be called with a model object or an array of field names and values, you provided %d",
2875
-                        "event_espresso"
2876
-                    ),
2877
-                    get_class($this),
2878
-                    $obj_or_fields_array
2879
-                )
2880
-            );
2881
-        }
2882
-        $query_params = array();
2883
-        if ($this->has_primary_key_field()
2884
-            && ($include_primary_key
2885
-                || $this->get_primary_key_field()
2886
-                   instanceof
2887
-                   EE_Primary_Key_String_Field)
2888
-            && isset($fields_n_values[$this->primary_key_name()])
2889
-        ) {
2890
-            $query_params[0]['OR'][$this->primary_key_name()] = $fields_n_values[$this->primary_key_name()];
2891
-        }
2892
-        foreach ($this->unique_indexes() as $unique_index_name => $unique_index) {
2893
-            $uniqueness_where_params = array_intersect_key($fields_n_values, $unique_index->fields());
2894
-            $query_params[0]['OR']['AND*' . $unique_index_name] = $uniqueness_where_params;
2895
-        }
2896
-        //if there is nothing to base this search on, then we shouldn't find anything
2897
-        if (empty($query_params)) {
2898
-            return array();
2899
-        }
2900
-        return $this->get_one($query_params);
2901
-    }
2902
-
2903
-
2904
-
2905
-    /**
2906
-     * Like count, but is optimized and returns a boolean instead of an int
2907
-     *
2908
-     * @param array $query_params
2909
-     * @return boolean
2910
-     * @throws EE_Error
2911
-     */
2912
-    public function exists($query_params)
2913
-    {
2914
-        $query_params['limit'] = 1;
2915
-        return $this->count($query_params) > 0;
2916
-    }
2917
-
2918
-
2919
-
2920
-    /**
2921
-     * Wrapper for exists, except ignores default query parameters so we're only considering ID
2922
-     *
2923
-     * @param int|string $id
2924
-     * @return boolean
2925
-     * @throws EE_Error
2926
-     */
2927
-    public function exists_by_ID($id)
2928
-    {
2929
-        return $this->exists(
2930
-            array(
2931
-                'default_where_conditions' => EEM_Base::default_where_conditions_none,
2932
-                array(
2933
-                    $this->primary_key_name() => $id,
2934
-                ),
2935
-            )
2936
-        );
2937
-    }
2938
-
2939
-
2940
-
2941
-    /**
2942
-     * Inserts a new row in $table, using the $cols_n_values which apply to that table.
2943
-     * If a $new_id is supplied and if $table is an EE_Other_Table, we assume
2944
-     * we need to add a foreign key column to point to $new_id (which should be the primary key's value
2945
-     * on the main table)
2946
-     * This is protected rather than private because private is not accessible to any child methods and there MAY be
2947
-     * cases where we want to call it directly rather than via insert().
2948
-     *
2949
-     * @access   protected
2950
-     * @param EE_Table_Base $table
2951
-     * @param array         $fields_n_values each key should be in field's keys, and value should be an int, string or
2952
-     *                                       float
2953
-     * @param int           $new_id          for now we assume only int keys
2954
-     * @throws EE_Error
2955
-     * @global WPDB         $wpdb            only used to get the $wpdb->insert_id after performing an insert
2956
-     * @return int ID of new row inserted, or FALSE on failure
2957
-     */
2958
-    protected function _insert_into_specific_table(EE_Table_Base $table, $fields_n_values, $new_id = 0)
2959
-    {
2960
-        global $wpdb;
2961
-        $insertion_col_n_values = array();
2962
-        $format_for_insertion = array();
2963
-        $fields_on_table = $this->_get_fields_for_table($table->get_table_alias());
2964
-        foreach ($fields_on_table as $field_name => $field_obj) {
2965
-            //check if its an auto-incrementing column, in which case we should just leave it to do its autoincrement thing
2966
-            if ($field_obj->is_auto_increment()) {
2967
-                continue;
2968
-            }
2969
-            $prepared_value = $this->_prepare_value_or_use_default($field_obj, $fields_n_values);
2970
-            //if the value we want to assign it to is NULL, just don't mention it for the insertion
2971
-            if ($prepared_value !== null) {
2972
-                $insertion_col_n_values[$field_obj->get_table_column()] = $prepared_value;
2973
-                $format_for_insertion[] = $field_obj->get_wpdb_data_type();
2974
-            }
2975
-        }
2976
-        if ($table instanceof EE_Secondary_Table && $new_id) {
2977
-            //its not the main table, so we should have already saved the main table's PK which we just inserted
2978
-            //so add the fk to the main table as a column
2979
-            $insertion_col_n_values[$table->get_fk_on_table()] = $new_id;
2980
-            $format_for_insertion[] = '%d';//yes right now we're only allowing these foreign keys to be INTs
2981
-        }
2982
-        //insert the new entry
2983
-        $result = $this->_do_wpdb_query('insert',
2984
-            array($table->get_table_name(), $insertion_col_n_values, $format_for_insertion));
2985
-        if ($result === false) {
2986
-            return false;
2987
-        }
2988
-        //ok, now what do we return for the ID of the newly-inserted thing?
2989
-        if ($this->has_primary_key_field()) {
2990
-            if ($this->get_primary_key_field()->is_auto_increment()) {
2991
-                return $wpdb->insert_id;
2992
-            }
2993
-            //it's not an auto-increment primary key, so
2994
-            //it must have been supplied
2995
-            return $fields_n_values[$this->get_primary_key_field()->get_name()];
2996
-        }
2997
-        //we can't return a  primary key because there is none. instead return
2998
-        //a unique string indicating this model
2999
-        return $this->get_index_primary_key_string($fields_n_values);
3000
-    }
3001
-
3002
-
3003
-
3004
-    /**
3005
-     * Prepare the $field_obj 's value in $fields_n_values for use in the database.
3006
-     * If the field doesn't allow NULL, try to use its default. (If it doesn't allow NULL,
3007
-     * and there is no default, we pass it along. WPDB will take care of it)
3008
-     *
3009
-     * @param EE_Model_Field_Base $field_obj
3010
-     * @param array               $fields_n_values
3011
-     * @return mixed string|int|float depending on what the table column will be expecting
3012
-     * @throws EE_Error
3013
-     */
3014
-    protected function _prepare_value_or_use_default($field_obj, $fields_n_values)
3015
-    {
3016
-        //if this field doesn't allow nullable, don't allow it
3017
-        if (
3018
-            ! $field_obj->is_nullable()
3019
-            && (
3020
-                ! isset($fields_n_values[$field_obj->get_name()])
3021
-                || $fields_n_values[$field_obj->get_name()] === null
3022
-            )
3023
-        ) {
3024
-            $fields_n_values[$field_obj->get_name()] = $field_obj->get_default_value();
3025
-        }
3026
-        $unprepared_value = isset($fields_n_values[$field_obj->get_name()])
3027
-            ? $fields_n_values[$field_obj->get_name()]
3028
-            : null;
3029
-        return $this->_prepare_value_for_use_in_db($unprepared_value, $field_obj);
3030
-    }
3031
-
3032
-
3033
-
3034
-    /**
3035
-     * Consolidates code for preparing  a value supplied to the model for use int eh db. Calls the field's
3036
-     * prepare_for_use_in_db method on the value, and depending on $value_already_prepare_by_model_obj, may also call
3037
-     * the field's prepare_for_set() method.
3038
-     *
3039
-     * @param mixed               $value value in the client code domain if $value_already_prepared_by_model_object is
3040
-     *                                   false, otherwise a value in the model object's domain (see lengthy comment at
3041
-     *                                   top of file)
3042
-     * @param EE_Model_Field_Base $field field which will be doing the preparing of the value. If null, we assume
3043
-     *                                   $value is a custom selection
3044
-     * @return mixed a value ready for use in the database for insertions, updating, or in a where clause
3045
-     */
3046
-    private function _prepare_value_for_use_in_db($value, $field)
3047
-    {
3048
-        if ($field && $field instanceof EE_Model_Field_Base) {
3049
-            switch ($this->_values_already_prepared_by_model_object) {
3050
-                /** @noinspection PhpMissingBreakStatementInspection */
3051
-                case self::not_prepared_by_model_object:
3052
-                    $value = $field->prepare_for_set($value);
3053
-                //purposefully left out "return"
3054
-                case self::prepared_by_model_object:
3055
-                    /** @noinspection SuspiciousAssignmentsInspection */
3056
-                    $value = $field->prepare_for_use_in_db($value);
3057
-                case self::prepared_for_use_in_db:
3058
-                    //leave the value alone
3059
-            }
3060
-            return $value;
3061
-        }
3062
-        return $value;
3063
-    }
3064
-
3065
-
3066
-
3067
-    /**
3068
-     * Returns the main table on this model
3069
-     *
3070
-     * @return EE_Primary_Table
3071
-     * @throws EE_Error
3072
-     */
3073
-    protected function _get_main_table()
3074
-    {
3075
-        foreach ($this->_tables as $table) {
3076
-            if ($table instanceof EE_Primary_Table) {
3077
-                return $table;
3078
-            }
3079
-        }
3080
-        throw new EE_Error(sprintf(__('There are no main tables on %s. They should be added to _tables array in the constructor',
3081
-            'event_espresso'), get_class($this)));
3082
-    }
3083
-
3084
-
3085
-
3086
-    /**
3087
-     * table
3088
-     * returns EE_Primary_Table table name
3089
-     *
3090
-     * @return string
3091
-     * @throws EE_Error
3092
-     */
3093
-    public function table()
3094
-    {
3095
-        return $this->_get_main_table()->get_table_name();
3096
-    }
3097
-
3098
-
3099
-
3100
-    /**
3101
-     * table
3102
-     * returns first EE_Secondary_Table table name
3103
-     *
3104
-     * @return string
3105
-     */
3106
-    public function second_table()
3107
-    {
3108
-        // grab second table from tables array
3109
-        $second_table = end($this->_tables);
3110
-        return $second_table instanceof EE_Secondary_Table ? $second_table->get_table_name() : null;
3111
-    }
3112
-
3113
-
3114
-
3115
-    /**
3116
-     * get_table_obj_by_alias
3117
-     * returns table name given it's alias
3118
-     *
3119
-     * @param string $table_alias
3120
-     * @return EE_Primary_Table | EE_Secondary_Table
3121
-     */
3122
-    public function get_table_obj_by_alias($table_alias = '')
3123
-    {
3124
-        return isset($this->_tables[$table_alias]) ? $this->_tables[$table_alias] : null;
3125
-    }
3126
-
3127
-
3128
-
3129
-    /**
3130
-     * Gets all the tables of type EE_Other_Table from EEM_CPT_Basel_Model::_tables
3131
-     *
3132
-     * @return EE_Secondary_Table[]
3133
-     */
3134
-    protected function _get_other_tables()
3135
-    {
3136
-        $other_tables = array();
3137
-        foreach ($this->_tables as $table_alias => $table) {
3138
-            if ($table instanceof EE_Secondary_Table) {
3139
-                $other_tables[$table_alias] = $table;
3140
-            }
3141
-        }
3142
-        return $other_tables;
3143
-    }
3144
-
3145
-
3146
-
3147
-    /**
3148
-     * Finds all the fields that correspond to the given table
3149
-     *
3150
-     * @param string $table_alias , array key in EEM_Base::_tables
3151
-     * @return EE_Model_Field_Base[]
3152
-     */
3153
-    public function _get_fields_for_table($table_alias)
3154
-    {
3155
-        return $this->_fields[$table_alias];
3156
-    }
3157
-
3158
-
3159
-
3160
-    /**
3161
-     * Recurses through all the where parameters, and finds all the related models we'll need
3162
-     * to complete this query. Eg, given where parameters like array('EVT_ID'=>3) from within Event model, we won't
3163
-     * need any related models. But if the array were array('Registrations.REG_ID'=>3), we'd need the related
3164
-     * Registration model. If it were array('Registrations.Transactions.Payments.PAY_ID'=>3), then we'd need the
3165
-     * related Registration, Transaction, and Payment models.
3166
-     *
3167
-     * @param array $query_params like EEM_Base::get_all's $query_parameters['where']
3168
-     * @return EE_Model_Query_Info_Carrier
3169
-     * @throws EE_Error
3170
-     */
3171
-    public function _extract_related_models_from_query($query_params)
3172
-    {
3173
-        $query_info_carrier = new EE_Model_Query_Info_Carrier();
3174
-        if (array_key_exists(0, $query_params)) {
3175
-            $this->_extract_related_models_from_sub_params_array_keys($query_params[0], $query_info_carrier, 0);
3176
-        }
3177
-        if (array_key_exists('group_by', $query_params)) {
3178
-            if (is_array($query_params['group_by'])) {
3179
-                $this->_extract_related_models_from_sub_params_array_values(
3180
-                    $query_params['group_by'],
3181
-                    $query_info_carrier,
3182
-                    'group_by'
3183
-                );
3184
-            } elseif (! empty ($query_params['group_by'])) {
3185
-                $this->_extract_related_model_info_from_query_param(
3186
-                    $query_params['group_by'],
3187
-                    $query_info_carrier,
3188
-                    'group_by'
3189
-                );
3190
-            }
3191
-        }
3192
-        if (array_key_exists('having', $query_params)) {
3193
-            $this->_extract_related_models_from_sub_params_array_keys(
3194
-                $query_params[0],
3195
-                $query_info_carrier,
3196
-                'having'
3197
-            );
3198
-        }
3199
-        if (array_key_exists('order_by', $query_params)) {
3200
-            if (is_array($query_params['order_by'])) {
3201
-                $this->_extract_related_models_from_sub_params_array_keys(
3202
-                    $query_params['order_by'],
3203
-                    $query_info_carrier,
3204
-                    'order_by'
3205
-                );
3206
-            } elseif (! empty($query_params['order_by'])) {
3207
-                $this->_extract_related_model_info_from_query_param(
3208
-                    $query_params['order_by'],
3209
-                    $query_info_carrier,
3210
-                    'order_by'
3211
-                );
3212
-            }
3213
-        }
3214
-        if (array_key_exists('force_join', $query_params)) {
3215
-            $this->_extract_related_models_from_sub_params_array_values(
3216
-                $query_params['force_join'],
3217
-                $query_info_carrier,
3218
-                'force_join'
3219
-            );
3220
-        }
3221
-        return $query_info_carrier;
3222
-    }
3223
-
3224
-
3225
-
3226
-    /**
3227
-     * For extracting related models from WHERE (0), HAVING (having), ORDER BY (order_by) or forced joins (force_join)
3228
-     *
3229
-     * @param array                       $sub_query_params like EEM_Base::get_all's $query_params[0] or
3230
-     *                                                      $query_params['having']
3231
-     * @param EE_Model_Query_Info_Carrier $model_query_info_carrier
3232
-     * @param string                      $query_param_type one of $this->_allowed_query_params
3233
-     * @throws EE_Error
3234
-     * @return \EE_Model_Query_Info_Carrier
3235
-     */
3236
-    private function _extract_related_models_from_sub_params_array_keys(
3237
-        $sub_query_params,
3238
-        EE_Model_Query_Info_Carrier $model_query_info_carrier,
3239
-        $query_param_type
3240
-    ) {
3241
-        if (! empty($sub_query_params)) {
3242
-            $sub_query_params = (array)$sub_query_params;
3243
-            foreach ($sub_query_params as $param => $possibly_array_of_params) {
3244
-                //$param could be simply 'EVT_ID', or it could be 'Registrations.REG_ID', or even 'Registrations.Transactions.Payments.PAY_amount'
3245
-                $this->_extract_related_model_info_from_query_param($param, $model_query_info_carrier,
3246
-                    $query_param_type);
3247
-                //if $possibly_array_of_params is an array, try recursing into it, searching for keys which
3248
-                //indicate needed joins. Eg, array('NOT'=>array('Registration.TXN_ID'=>23)). In this case, we tried
3249
-                //extracting models out of the 'NOT', which obviously wasn't successful, and then we recurse into the value
3250
-                //of array('Registration.TXN_ID'=>23)
3251
-                $query_param_sans_stars = $this->_remove_stars_and_anything_after_from_condition_query_param_key($param);
3252
-                if (in_array($query_param_sans_stars, $this->_logic_query_param_keys, true)) {
3253
-                    if (! is_array($possibly_array_of_params)) {
3254
-                        throw new EE_Error(sprintf(__("You used a special where query param %s, but the value isn't an array of where query params, it's just %s'. It should be an array, eg array('EVT_ID'=>23,'OR'=>array('Venue.VNU_ID'=>32,'Venue.VNU_name'=>'monkey_land'))",
3255
-                            "event_espresso"),
3256
-                            $param, $possibly_array_of_params));
3257
-                    }
3258
-                    $this->_extract_related_models_from_sub_params_array_keys(
3259
-                        $possibly_array_of_params,
3260
-                        $model_query_info_carrier, $query_param_type
3261
-                    );
3262
-                } elseif ($query_param_type === 0 //ie WHERE
3263
-                          && is_array($possibly_array_of_params)
3264
-                          && isset($possibly_array_of_params[2])
3265
-                          && $possibly_array_of_params[2] == true
3266
-                ) {
3267
-                    //then $possible_array_of_params looks something like array('<','DTT_sold',true)
3268
-                    //indicating that $possible_array_of_params[1] is actually a field name,
3269
-                    //from which we should extract query parameters!
3270
-                    if (! isset($possibly_array_of_params[0], $possibly_array_of_params[1])) {
3271
-                        throw new EE_Error(sprintf(__("Improperly formed query parameter %s. It should be numerically indexed like array('<','DTT_sold',true); but you provided %s",
3272
-                            "event_espresso"), $query_param_type, implode(",", $possibly_array_of_params)));
3273
-                    }
3274
-                    $this->_extract_related_model_info_from_query_param($possibly_array_of_params[1],
3275
-                        $model_query_info_carrier, $query_param_type);
3276
-                }
3277
-            }
3278
-        }
3279
-        return $model_query_info_carrier;
3280
-    }
3281
-
3282
-
3283
-
3284
-    /**
3285
-     * For extracting related models from forced_joins, where the array values contain the info about what
3286
-     * models to join with. Eg an array like array('Attendee','Price.Price_Type');
3287
-     *
3288
-     * @param array                       $sub_query_params like EEM_Base::get_all's $query_params[0] or
3289
-     *                                                      $query_params['having']
3290
-     * @param EE_Model_Query_Info_Carrier $model_query_info_carrier
3291
-     * @param string                      $query_param_type one of $this->_allowed_query_params
3292
-     * @throws EE_Error
3293
-     * @return \EE_Model_Query_Info_Carrier
3294
-     */
3295
-    private function _extract_related_models_from_sub_params_array_values(
3296
-        $sub_query_params,
3297
-        EE_Model_Query_Info_Carrier $model_query_info_carrier,
3298
-        $query_param_type
3299
-    ) {
3300
-        if (! empty($sub_query_params)) {
3301
-            if (! is_array($sub_query_params)) {
3302
-                throw new EE_Error(sprintf(__("Query parameter %s should be an array, but it isn't.", "event_espresso"),
3303
-                    $sub_query_params));
3304
-            }
3305
-            foreach ($sub_query_params as $param) {
3306
-                //$param could be simply 'EVT_ID', or it could be 'Registrations.REG_ID', or even 'Registrations.Transactions.Payments.PAY_amount'
3307
-                $this->_extract_related_model_info_from_query_param($param, $model_query_info_carrier,
3308
-                    $query_param_type);
3309
-            }
3310
-        }
3311
-        return $model_query_info_carrier;
3312
-    }
3313
-
3314
-
3315
-
3316
-    /**
3317
-     * Extract all the query parts from $query_params (an array like whats passed to EEM_Base::get_all)
3318
-     * and put into a EEM_Related_Model_Info_Carrier for easy extraction into a query. We create this object
3319
-     * instead of directly constructing the SQL because often we need to extract info from the $query_params
3320
-     * but use them in a different order. Eg, we need to know what models we are querying
3321
-     * before we know what joins to perform. However, we need to know what data types correspond to which fields on
3322
-     * other models before we can finalize the where clause SQL.
3323
-     *
3324
-     * @param array $query_params
3325
-     * @throws EE_Error
3326
-     * @return EE_Model_Query_Info_Carrier
3327
-     */
3328
-    public function _create_model_query_info_carrier($query_params)
3329
-    {
3330
-        if (! is_array($query_params)) {
3331
-            EE_Error::doing_it_wrong(
3332
-                'EEM_Base::_create_model_query_info_carrier',
3333
-                sprintf(
3334
-                    __(
3335
-                        '$query_params should be an array, you passed a variable of type %s',
3336
-                        'event_espresso'
3337
-                    ),
3338
-                    gettype($query_params)
3339
-                ),
3340
-                '4.6.0'
3341
-            );
3342
-            $query_params = array();
3343
-        }
3344
-        $where_query_params = isset($query_params[0]) ? $query_params[0] : array();
3345
-        //first check if we should alter the query to account for caps or not
3346
-        //because the caps might require us to do extra joins
3347
-        if (isset($query_params['caps']) && $query_params['caps'] !== 'none') {
3348
-            $query_params[0] = $where_query_params = array_replace_recursive(
3349
-                $where_query_params,
3350
-                $this->caps_where_conditions(
3351
-                    $query_params['caps']
3352
-                )
3353
-            );
3354
-        }
3355
-        $query_object = $this->_extract_related_models_from_query($query_params);
3356
-        //verify where_query_params has NO numeric indexes.... that's simply not how you use it!
3357
-        foreach ($where_query_params as $key => $value) {
3358
-            if (is_int($key)) {
3359
-                throw new EE_Error(
3360
-                    sprintf(
3361
-                        __(
3362
-                            "WHERE query params must NOT be numerically-indexed. You provided the array key '%s' for value '%s' while querying model %s. All the query params provided were '%s' Please read documentation on EEM_Base::get_all.",
3363
-                            "event_espresso"
3364
-                        ),
3365
-                        $key,
3366
-                        var_export($value, true),
3367
-                        var_export($query_params, true),
3368
-                        get_class($this)
3369
-                    )
3370
-                );
3371
-            }
3372
-        }
3373
-        if (
3374
-            array_key_exists('default_where_conditions', $query_params)
3375
-            && ! empty($query_params['default_where_conditions'])
3376
-        ) {
3377
-            $use_default_where_conditions = $query_params['default_where_conditions'];
3378
-        } else {
3379
-            $use_default_where_conditions = EEM_Base::default_where_conditions_all;
3380
-        }
3381
-        $where_query_params = array_merge(
3382
-            $this->_get_default_where_conditions_for_models_in_query(
3383
-                $query_object,
3384
-                $use_default_where_conditions,
3385
-                $where_query_params
3386
-            ),
3387
-            $where_query_params
3388
-        );
3389
-        $query_object->set_where_sql($this->_construct_where_clause($where_query_params));
3390
-        // if this is a "on_join_limit" then we are limiting on on a specific table in a multi_table join.
3391
-        // So we need to setup a subquery and use that for the main join.
3392
-        // Note for now this only works on the primary table for the model.
3393
-        // So for instance, you could set the limit array like this:
3394
-        // array( 'on_join_limit' => array('Primary_Table_Alias', array(1,10) ) )
3395
-        if (array_key_exists('on_join_limit', $query_params) && ! empty($query_params['on_join_limit'])) {
3396
-            $query_object->set_main_model_join_sql(
3397
-                $this->_construct_limit_join_select(
3398
-                    $query_params['on_join_limit'][0],
3399
-                    $query_params['on_join_limit'][1]
3400
-                )
3401
-            );
3402
-        }
3403
-        //set limit
3404
-        if (array_key_exists('limit', $query_params)) {
3405
-            if (is_array($query_params['limit'])) {
3406
-                if (! isset($query_params['limit'][0], $query_params['limit'][1])) {
3407
-                    $e = sprintf(
3408
-                        __(
3409
-                            "Invalid DB query. You passed '%s' for the LIMIT, but only the following are valid: an integer, string representing an integer, a string like 'int,int', or an array like array(int,int)",
3410
-                            "event_espresso"
3411
-                        ),
3412
-                        http_build_query($query_params['limit'])
3413
-                    );
3414
-                    throw new EE_Error($e . "|" . $e);
3415
-                }
3416
-                //they passed us an array for the limit. Assume it's like array(50,25), meaning offset by 50, and get 25
3417
-                $query_object->set_limit_sql(" LIMIT " . $query_params['limit'][0] . "," . $query_params['limit'][1]);
3418
-            } elseif (! empty ($query_params['limit'])) {
3419
-                $query_object->set_limit_sql(" LIMIT " . $query_params['limit']);
3420
-            }
3421
-        }
3422
-        //set order by
3423
-        if (array_key_exists('order_by', $query_params)) {
3424
-            if (is_array($query_params['order_by'])) {
3425
-                //if they're using 'order_by' as an array, they can't use 'order' (because 'order_by' must
3426
-                //specify whether to ascend or descend on each field. Eg 'order_by'=>array('EVT_ID'=>'ASC'). So
3427
-                //including 'order' wouldn't make any sense if 'order_by' has already specified which way to order!
3428
-                if (array_key_exists('order', $query_params)) {
3429
-                    throw new EE_Error(
3430
-                        sprintf(
3431
-                            __(
3432
-                                "In querying %s, we are using query parameter 'order_by' as an array (keys:%s,values:%s), and so we can't use query parameter 'order' (value %s). You should just use the 'order_by' parameter ",
3433
-                                "event_espresso"
3434
-                            ),
3435
-                            get_class($this),
3436
-                            implode(", ", array_keys($query_params['order_by'])),
3437
-                            implode(", ", $query_params['order_by']),
3438
-                            $query_params['order']
3439
-                        )
3440
-                    );
3441
-                }
3442
-                $this->_extract_related_models_from_sub_params_array_keys(
3443
-                    $query_params['order_by'],
3444
-                    $query_object,
3445
-                    'order_by'
3446
-                );
3447
-                //assume it's an array of fields to order by
3448
-                $order_array = array();
3449
-                foreach ($query_params['order_by'] as $field_name_to_order_by => $order) {
3450
-                    $order = $this->_extract_order($order);
3451
-                    $order_array[] = $this->_deduce_column_name_from_query_param($field_name_to_order_by) . SP . $order;
3452
-                }
3453
-                $query_object->set_order_by_sql(" ORDER BY " . implode(",", $order_array));
3454
-            } elseif (! empty ($query_params['order_by'])) {
3455
-                $this->_extract_related_model_info_from_query_param(
3456
-                    $query_params['order_by'],
3457
-                    $query_object,
3458
-                    'order',
3459
-                    $query_params['order_by']
3460
-                );
3461
-                $order = isset($query_params['order'])
3462
-                    ? $this->_extract_order($query_params['order'])
3463
-                    : 'DESC';
3464
-                $query_object->set_order_by_sql(
3465
-                    " ORDER BY " . $this->_deduce_column_name_from_query_param($query_params['order_by']) . SP . $order
3466
-                );
3467
-            }
3468
-        }
3469
-        //if 'order_by' wasn't set, maybe they are just using 'order' on its own?
3470
-        if (! array_key_exists('order_by', $query_params)
3471
-            && array_key_exists('order', $query_params)
3472
-            && ! empty($query_params['order'])
3473
-        ) {
3474
-            $pk_field = $this->get_primary_key_field();
3475
-            $order = $this->_extract_order($query_params['order']);
3476
-            $query_object->set_order_by_sql(" ORDER BY " . $pk_field->get_qualified_column() . SP . $order);
3477
-        }
3478
-        //set group by
3479
-        if (array_key_exists('group_by', $query_params)) {
3480
-            if (is_array($query_params['group_by'])) {
3481
-                //it's an array, so assume we'll be grouping by a bunch of stuff
3482
-                $group_by_array = array();
3483
-                foreach ($query_params['group_by'] as $field_name_to_group_by) {
3484
-                    $group_by_array[] = $this->_deduce_column_name_from_query_param($field_name_to_group_by);
3485
-                }
3486
-                $query_object->set_group_by_sql(" GROUP BY " . implode(", ", $group_by_array));
3487
-            } elseif (! empty ($query_params['group_by'])) {
3488
-                $query_object->set_group_by_sql(
3489
-                    " GROUP BY " . $this->_deduce_column_name_from_query_param($query_params['group_by'])
3490
-                );
3491
-            }
3492
-        }
3493
-        //set having
3494
-        if (array_key_exists('having', $query_params) && $query_params['having']) {
3495
-            $query_object->set_having_sql($this->_construct_having_clause($query_params['having']));
3496
-        }
3497
-        //now, just verify they didn't pass anything wack
3498
-        foreach ($query_params as $query_key => $query_value) {
3499
-            if (! in_array($query_key, $this->_allowed_query_params, true)) {
3500
-                throw new EE_Error(
3501
-                    sprintf(
3502
-                        __(
3503
-                            "You passed %s as a query parameter to %s, which is illegal! The allowed query parameters are %s",
3504
-                            'event_espresso'
3505
-                        ),
3506
-                        $query_key,
3507
-                        get_class($this),
3508
-                        //						print_r( $this->_allowed_query_params, TRUE )
3509
-                        implode(',', $this->_allowed_query_params)
3510
-                    )
3511
-                );
3512
-            }
3513
-        }
3514
-        $main_model_join_sql = $query_object->get_main_model_join_sql();
3515
-        if (empty($main_model_join_sql)) {
3516
-            $query_object->set_main_model_join_sql($this->_construct_internal_join());
3517
-        }
3518
-        return $query_object;
3519
-    }
3520
-
3521
-
3522
-
3523
-    /**
3524
-     * Gets the where conditions that should be imposed on the query based on the
3525
-     * context (eg reading frontend, backend, edit or delete).
3526
-     *
3527
-     * @param string $context one of EEM_Base::valid_cap_contexts()
3528
-     * @return array like EEM_Base::get_all() 's $query_params[0]
3529
-     * @throws EE_Error
3530
-     */
3531
-    public function caps_where_conditions($context = self::caps_read)
3532
-    {
3533
-        EEM_Base::verify_is_valid_cap_context($context);
3534
-        $cap_where_conditions = array();
3535
-        $cap_restrictions = $this->caps_missing($context);
3536
-        /**
3537
-         * @var $cap_restrictions EE_Default_Where_Conditions[]
3538
-         */
3539
-        foreach ($cap_restrictions as $cap => $restriction_if_no_cap) {
3540
-            $cap_where_conditions = array_replace_recursive($cap_where_conditions,
3541
-                $restriction_if_no_cap->get_default_where_conditions());
3542
-        }
3543
-        return apply_filters('FHEE__EEM_Base__caps_where_conditions__return', $cap_where_conditions, $this, $context,
3544
-            $cap_restrictions);
3545
-    }
3546
-
3547
-
3548
-
3549
-    /**
3550
-     * Verifies that $should_be_order_string is in $this->_allowed_order_values,
3551
-     * otherwise throws an exception
3552
-     *
3553
-     * @param string $should_be_order_string
3554
-     * @return string either ASC, asc, DESC or desc
3555
-     * @throws EE_Error
3556
-     */
3557
-    private function _extract_order($should_be_order_string)
3558
-    {
3559
-        if (in_array($should_be_order_string, $this->_allowed_order_values)) {
3560
-            return $should_be_order_string;
3561
-        }
3562
-        throw new EE_Error(
3563
-            sprintf(
3564
-                __(
3565
-                    "While performing a query on '%s', tried to use '%s' as an order parameter. ",
3566
-                    "event_espresso"
3567
-                ), get_class($this), $should_be_order_string
3568
-            )
3569
-        );
3570
-    }
3571
-
3572
-
3573
-
3574
-    /**
3575
-     * Looks at all the models which are included in this query, and asks each
3576
-     * for their universal_where_params, and returns them in the same format as $query_params[0] (where),
3577
-     * so they can be merged
3578
-     *
3579
-     * @param EE_Model_Query_Info_Carrier $query_info_carrier
3580
-     * @param string                      $use_default_where_conditions can be 'none','other_models_only', or 'all'.
3581
-     *                                                                  'none' means NO default where conditions will
3582
-     *                                                                  be used AT ALL during this query.
3583
-     *                                                                  'other_models_only' means default where
3584
-     *                                                                  conditions from other models will be used, but
3585
-     *                                                                  not for this primary model. 'all', the default,
3586
-     *                                                                  means default where conditions will apply as
3587
-     *                                                                  normal
3588
-     * @param array                       $where_query_params           like EEM_Base::get_all's $query_params[0]
3589
-     * @throws EE_Error
3590
-     * @return array like $query_params[0], see EEM_Base::get_all for documentation
3591
-     */
3592
-    private function _get_default_where_conditions_for_models_in_query(
3593
-        EE_Model_Query_Info_Carrier $query_info_carrier,
3594
-        $use_default_where_conditions = EEM_Base::default_where_conditions_all,
3595
-        $where_query_params = array()
3596
-    ) {
3597
-        $allowed_used_default_where_conditions_values = EEM_Base::valid_default_where_conditions();
3598
-        if (! in_array($use_default_where_conditions, $allowed_used_default_where_conditions_values)) {
3599
-            throw new EE_Error(sprintf(__("You passed an invalid value to the query parameter 'default_where_conditions' of '%s'. Allowed values are %s",
3600
-                "event_espresso"), $use_default_where_conditions,
3601
-                implode(", ", $allowed_used_default_where_conditions_values)));
3602
-        }
3603
-        $universal_query_params = array();
3604
-        if ($this->_should_use_default_where_conditions( $use_default_where_conditions, true)) {
3605
-            $universal_query_params = $this->_get_default_where_conditions();
3606
-        } else if ($this->_should_use_minimum_where_conditions( $use_default_where_conditions, true)) {
3607
-            $universal_query_params = $this->_get_minimum_where_conditions();
3608
-        }
3609
-        foreach ($query_info_carrier->get_model_names_included() as $model_relation_path => $model_name) {
3610
-            $related_model = $this->get_related_model_obj($model_name);
3611
-            if ( $this->_should_use_default_where_conditions( $use_default_where_conditions, false)) {
3612
-                $related_model_universal_where_params = $related_model->_get_default_where_conditions($model_relation_path);
3613
-            } elseif ($this->_should_use_minimum_where_conditions( $use_default_where_conditions, false)) {
3614
-                $related_model_universal_where_params = $related_model->_get_minimum_where_conditions($model_relation_path);
3615
-            } else {
3616
-                //we don't want to add full or even minimum default where conditions from this model, so just continue
3617
-                continue;
3618
-            }
3619
-            $overrides = $this->_override_defaults_or_make_null_friendly(
3620
-                $related_model_universal_where_params,
3621
-                $where_query_params,
3622
-                $related_model,
3623
-                $model_relation_path
3624
-            );
3625
-            $universal_query_params = EEH_Array::merge_arrays_and_overwrite_keys(
3626
-                $universal_query_params,
3627
-                $overrides
3628
-            );
3629
-        }
3630
-        return $universal_query_params;
3631
-    }
3632
-
3633
-
3634
-
3635
-    /**
3636
-     * Determines whether or not we should use default where conditions for the model in question
3637
-     * (this model, or other related models).
3638
-     * Basically, we should use default where conditions on this model if they have requested to use them on all models,
3639
-     * this model only, or to use minimum where conditions on all other models and normal where conditions on this one.
3640
-     * We should use default where conditions on related models when they requested to use default where conditions
3641
-     * on all models, or specifically just on other related models
3642
-     * @param      $default_where_conditions_value
3643
-     * @param bool $for_this_model false means this is for OTHER related models
3644
-     * @return bool
3645
-     */
3646
-    private function _should_use_default_where_conditions( $default_where_conditions_value, $for_this_model = true )
3647
-    {
3648
-        return (
3649
-                   $for_this_model
3650
-                   && in_array(
3651
-                       $default_where_conditions_value,
3652
-                       array(
3653
-                           EEM_Base::default_where_conditions_all,
3654
-                           EEM_Base::default_where_conditions_this_only,
3655
-                           EEM_Base::default_where_conditions_minimum_others,
3656
-                       ),
3657
-                       true
3658
-                   )
3659
-               )
3660
-               || (
3661
-                   ! $for_this_model
3662
-                   && in_array(
3663
-                       $default_where_conditions_value,
3664
-                       array(
3665
-                           EEM_Base::default_where_conditions_all,
3666
-                           EEM_Base::default_where_conditions_others_only,
3667
-                       ),
3668
-                       true
3669
-                   )
3670
-               );
3671
-    }
3672
-
3673
-    /**
3674
-     * Determines whether or not we should use default minimum conditions for the model in question
3675
-     * (this model, or other related models).
3676
-     * Basically, we should use minimum where conditions on this model only if they requested all models to use minimum
3677
-     * where conditions.
3678
-     * We should use minimum where conditions on related models if they requested to use minimum where conditions
3679
-     * on this model or others
3680
-     * @param      $default_where_conditions_value
3681
-     * @param bool $for_this_model false means this is for OTHER related models
3682
-     * @return bool
3683
-     */
3684
-    private function _should_use_minimum_where_conditions($default_where_conditions_value, $for_this_model = true)
3685
-    {
3686
-        return (
3687
-                   $for_this_model
3688
-                   && $default_where_conditions_value === EEM_Base::default_where_conditions_minimum_all
3689
-               )
3690
-               || (
3691
-                   ! $for_this_model
3692
-                   && in_array(
3693
-                       $default_where_conditions_value,
3694
-                       array(
3695
-                           EEM_Base::default_where_conditions_minimum_others,
3696
-                           EEM_Base::default_where_conditions_minimum_all,
3697
-                       ),
3698
-                       true
3699
-                   )
3700
-               );
3701
-    }
3702
-
3703
-
3704
-    /**
3705
-     * Checks if any of the defaults have been overridden. If there are any that AREN'T overridden,
3706
-     * then we also add a special where condition which allows for that model's primary key
3707
-     * to be null (which is important for JOINs. Eg, if you want to see all Events ordered by Venue's name,
3708
-     * then Event's with NO Venue won't appear unless you allow VNU_ID to be NULL)
3709
-     *
3710
-     * @param array    $default_where_conditions
3711
-     * @param array    $provided_where_conditions
3712
-     * @param EEM_Base $model
3713
-     * @param string   $model_relation_path like 'Transaction.Payment.'
3714
-     * @return array like EEM_Base::get_all's $query_params[0]
3715
-     * @throws EE_Error
3716
-     */
3717
-    private function _override_defaults_or_make_null_friendly(
3718
-        $default_where_conditions,
3719
-        $provided_where_conditions,
3720
-        $model,
3721
-        $model_relation_path
3722
-    ) {
3723
-        $null_friendly_where_conditions = array();
3724
-        $none_overridden = true;
3725
-        $or_condition_key_for_defaults = 'OR*' . get_class($model);
3726
-        foreach ($default_where_conditions as $key => $val) {
3727
-            if (isset($provided_where_conditions[$key])) {
3728
-                $none_overridden = false;
3729
-            } else {
3730
-                $null_friendly_where_conditions[$or_condition_key_for_defaults]['AND'][$key] = $val;
3731
-            }
3732
-        }
3733
-        if ($none_overridden && $default_where_conditions) {
3734
-            if ($model->has_primary_key_field()) {
3735
-                $null_friendly_where_conditions[$or_condition_key_for_defaults][$model_relation_path
3736
-                                                                                . "."
3737
-                                                                                . $model->primary_key_name()] = array('IS NULL');
3738
-            }/*else{
35
+	/**
36
+	 * Flag to indicate whether the values provided to EEM_Base have already been prepared
37
+	 * by the model object or not (ie, the model object has used the field's _prepare_for_set function on the values).
38
+	 * They almost always WILL NOT, but it's not necessarily a requirement.
39
+	 * For example, if you want to run EEM_Event::instance()->get_all(array(array('EVT_ID'=>$_GET['event_id'])));
40
+	 *
41
+	 * @var boolean
42
+	 */
43
+	private $_values_already_prepared_by_model_object = 0;
44
+
45
+	/**
46
+	 * when $_values_already_prepared_by_model_object equals this, we assume
47
+	 * the data is just like form input that needs to have the model fields'
48
+	 * prepare_for_set and prepare_for_use_in_db called on it
49
+	 */
50
+	const not_prepared_by_model_object = 0;
51
+
52
+	/**
53
+	 * when $_values_already_prepared_by_model_object equals this, we
54
+	 * assume this value is coming from a model object and doesn't need to have
55
+	 * prepare_for_set called on it, just prepare_for_use_in_db is used
56
+	 */
57
+	const prepared_by_model_object = 1;
58
+
59
+	/**
60
+	 * when $_values_already_prepared_by_model_object equals this, we assume
61
+	 * the values are already to be used in the database (ie no processing is done
62
+	 * on them by the model's fields)
63
+	 */
64
+	const prepared_for_use_in_db = 2;
65
+
66
+
67
+	protected $singular_item = 'Item';
68
+
69
+	protected $plural_item   = 'Items';
70
+
71
+	/**
72
+	 * @type \EE_Table_Base[] $_tables array of EE_Table objects for defining which tables comprise this model.
73
+	 */
74
+	protected $_tables;
75
+
76
+	/**
77
+	 * with two levels: top-level has array keys which are database table aliases (ie, keys in _tables)
78
+	 * and the value is an array. Each of those sub-arrays have keys of field names (eg 'ATT_ID', which should also be
79
+	 * variable names on the model objects (eg, EE_Attendee), and the keys should be children of EE_Model_Field
80
+	 *
81
+	 * @var \EE_Model_Field_Base[][] $_fields
82
+	 */
83
+	protected $_fields;
84
+
85
+	/**
86
+	 * array of different kinds of relations
87
+	 *
88
+	 * @var \EE_Model_Relation_Base[] $_model_relations
89
+	 */
90
+	protected $_model_relations;
91
+
92
+	/**
93
+	 * @var \EE_Index[] $_indexes
94
+	 */
95
+	protected $_indexes = array();
96
+
97
+	/**
98
+	 * Default strategy for getting where conditions on this model. This strategy is used to get default
99
+	 * where conditions which are added to get_all, update, and delete queries. They can be overridden
100
+	 * by setting the same columns as used in these queries in the query yourself.
101
+	 *
102
+	 * @var EE_Default_Where_Conditions
103
+	 */
104
+	protected $_default_where_conditions_strategy;
105
+
106
+	/**
107
+	 * Strategy for getting conditions on this model when 'default_where_conditions' equals 'minimum'.
108
+	 * This is particularly useful when you want something between 'none' and 'default'
109
+	 *
110
+	 * @var EE_Default_Where_Conditions
111
+	 */
112
+	protected $_minimum_where_conditions_strategy;
113
+
114
+	/**
115
+	 * String describing how to find the "owner" of this model's objects.
116
+	 * When there is a foreign key on this model to the wp_users table, this isn't needed.
117
+	 * But when there isn't, this indicates which related model, or transiently-related model,
118
+	 * has the foreign key to the wp_users table.
119
+	 * Eg, for EEM_Registration this would be 'Event' because registrations are directly
120
+	 * related to events, and events have a foreign key to wp_users.
121
+	 * On EEM_Transaction, this would be 'Transaction.Event'
122
+	 *
123
+	 * @var string
124
+	 */
125
+	protected $_model_chain_to_wp_user = '';
126
+
127
+	/**
128
+	 * This is a flag typically set by updates so that we don't load the where strategy on updates because updates
129
+	 * don't need it (particularly CPT models)
130
+	 *
131
+	 * @var bool
132
+	 */
133
+	protected $_ignore_where_strategy = false;
134
+
135
+	/**
136
+	 * String used in caps relating to this model. Eg, if the caps relating to this
137
+	 * model are 'ee_edit_events', 'ee_read_events', etc, it would be 'events'.
138
+	 *
139
+	 * @var string. If null it hasn't been initialized yet. If false then we
140
+	 * have indicated capabilities don't apply to this
141
+	 */
142
+	protected $_caps_slug = null;
143
+
144
+	/**
145
+	 * 2d array where top-level keys are one of EEM_Base::valid_cap_contexts(),
146
+	 * and next-level keys are capability names, and each's value is a
147
+	 * EE_Default_Where_Condition. If the requester requests to apply caps to the query,
148
+	 * they specify which context to use (ie, frontend, backend, edit or delete)
149
+	 * and then each capability in the corresponding sub-array that they're missing
150
+	 * adds the where conditions onto the query.
151
+	 *
152
+	 * @var array
153
+	 */
154
+	protected $_cap_restrictions = array(
155
+		self::caps_read       => array(),
156
+		self::caps_read_admin => array(),
157
+		self::caps_edit       => array(),
158
+		self::caps_delete     => array(),
159
+	);
160
+
161
+	/**
162
+	 * Array defining which cap restriction generators to use to create default
163
+	 * cap restrictions to put in EEM_Base::_cap_restrictions.
164
+	 * Array-keys are one of EEM_Base::valid_cap_contexts(), and values are a child of
165
+	 * EE_Restriction_Generator_Base. If you don't want any cap restrictions generated
166
+	 * automatically set this to false (not just null).
167
+	 *
168
+	 * @var EE_Restriction_Generator_Base[]
169
+	 */
170
+	protected $_cap_restriction_generators = array();
171
+
172
+	/**
173
+	 * constants used to categorize capability restrictions on EEM_Base::_caps_restrictions
174
+	 */
175
+	const caps_read       = 'read';
176
+
177
+	const caps_read_admin = 'read_admin';
178
+
179
+	const caps_edit       = 'edit';
180
+
181
+	const caps_delete     = 'delete';
182
+
183
+	/**
184
+	 * Keys are all the cap contexts (ie constants EEM_Base::_caps_*) and values are their 'action'
185
+	 * as how they'd be used in capability names. Eg EEM_Base::caps_read ('read_frontend')
186
+	 * maps to 'read' because when looking for relevant permissions we're going to use
187
+	 * 'read' in teh capabilities names like 'ee_read_events' etc.
188
+	 *
189
+	 * @var array
190
+	 */
191
+	protected $_cap_contexts_to_cap_action_map = array(
192
+		self::caps_read       => 'read',
193
+		self::caps_read_admin => 'read',
194
+		self::caps_edit       => 'edit',
195
+		self::caps_delete     => 'delete',
196
+	);
197
+
198
+	/**
199
+	 * Timezone
200
+	 * This gets set via the constructor so that we know what timezone incoming strings|timestamps are in when there
201
+	 * are EE_Datetime_Fields in use.  This can also be used before a get to set what timezone you want strings coming
202
+	 * out of the created objects.  NOT all EEM_Base child classes use this property but any that use a
203
+	 * EE_Datetime_Field data type will have access to it.
204
+	 *
205
+	 * @var string
206
+	 */
207
+	protected $_timezone;
208
+
209
+
210
+	/**
211
+	 * This holds the id of the blog currently making the query.  Has no bearing on single site but is used for
212
+	 * multisite.
213
+	 *
214
+	 * @var int
215
+	 */
216
+	protected static $_model_query_blog_id;
217
+
218
+	/**
219
+	 * A copy of _fields, except the array keys are the model names pointed to by
220
+	 * the field
221
+	 *
222
+	 * @var EE_Model_Field_Base[]
223
+	 */
224
+	private $_cache_foreign_key_to_fields = array();
225
+
226
+	/**
227
+	 * Cached list of all the fields on the model, indexed by their name
228
+	 *
229
+	 * @var EE_Model_Field_Base[]
230
+	 */
231
+	private $_cached_fields = null;
232
+
233
+	/**
234
+	 * Cached list of all the fields on the model, except those that are
235
+	 * marked as only pertinent to the database
236
+	 *
237
+	 * @var EE_Model_Field_Base[]
238
+	 */
239
+	private $_cached_fields_non_db_only = null;
240
+
241
+	/**
242
+	 * A cached reference to the primary key for quick lookup
243
+	 *
244
+	 * @var EE_Model_Field_Base
245
+	 */
246
+	private $_primary_key_field = null;
247
+
248
+	/**
249
+	 * Flag indicating whether this model has a primary key or not
250
+	 *
251
+	 * @var boolean
252
+	 */
253
+	protected $_has_primary_key_field = null;
254
+
255
+	/**
256
+	 * Whether or not this model is based off a table in WP core only (CPTs should set
257
+	 * this to FALSE, but if we were to make an EE_WP_Post model, it should set this to true).
258
+	 * This should be true for models that deal with data that should exist independent of EE.
259
+	 * For example, if the model can read and insert data that isn't used by EE, this should be true.
260
+	 * It would be false, however, if you could guarantee the model would only interact with EE data,
261
+	 * even if it uses a WP core table (eg event and venue models set this to false for that reason:
262
+	 * they can only read and insert events and venues custom post types, not arbitrary post types)
263
+	 * @var boolean
264
+	 */
265
+	protected $_wp_core_model = false;
266
+
267
+	/**
268
+	 *    List of valid operators that can be used for querying.
269
+	 * The keys are all operators we'll accept, the values are the real SQL
270
+	 * operators used
271
+	 *
272
+	 * @var array
273
+	 */
274
+	protected $_valid_operators = array(
275
+		'='           => '=',
276
+		'<='          => '<=',
277
+		'<'           => '<',
278
+		'>='          => '>=',
279
+		'>'           => '>',
280
+		'!='          => '!=',
281
+		'LIKE'        => 'LIKE',
282
+		'like'        => 'LIKE',
283
+		'NOT_LIKE'    => 'NOT LIKE',
284
+		'not_like'    => 'NOT LIKE',
285
+		'NOT LIKE'    => 'NOT LIKE',
286
+		'not like'    => 'NOT LIKE',
287
+		'IN'          => 'IN',
288
+		'in'          => 'IN',
289
+		'NOT_IN'      => 'NOT IN',
290
+		'not_in'      => 'NOT IN',
291
+		'NOT IN'      => 'NOT IN',
292
+		'not in'      => 'NOT IN',
293
+		'between'     => 'BETWEEN',
294
+		'BETWEEN'     => 'BETWEEN',
295
+		'IS_NOT_NULL' => 'IS NOT NULL',
296
+		'is_not_null' => 'IS NOT NULL',
297
+		'IS NOT NULL' => 'IS NOT NULL',
298
+		'is not null' => 'IS NOT NULL',
299
+		'IS_NULL'     => 'IS NULL',
300
+		'is_null'     => 'IS NULL',
301
+		'IS NULL'     => 'IS NULL',
302
+		'is null'     => 'IS NULL',
303
+		'REGEXP'      => 'REGEXP',
304
+		'regexp'      => 'REGEXP',
305
+		'NOT_REGEXP'  => 'NOT REGEXP',
306
+		'not_regexp'  => 'NOT REGEXP',
307
+		'NOT REGEXP'  => 'NOT REGEXP',
308
+		'not regexp'  => 'NOT REGEXP',
309
+	);
310
+
311
+	/**
312
+	 * operators that work like 'IN', accepting a comma-separated list of values inside brackets. Eg '(1,2,3)'
313
+	 *
314
+	 * @var array
315
+	 */
316
+	protected $_in_style_operators = array('IN', 'NOT IN');
317
+
318
+	/**
319
+	 * operators that work like 'BETWEEN'.  Typically used for datetime calculations, i.e. "BETWEEN '12-1-2011' AND
320
+	 * '12-31-2012'"
321
+	 *
322
+	 * @var array
323
+	 */
324
+	protected $_between_style_operators = array('BETWEEN');
325
+
326
+	/**
327
+	 * Operators that work like SQL's like: input should be assumed to be a string, already prepared for a LIKE query.
328
+	 * @var array
329
+	 */
330
+	protected $_like_style_operators = array('LIKE', 'NOT LIKE');
331
+	/**
332
+	 * operators that are used for handling NUll and !NULL queries.  Typically used for when checking if a row exists
333
+	 * on a join table.
334
+	 *
335
+	 * @var array
336
+	 */
337
+	protected $_null_style_operators = array('IS NOT NULL', 'IS NULL');
338
+
339
+	/**
340
+	 * Allowed values for $query_params['order'] for ordering in queries
341
+	 *
342
+	 * @var array
343
+	 */
344
+	protected $_allowed_order_values = array('asc', 'desc', 'ASC', 'DESC');
345
+
346
+	/**
347
+	 * When these are keys in a WHERE or HAVING clause, they are handled much differently
348
+	 * than regular field names. It is assumed that their values are an array of WHERE conditions
349
+	 *
350
+	 * @var array
351
+	 */
352
+	private $_logic_query_param_keys = array('not', 'and', 'or', 'NOT', 'AND', 'OR');
353
+
354
+	/**
355
+	 * Allowed keys in $query_params arrays passed into queries. Note that 0 is meant to always be a
356
+	 * 'where', but 'where' clauses are so common that we thought we'd omit it
357
+	 *
358
+	 * @var array
359
+	 */
360
+	private $_allowed_query_params = array(
361
+		0,
362
+		'limit',
363
+		'order_by',
364
+		'group_by',
365
+		'having',
366
+		'force_join',
367
+		'order',
368
+		'on_join_limit',
369
+		'default_where_conditions',
370
+		'caps',
371
+	);
372
+
373
+	/**
374
+	 * All the data types that can be used in $wpdb->prepare statements.
375
+	 *
376
+	 * @var array
377
+	 */
378
+	private $_valid_wpdb_data_types = array('%d', '%s', '%f');
379
+
380
+	/**
381
+	 * @var EE_Registry $EE
382
+	 */
383
+	protected $EE = null;
384
+
385
+
386
+	/**
387
+	 * Property which, when set, will have this model echo out the next X queries to the page for debugging.
388
+	 *
389
+	 * @var int
390
+	 */
391
+	protected $_show_next_x_db_queries = 0;
392
+
393
+	/**
394
+	 * When using _get_all_wpdb_results, you can specify a custom selection. If you do so,
395
+	 * it gets saved on this property so those selections can be used in WHERE, GROUP_BY, etc.
396
+	 *
397
+	 * @var array
398
+	 */
399
+	protected $_custom_selections = array();
400
+
401
+	/**
402
+	 * key => value Entity Map using  array( EEM_Base::$_model_query_blog_id => array( ID => model object ) )
403
+	 * caches every model object we've fetched from the DB on this request
404
+	 *
405
+	 * @var array
406
+	 */
407
+	protected $_entity_map;
408
+
409
+	/**
410
+	 * @var LoaderInterface $loader
411
+	 */
412
+	private static $loader;
413
+
414
+
415
+	/**
416
+	 * constant used to show EEM_Base has not yet verified the db on this http request
417
+	 */
418
+	const db_verified_none = 0;
419
+
420
+	/**
421
+	 * constant used to show EEM_Base has verified the EE core db on this http request,
422
+	 * but not the addons' dbs
423
+	 */
424
+	const db_verified_core = 1;
425
+
426
+	/**
427
+	 * constant used to show EEM_Base has verified the addons' dbs (and implicitly
428
+	 * the EE core db too)
429
+	 */
430
+	const db_verified_addons = 2;
431
+
432
+	/**
433
+	 * indicates whether an EEM_Base child has already re-verified the DB
434
+	 * is ok (we don't want to do it repetitively). Should be set to one the constants
435
+	 * looking like EEM_Base::db_verified_*
436
+	 *
437
+	 * @var int - 0 = none, 1 = core, 2 = addons
438
+	 */
439
+	protected static $_db_verification_level = EEM_Base::db_verified_none;
440
+
441
+	/**
442
+	 * @const constant for 'default_where_conditions' to apply default where conditions to ALL queried models
443
+	 *        (eg, if retrieving registrations ordered by their datetimes, this will only return non-trashed
444
+	 *        registrations for non-trashed tickets for non-trashed datetimes)
445
+	 */
446
+	const default_where_conditions_all = 'all';
447
+
448
+	/**
449
+	 * @const constant for 'default_where_conditions' to apply default where conditions to THIS model only, but
450
+	 *        no other models which are joined to (eg, if retrieving registrations ordered by their datetimes, this will
451
+	 *        return non-trashed registrations, regardless of the related datetimes and tickets' statuses).
452
+	 *        It is preferred to use EEM_Base::default_where_conditions_minimum_others because, when joining to
453
+	 *        models which share tables with other models, this can return data for the wrong model.
454
+	 */
455
+	const default_where_conditions_this_only = 'this_model_only';
456
+
457
+	/**
458
+	 * @const constant for 'default_where_conditions' to apply default where conditions to other models queried,
459
+	 *        but not the current model (eg, if retrieving registrations ordered by their datetimes, this will
460
+	 *        return all registrations related to non-trashed tickets and non-trashed datetimes)
461
+	 */
462
+	const default_where_conditions_others_only = 'other_models_only';
463
+
464
+	/**
465
+	 * @const constant for 'default_where_conditions' to apply minimum where conditions to all models queried.
466
+	 *        For most models this the same as EEM_Base::default_where_conditions_none, except for models which share
467
+	 *        their table with other models, like the Event and Venue models. For example, when querying for events
468
+	 *        ordered by their venues' name, this will be sure to only return real events with associated real venues
469
+	 *        (regardless of whether those events and venues are trashed)
470
+	 *        In contrast, using EEM_Base::default_where_conditions_none would could return WP posts other than EE
471
+	 *        events.
472
+	 */
473
+	const default_where_conditions_minimum_all = 'minimum';
474
+
475
+	/**
476
+	 * @const constant for 'default_where_conditions' to apply apply where conditions to other models, and full default
477
+	 *        where conditions for the queried model (eg, when querying events ordered by venues' names, this will
478
+	 *        return non-trashed events for any venues, regardless of whether those associated venues are trashed or
479
+	 *        not)
480
+	 */
481
+	const default_where_conditions_minimum_others = 'full_this_minimum_others';
482
+
483
+	/**
484
+	 * @const constant for 'default_where_conditions' to NOT apply any where conditions. This should very rarely be
485
+	 *        used, because when querying from a model which shares its table with another model (eg Events and Venues)
486
+	 *        it's possible it will return table entries for other models. You should use
487
+	 *        EEM_Base::default_where_conditions_minimum_all instead.
488
+	 */
489
+	const default_where_conditions_none = 'none';
490
+
491
+
492
+
493
+	/**
494
+	 * About all child constructors:
495
+	 * they should define the _tables, _fields and _model_relations arrays.
496
+	 * Should ALWAYS be called after child constructor.
497
+	 * In order to make the child constructors to be as simple as possible, this parent constructor
498
+	 * finalizes constructing all the object's attributes.
499
+	 * Generally, rather than requiring a child to code
500
+	 * $this->_tables = array(
501
+	 *        'Event_Post_Table' => new EE_Table('Event_Post_Table','wp_posts')
502
+	 *        ...);
503
+	 *  (thus repeating itself in the array key and in the constructor of the new EE_Table,)
504
+	 * each EE_Table has a function to set the table's alias after the constructor, using
505
+	 * the array key ('Event_Post_Table'), instead of repeating it. The model fields and model relations
506
+	 * do something similar.
507
+	 *
508
+	 * @param null $timezone
509
+	 * @throws EE_Error
510
+	 */
511
+	protected function __construct($timezone = null)
512
+	{
513
+		// check that the model has not been loaded too soon
514
+		if (! did_action('AHEE__EE_System__load_espresso_addons')) {
515
+			throw new EE_Error (
516
+				sprintf(
517
+					__('The %1$s model can not be loaded before the "AHEE__EE_System__load_espresso_addons" hook has been called. This gives other addons a chance to extend this model.',
518
+						'event_espresso'),
519
+					get_class($this)
520
+				)
521
+			);
522
+		}
523
+		/**
524
+		 * Set blogid for models to current blog. However we ONLY do this if $_model_query_blog_id is not already set.
525
+		 */
526
+		if (empty(EEM_Base::$_model_query_blog_id)) {
527
+			EEM_Base::set_model_query_blog_id();
528
+		}
529
+		/**
530
+		 * Filters the list of tables on a model. It is best to NOT use this directly and instead
531
+		 * just use EE_Register_Model_Extension
532
+		 *
533
+		 * @var EE_Table_Base[] $_tables
534
+		 */
535
+		$this->_tables = (array)apply_filters('FHEE__' . get_class($this) . '__construct__tables', $this->_tables);
536
+		foreach ($this->_tables as $table_alias => $table_obj) {
537
+			/** @var $table_obj EE_Table_Base */
538
+			$table_obj->_construct_finalize_with_alias($table_alias);
539
+			if ($table_obj instanceof EE_Secondary_Table) {
540
+				/** @var $table_obj EE_Secondary_Table */
541
+				$table_obj->_construct_finalize_set_table_to_join_with($this->_get_main_table());
542
+			}
543
+		}
544
+		/**
545
+		 * Filters the list of fields on a model. It is best to NOT use this directly and instead just use
546
+		 * EE_Register_Model_Extension
547
+		 *
548
+		 * @param EE_Model_Field_Base[] $_fields
549
+		 */
550
+		$this->_fields = (array)apply_filters('FHEE__' . get_class($this) . '__construct__fields', $this->_fields);
551
+		$this->_invalidate_field_caches();
552
+		foreach ($this->_fields as $table_alias => $fields_for_table) {
553
+			if (! array_key_exists($table_alias, $this->_tables)) {
554
+				throw new EE_Error(sprintf(__("Table alias %s does not exist in EEM_Base child's _tables array. Only tables defined are %s",
555
+					'event_espresso'), $table_alias, implode(",", $this->_fields)));
556
+			}
557
+			foreach ($fields_for_table as $field_name => $field_obj) {
558
+				/** @var $field_obj EE_Model_Field_Base | EE_Primary_Key_Field_Base */
559
+				//primary key field base has a slightly different _construct_finalize
560
+				/** @var $field_obj EE_Model_Field_Base */
561
+				$field_obj->_construct_finalize($table_alias, $field_name, $this->get_this_model_name());
562
+			}
563
+		}
564
+		// everything is related to Extra_Meta
565
+		if (get_class($this) !== 'EEM_Extra_Meta') {
566
+			//make extra meta related to everything, but don't block deleting things just
567
+			//because they have related extra meta info. For now just orphan those extra meta
568
+			//in the future we should automatically delete them
569
+			$this->_model_relations['Extra_Meta'] = new EE_Has_Many_Any_Relation(false);
570
+		}
571
+		//and change logs
572
+		if (get_class($this) !== 'EEM_Change_Log') {
573
+			$this->_model_relations['Change_Log'] = new EE_Has_Many_Any_Relation(false);
574
+		}
575
+		/**
576
+		 * Filters the list of relations on a model. It is best to NOT use this directly and instead just use
577
+		 * EE_Register_Model_Extension
578
+		 *
579
+		 * @param EE_Model_Relation_Base[] $_model_relations
580
+		 */
581
+		$this->_model_relations = (array)apply_filters('FHEE__' . get_class($this) . '__construct__model_relations',
582
+			$this->_model_relations);
583
+		foreach ($this->_model_relations as $model_name => $relation_obj) {
584
+			/** @var $relation_obj EE_Model_Relation_Base */
585
+			$relation_obj->_construct_finalize_set_models($this->get_this_model_name(), $model_name);
586
+		}
587
+		foreach ($this->_indexes as $index_name => $index_obj) {
588
+			/** @var $index_obj EE_Index */
589
+			$index_obj->_construct_finalize($index_name, $this->get_this_model_name());
590
+		}
591
+		$this->set_timezone($timezone);
592
+		//finalize default where condition strategy, or set default
593
+		if (! $this->_default_where_conditions_strategy) {
594
+			//nothing was set during child constructor, so set default
595
+			$this->_default_where_conditions_strategy = new EE_Default_Where_Conditions();
596
+		}
597
+		$this->_default_where_conditions_strategy->_finalize_construct($this);
598
+		if (! $this->_minimum_where_conditions_strategy) {
599
+			//nothing was set during child constructor, so set default
600
+			$this->_minimum_where_conditions_strategy = new EE_Default_Where_Conditions();
601
+		}
602
+		$this->_minimum_where_conditions_strategy->_finalize_construct($this);
603
+		//if the cap slug hasn't been set, and we haven't set it to false on purpose
604
+		//to indicate to NOT set it, set it to the logical default
605
+		if ($this->_caps_slug === null) {
606
+			$this->_caps_slug = EEH_Inflector::pluralize_and_lower($this->get_this_model_name());
607
+		}
608
+		//initialize the standard cap restriction generators if none were specified by the child constructor
609
+		if ($this->_cap_restriction_generators !== false) {
610
+			foreach ($this->cap_contexts_to_cap_action_map() as $cap_context => $action) {
611
+				if (! isset($this->_cap_restriction_generators[$cap_context])) {
612
+					$this->_cap_restriction_generators[$cap_context] = apply_filters(
613
+						'FHEE__EEM_Base___construct__standard_cap_restriction_generator',
614
+						new EE_Restriction_Generator_Protected(),
615
+						$cap_context,
616
+						$this
617
+					);
618
+				}
619
+			}
620
+		}
621
+		//if there are cap restriction generators, use them to make the default cap restrictions
622
+		if ($this->_cap_restriction_generators !== false) {
623
+			foreach ($this->_cap_restriction_generators as $context => $generator_object) {
624
+				if (! $generator_object) {
625
+					continue;
626
+				}
627
+				if (! $generator_object instanceof EE_Restriction_Generator_Base) {
628
+					throw new EE_Error(
629
+						sprintf(
630
+							__('Index "%1$s" in the model %2$s\'s _cap_restriction_generators is not a child of EE_Restriction_Generator_Base. It should be that or NULL.',
631
+								'event_espresso'),
632
+							$context,
633
+							$this->get_this_model_name()
634
+						)
635
+					);
636
+				}
637
+				$action = $this->cap_action_for_context($context);
638
+				if (! $generator_object->construction_finalized()) {
639
+					$generator_object->_construct_finalize($this, $action);
640
+				}
641
+			}
642
+		}
643
+		do_action('AHEE__' . get_class($this) . '__construct__end');
644
+	}
645
+
646
+
647
+
648
+	/**
649
+	 * Used to set the $_model_query_blog_id static property.
650
+	 *
651
+	 * @param int $blog_id  If provided then will set the blog_id for the models to this id.  If not provided then the
652
+	 *                      value for get_current_blog_id() will be used.
653
+	 */
654
+	public static function set_model_query_blog_id($blog_id = 0)
655
+	{
656
+		EEM_Base::$_model_query_blog_id = $blog_id > 0 ? (int)$blog_id : get_current_blog_id();
657
+	}
658
+
659
+
660
+
661
+	/**
662
+	 * Returns whatever is set as the internal $model_query_blog_id.
663
+	 *
664
+	 * @return int
665
+	 */
666
+	public static function get_model_query_blog_id()
667
+	{
668
+		return EEM_Base::$_model_query_blog_id;
669
+	}
670
+
671
+
672
+
673
+	/**
674
+	 * This function is a singleton method used to instantiate the Espresso_model object
675
+	 *
676
+	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings
677
+	 *                                (and any incoming timezone data that gets saved).
678
+	 *                                Note this just sends the timezone info to the date time model field objects.
679
+	 *                                Default is NULL
680
+	 *                                (and will be assumed using the set timezone in the 'timezone_string' wp option)
681
+	 * @return static (as in the concrete child class)
682
+	 * @throws EE_Error
683
+	 * @throws InvalidArgumentException
684
+	 * @throws InvalidDataTypeException
685
+	 * @throws InvalidInterfaceException
686
+	 */
687
+	public static function instance($timezone = null)
688
+	{
689
+		// check if instance of Espresso_model already exists
690
+		if (! static::$_instance instanceof static) {
691
+			// instantiate Espresso_model
692
+			static::$_instance = new static(
693
+				$timezone,
694
+				LoaderFactory::getLoader()->load('EventEspresso\core\services\orm\ModelFieldFactory')
695
+			);
696
+		}
697
+		//we might have a timezone set, let set_timezone decide what to do with it
698
+		static::$_instance->set_timezone($timezone);
699
+		// Espresso_model object
700
+		return static::$_instance;
701
+	}
702
+
703
+
704
+
705
+	/**
706
+	 * resets the model and returns it
707
+	 *
708
+	 * @param null | string $timezone
709
+	 * @return EEM_Base|null (if the model was already instantiated, returns it, with
710
+	 * all its properties reset; if it wasn't instantiated, returns null)
711
+	 * @throws EE_Error
712
+	 * @throws ReflectionException
713
+	 * @throws InvalidArgumentException
714
+	 * @throws InvalidDataTypeException
715
+	 * @throws InvalidInterfaceException
716
+	 */
717
+	public static function reset($timezone = null)
718
+	{
719
+		if (static::$_instance instanceof EEM_Base) {
720
+			//let's try to NOT swap out the current instance for a new one
721
+			//because if someone has a reference to it, we can't remove their reference
722
+			//so it's best to keep using the same reference, but change the original object
723
+			//reset all its properties to their original values as defined in the class
724
+			$r = new ReflectionClass(get_class(static::$_instance));
725
+			$static_properties = $r->getStaticProperties();
726
+			foreach ($r->getDefaultProperties() as $property => $value) {
727
+				//don't set instance to null like it was originally,
728
+				//but it's static anyways, and we're ignoring static properties (for now at least)
729
+				if (! isset($static_properties[$property])) {
730
+					static::$_instance->{$property} = $value;
731
+				}
732
+			}
733
+			//and then directly call its constructor again, like we would if we were creating a new one
734
+			static::$_instance->__construct(
735
+				$timezone,
736
+				LoaderFactory::getLoader()->load('EventEspresso\core\services\orm\ModelFieldFactory')
737
+			);
738
+			return self::instance();
739
+		}
740
+		return null;
741
+	}
742
+
743
+
744
+
745
+	/**
746
+	 * @return LoaderInterface
747
+	 * @throws InvalidArgumentException
748
+	 * @throws InvalidDataTypeException
749
+	 * @throws InvalidInterfaceException
750
+	 */
751
+	private static function getLoader()
752
+	{
753
+		if(! EEM_Base::$loader instanceof LoaderInterface) {
754
+			EEM_Base::$loader = LoaderFactory::getLoader();
755
+		}
756
+		return EEM_Base::$loader;
757
+	}
758
+
759
+
760
+
761
+	/**
762
+	 * retrieve the status details from esp_status table as an array IF this model has the status table as a relation.
763
+	 *
764
+	 * @param  boolean $translated return localized strings or JUST the array.
765
+	 * @return array
766
+	 * @throws EE_Error
767
+	 * @throws InvalidArgumentException
768
+	 * @throws InvalidDataTypeException
769
+	 * @throws InvalidInterfaceException
770
+	 */
771
+	public function status_array($translated = false)
772
+	{
773
+		if (! array_key_exists('Status', $this->_model_relations)) {
774
+			return array();
775
+		}
776
+		$model_name = $this->get_this_model_name();
777
+		$status_type = str_replace(' ', '_', strtolower(str_replace('_', ' ', $model_name)));
778
+		$stati = EEM_Status::instance()->get_all(array(array('STS_type' => $status_type)));
779
+		$status_array = array();
780
+		foreach ($stati as $status) {
781
+			$status_array[$status->ID()] = $status->get('STS_code');
782
+		}
783
+		return $translated
784
+			? EEM_Status::instance()->localized_status($status_array, false, 'sentence')
785
+			: $status_array;
786
+	}
787
+
788
+
789
+
790
+	/**
791
+	 * Gets all the EE_Base_Class objects which match the $query_params, by querying the DB.
792
+	 *
793
+	 * @param array $query_params             {
794
+	 * @var array $0 (where) array {
795
+	 *                                        eg: array('QST_display_text'=>'Are you bob?','QST_admin_text'=>'Determine
796
+	 *                                        if user is bob') becomes SQL >> "...WHERE QST_display_text = 'Are you
797
+	 *                                        bob?' AND QST_admin_text = 'Determine if user is bob'...") To add WHERE
798
+	 *                                        conditions based on related models (and even
799
+	 *                                        models-related-to-related-models) prepend the model's name onto the field
800
+	 *                                        name. Eg,
801
+	 *                                        EEM_Event::instance()->get_all(array(array('Venue.VNU_ID'=>12))); becomes
802
+	 *                                        SQL >> "SELECT * FROM wp_posts AS Event_CPT LEFT JOIN wp_esp_event_meta
803
+	 *                                        AS Event_Meta ON Event_CPT.ID = Event_Meta.EVT_ID LEFT JOIN
804
+	 *                                        wp_esp_event_venue AS Event_Venue ON Event_Venue.EVT_ID=Event_CPT.ID LEFT
805
+	 *                                        JOIN wp_posts AS Venue_CPT ON Venue_CPT.ID=Event_Venue.VNU_ID LEFT JOIN
806
+	 *                                        wp_esp_venue_meta AS Venue_Meta ON Venue_CPT.ID = Venue_Meta.VNU_ID WHERE
807
+	 *                                        Venue_CPT.ID = 12 Notice that automatically took care of joining Events
808
+	 *                                        to Venues (even when each of those models actually consisted of two
809
+	 *                                        tables). Also, you may chain the model relations together. Eg instead of
810
+	 *                                        just having
811
+	 *                                        "Venue.VNU_ID", you could have
812
+	 *                                        "Registration.Attendee.ATT_ID" as a field on a query for events (because
813
+	 *                                        events are related to Registrations, which are related to Attendees). You
814
+	 *                                        can take it even further with
815
+	 *                                        "Registration.Transaction.Payment.PAY_amount" etc. To change the operator
816
+	 *                                        (from the default of '='), change the value to an numerically-indexed
817
+	 *                                        array, where the first item in the list is the operator. eg: array(
818
+	 *                                        'QST_display_text' => array('LIKE','%bob%'), 'QST_ID' => array('<',34),
819
+	 *                                        'QST_wp_user' => array('in',array(1,2,7,23))) becomes SQL >> "...WHERE
820
+	 *                                        QST_display_text LIKE '%bob%' AND QST_ID < 34 AND QST_wp_user IN
821
+	 *                                        (1,2,7,23)...". Valid operators so far: =, !=, <, <=, >, >=, LIKE, NOT
822
+	 *                                        LIKE, IN (followed by numeric-indexed array), NOT IN (dido), BETWEEN
823
+	 *                                        (followed by an array with exactly 2 date strings), IS NULL, and IS NOT
824
+	 *                                        NULL Values can be a string, int, or float. They can also be arrays IFF
825
+	 *                                        the operator is IN. Also, values can actually be field names. To indicate
826
+	 *                                        the value is a field, simply provide a third array item (true) to the
827
+	 *                                        operator-value array like so: eg: array( 'DTT_reg_limit' => array('>',
828
+	 *                                        'DTT_sold', TRUE) ) becomes SQL >> "...WHERE DTT_reg_limit > DTT_sold"
829
+	 *                                        Note: you can also use related model field names like you would any other
830
+	 *                                        field name. eg:
831
+	 *                                        array('Datetime.DTT_reg_limit'=>array('=','Datetime.DTT_sold',TRUE) could
832
+	 *                                        be used if you were querying EEM_Tickets (because Datetime is directly related to tickets) Also, by default all the where conditions are AND'd together. To override this, add an array key 'OR' (or 'AND') and the array to be OR'd together eg: array('OR'=>array('TXN_ID' => 23 , 'TXN_timestamp__>' =>
833
+	 *                                        345678912)) becomes SQL >> "...WHERE TXN_ID = 23 OR TXN_timestamp =
834
+	 *                                        345678912...". Also, to negate an entire set of conditions, use 'NOT' as
835
+	 *                                        an array key. eg: array('NOT'=>array('TXN_total' =>
836
+	 *                                        50, 'TXN_paid'=>23) becomes SQL >> "...where ! (TXN_total =50 AND
837
+	 *                                        TXN_paid =23) Note: the 'glue' used to join each condition will continue
838
+	 *                                        to be what you last specified. IE, "AND"s by default, but if you had
839
+	 *                                        previously specified to use ORs to join, ORs will continue to be used.
840
+	 *                                        So, if you specify to use an "OR" to join conditions, it will continue to
841
+	 *                                        "stick" until you specify an AND. eg
842
+	 *                                        array('OR'=>array('NOT'=>array('TXN_total' => 50,
843
+	 *                                        'TXN_paid'=>23)),AND=>array('TXN_ID'=>1,'STS_ID'=>'TIN') becomes SQL >>
844
+	 *                                        "...where ! (TXN_total =50 OR TXN_paid =23) AND TXN_ID=1 AND
845
+	 *                                        STS_ID='TIN'" They can be nested indefinitely. eg:
846
+	 *                                        array('OR'=>array('TXN_total' => 23, 'NOT'=> array( 'TXN_timestamp'=> 345678912, 'AND'=>array('TXN_paid' => 53, 'STS_ID' => 'TIN')))) becomes SQL >> "...WHERE TXN_total = 23 OR ! (TXN_timestamp = 345678912 OR (TXN_paid = 53 AND STS_ID = 'TIN'))..." GOTCHA: because this is an array, array keys must be unique, making it impossible to place two or more where conditions applying to the same field. eg: array('PAY_timestamp'=>array('>',$start_date),'PAY_timestamp'=>array('<',$end_date),'PAY_timestamp'=>array('!=',$special_date)), as PHP enforces that the array keys must be unique, thus removing the first two array entries with key 'PAY_timestamp'. becomes SQL >> "PAY_timestamp !=  4234232", ignoring the first two PAY_timestamp conditions). To overcome this, you can add a '*' character to the end of the field's name, followed by anything. These will be removed when generating the SQL string, but allow for the array keys to be unique. eg: you could rewrite the previous query as: array('PAY_timestamp'=>array('>',$start_date),'PAY_timestamp*1st'=>array('<',$end_date),'PAY_timestamp*2nd'=>array('!=',$special_date)) which correctly becomes SQL >>
847
+	 *                                        "PAY_timestamp > 123412341 AND PAY_timestamp < 2354235235234 AND
848
+	 *                                        PAY_timestamp != 1241234123" This can be applied to condition operators
849
+	 *                                        too, eg:
850
+	 *                                        array('OR'=>array('REG_ID'=>3,'Transaction.TXN_ID'=>23),'OR*whatever'=>array('Attendee.ATT_fname'=>'bob','Attendee.ATT_lname'=>'wilson')));
851
+	 * @var mixed   $limit                    int|array    adds a limit to the query just like the SQL limit clause, so
852
+	 *                                        limits of "23", "25,50", and array(23,42) are all valid would become SQL
853
+	 *                                        "...LIMIT 23", "...LIMIT 25,50", and "...LIMIT 23,42" respectively.
854
+	 *                                        Remember when you provide two numbers for the limit, the 1st number is
855
+	 *                                        the OFFSET, the 2nd is the LIMIT
856
+	 * @var array   $on_join_limit            allows the setting of a special select join with a internal limit so you
857
+	 *                                        can do paging on one-to-many multi-table-joins. Send an array in the
858
+	 *                                        following format array('on_join_limit'
859
+	 *                                        => array( 'table_alias', array(1,2) ) ).
860
+	 * @var mixed   $order_by                 name of a column to order by, or an array where keys are field names and
861
+	 *                                        values are either 'ASC' or 'DESC'.
862
+	 *                                        'limit'=>array('STS_ID'=>'ASC','REG_date'=>'DESC'), which would becomes
863
+	 *                                        SQL "...ORDER BY TXN_timestamp..." and "...ORDER BY STS_ID ASC, REG_date
864
+	 *                                        DESC..." respectively. Like the
865
+	 *                                        'where' conditions, these fields can be on related models. Eg
866
+	 *                                        'order_by'=>array('Registration.Transaction.TXN_amount'=>'ASC') is
867
+	 *                                        perfectly valid from any model related to 'Registration' (like Event,
868
+	 *                                        Attendee, Price, Datetime, etc.)
869
+	 * @var string  $order                    If 'order_by' is used and its value is a string (NOT an array), then
870
+	 *                                        'order' specifies whether to order the field specified in 'order_by' in
871
+	 *                                        ascending or descending order. Acceptable values are 'ASC' or 'DESC'. If,
872
+	 *                                        'order_by' isn't used, but 'order' is, then it is assumed you want to
873
+	 *                                        order by the primary key. Eg,
874
+	 *                                        EEM_Event::instance()->get_all(array('order_by'=>'Datetime.DTT_EVT_start','order'=>'ASC');
875
+	 *                                        //(will join with the Datetime model's table(s) and order by its field
876
+	 *                                        DTT_EVT_start) or
877
+	 *                                        EEM_Registration::instance()->get_all(array('order'=>'ASC'));//will make
878
+	 *                                        SQL "SELECT * FROM wp_esp_registration ORDER BY REG_ID ASC"
879
+	 * @var mixed   $group_by                 name of field to order by, or an array of fields. Eg either
880
+	 *                                        'group_by'=>'VNU_ID', or
881
+	 *                                        'group_by'=>array('EVT_name','Registration.Transaction.TXN_total') Note:
882
+	 *                                        if no
883
+	 *                                        $group_by is specified, and a limit is set, automatically groups by the
884
+	 *                                        model's primary key (or combined primary keys). This avoids some
885
+	 *                                        weirdness that results when using limits, tons of joins, and no group by,
886
+	 *                                        see https://events.codebasehq.com/projects/event-espresso/tickets/9389
887
+	 * @var array   $having                   exactly like WHERE parameters array, except these conditions apply to the
888
+	 *                                        grouped results (whereas WHERE conditions apply to the pre-grouped
889
+	 *                                        results)
890
+	 * @var array   $force_join               forces a join with the models named. Should be a numerically-indexed
891
+	 *                                        array where values are models to be joined in the query.Eg
892
+	 *                                        array('Attendee','Payment','Datetime'). You may join with transient
893
+	 *                                        models using period, eg "Registration.Transaction.Payment". You will
894
+	 *                                        probably only want to do this in hopes of increasing efficiency, as
895
+	 *                                        related models which belongs to the current model
896
+	 *                                        (ie, the current model has a foreign key to them, like how Registration
897
+	 *                                        belongs to Attendee) can be cached in order to avoid future queries
898
+	 * @var string  $default_where_conditions can be set to 'none', 'this_model_only', 'other_models_only', or 'all'.
899
+	 *                                        set this to 'none' to disable all default where conditions. Eg, usually
900
+	 *                                        soft-deleted objects are filtered-out if you want to include them, set
901
+	 *                                        this query param to 'none'. If you want to ONLY disable THIS model's
902
+	 *                                        default where conditions set it to 'other_models_only'. If you only want
903
+	 *                                        this model's default where conditions added to the query, use
904
+	 *                                        'this_model_only'. If you want to use all default where conditions
905
+	 *                                        (default), set to 'all'.
906
+	 * @var string  $caps                     controls what capability requirements to apply to the query; ie, should
907
+	 *                                        we just NOT apply any capabilities/permissions/restrictions and return
908
+	 *                                        everything? Or should we only show the current user items they should be
909
+	 *                                        able to view on the frontend, backend, edit, or delete? can be set to
910
+	 *                                        'none' (default), 'read_frontend', 'read_backend', 'edit' or 'delete'
911
+	 *                                        }
912
+	 * @return EE_Base_Class[]  *note that there is NO option to pass the output type. If you want results different
913
+	 *                                        from EE_Base_Class[], use _get_all_wpdb_results()and make it public
914
+	 *                                        again. Array keys are object IDs (if there is a primary key on the model.
915
+	 *                                        if not, numerically indexed) Some full examples: get 10 transactions
916
+	 *                                        which have Scottish attendees: EEM_Transaction::instance()->get_all(
917
+	 *                                        array( array(
918
+	 *                                        'OR'=>array(
919
+	 *                                        'Registration.Attendee.ATT_fname'=>array('like','Mc%'),
920
+	 *                                        'Registration.Attendee.ATT_fname*other'=>array('like','Mac%')
921
+	 *                                        )
922
+	 *                                        ),
923
+	 *                                        'limit'=>10,
924
+	 *                                        'group_by'=>'TXN_ID'
925
+	 *                                        ));
926
+	 *                                        get all the answers to the question titled "shirt size" for event with id
927
+	 *                                        12, ordered by their answer EEM_Answer::instance()->get_all(array( array(
928
+	 *                                        'Question.QST_display_text'=>'shirt size',
929
+	 *                                        'Registration.Event.EVT_ID'=>12
930
+	 *                                        ),
931
+	 *                                        'order_by'=>array('ANS_value'=>'ASC')
932
+	 *                                        ));
933
+	 * @throws EE_Error
934
+	 */
935
+	public function get_all($query_params = array())
936
+	{
937
+		if (isset($query_params['limit'])
938
+			&& ! isset($query_params['group_by'])
939
+		) {
940
+			$query_params['group_by'] = array_keys($this->get_combined_primary_key_fields());
941
+		}
942
+		return $this->_create_objects($this->_get_all_wpdb_results($query_params, ARRAY_A, null));
943
+	}
944
+
945
+
946
+
947
+	/**
948
+	 * Modifies the query parameters so we only get back model objects
949
+	 * that "belong" to the current user
950
+	 *
951
+	 * @param array $query_params @see EEM_Base::get_all()
952
+	 * @return array like EEM_Base::get_all
953
+	 */
954
+	public function alter_query_params_to_only_include_mine($query_params = array())
955
+	{
956
+		$wp_user_field_name = $this->wp_user_field_name();
957
+		if ($wp_user_field_name) {
958
+			$query_params[0][$wp_user_field_name] = get_current_user_id();
959
+		}
960
+		return $query_params;
961
+	}
962
+
963
+
964
+
965
+	/**
966
+	 * Returns the name of the field's name that points to the WP_User table
967
+	 *  on this model (or follows the _model_chain_to_wp_user and uses that model's
968
+	 * foreign key to the WP_User table)
969
+	 *
970
+	 * @return string|boolean string on success, boolean false when there is no
971
+	 * foreign key to the WP_User table
972
+	 */
973
+	public function wp_user_field_name()
974
+	{
975
+		try {
976
+			if (! empty($this->_model_chain_to_wp_user)) {
977
+				$models_to_follow_to_wp_users = explode('.', $this->_model_chain_to_wp_user);
978
+				$last_model_name = end($models_to_follow_to_wp_users);
979
+				$model_with_fk_to_wp_users = EE_Registry::instance()->load_model($last_model_name);
980
+				$model_chain_to_wp_user = $this->_model_chain_to_wp_user . '.';
981
+			} else {
982
+				$model_with_fk_to_wp_users = $this;
983
+				$model_chain_to_wp_user = '';
984
+			}
985
+			$wp_user_field = $model_with_fk_to_wp_users->get_foreign_key_to('WP_User');
986
+			return $model_chain_to_wp_user . $wp_user_field->get_name();
987
+		} catch (EE_Error $e) {
988
+			return false;
989
+		}
990
+	}
991
+
992
+
993
+
994
+	/**
995
+	 * Returns the _model_chain_to_wp_user string, which indicates which related model
996
+	 * (or transiently-related model) has a foreign key to the wp_users table;
997
+	 * useful for finding if model objects of this type are 'owned' by the current user.
998
+	 * This is an empty string when the foreign key is on this model and when it isn't,
999
+	 * but is only non-empty when this model's ownership is indicated by a RELATED model
1000
+	 * (or transiently-related model)
1001
+	 *
1002
+	 * @return string
1003
+	 */
1004
+	public function model_chain_to_wp_user()
1005
+	{
1006
+		return $this->_model_chain_to_wp_user;
1007
+	}
1008
+
1009
+
1010
+
1011
+	/**
1012
+	 * Whether this model is 'owned' by a specific wordpress user (even indirectly,
1013
+	 * like how registrations don't have a foreign key to wp_users, but the
1014
+	 * events they are for are), or is unrelated to wp users.
1015
+	 * generally available
1016
+	 *
1017
+	 * @return boolean
1018
+	 */
1019
+	public function is_owned()
1020
+	{
1021
+		if ($this->model_chain_to_wp_user()) {
1022
+			return true;
1023
+		}
1024
+		try {
1025
+			$this->get_foreign_key_to('WP_User');
1026
+			return true;
1027
+		} catch (EE_Error $e) {
1028
+			return false;
1029
+		}
1030
+	}
1031
+
1032
+
1033
+
1034
+	/**
1035
+	 * Used internally to get WPDB results, because other functions, besides get_all, may want to do some queries, but
1036
+	 * may want to preserve the WPDB results (eg, update, which first queries to make sure we have all the tables on
1037
+	 * the model)
1038
+	 *
1039
+	 * @param array  $query_params      like EEM_Base::get_all's $query_params
1040
+	 * @param string $output            ARRAY_A, OBJECT_K, etc. Just like
1041
+	 * @param mixed  $columns_to_select , What columns to select. By default, we select all columns specified by the
1042
+	 *                                  fields on the model, and the models we joined to in the query. However, you can
1043
+	 *                                  override this and set the select to "*", or a specific column name, like
1044
+	 *                                  "ATT_ID", etc. If you would like to use these custom selections in WHERE,
1045
+	 *                                  GROUP_BY, or HAVING clauses, you must instead provide an array. Array keys are
1046
+	 *                                  the aliases used to refer to this selection, and values are to be
1047
+	 *                                  numerically-indexed arrays, where 0 is the selection and 1 is the data type.
1048
+	 *                                  Eg, array('count'=>array('COUNT(REG_ID)','%d'))
1049
+	 * @return array | stdClass[] like results of $wpdb->get_results($sql,OBJECT), (ie, output type is OBJECT)
1050
+	 * @throws EE_Error
1051
+	 */
1052
+	protected function _get_all_wpdb_results($query_params = array(), $output = ARRAY_A, $columns_to_select = null)
1053
+	{
1054
+		// remember the custom selections, if any, and type cast as array
1055
+		// (unless $columns_to_select is an object, then just set as an empty array)
1056
+		// Note: (array) 'some string' === array( 'some string' )
1057
+		$this->_custom_selections = ! is_object($columns_to_select) ? (array)$columns_to_select : array();
1058
+		$model_query_info = $this->_create_model_query_info_carrier($query_params);
1059
+		$select_expressions = $columns_to_select !== null
1060
+			? $this->_construct_select_from_input($columns_to_select)
1061
+			: $this->_construct_default_select_sql($model_query_info);
1062
+		$SQL = "SELECT $select_expressions " . $this->_construct_2nd_half_of_select_query($model_query_info);
1063
+		return $this->_do_wpdb_query('get_results', array($SQL, $output));
1064
+	}
1065
+
1066
+
1067
+
1068
+	/**
1069
+	 * Gets an array of rows from the database just like $wpdb->get_results would,
1070
+	 * but you can use the $query_params like on EEM_Base::get_all() to more easily
1071
+	 * take care of joins, field preparation etc.
1072
+	 *
1073
+	 * @param array  $query_params      like EEM_Base::get_all's $query_params
1074
+	 * @param string $output            ARRAY_A, OBJECT_K, etc. Just like
1075
+	 * @param mixed  $columns_to_select , What columns to select. By default, we select all columns specified by the
1076
+	 *                                  fields on the model, and the models we joined to in the query. However, you can
1077
+	 *                                  override this and set the select to "*", or a specific column name, like
1078
+	 *                                  "ATT_ID", etc. If you would like to use these custom selections in WHERE,
1079
+	 *                                  GROUP_BY, or HAVING clauses, you must instead provide an array. Array keys are
1080
+	 *                                  the aliases used to refer to this selection, and values are to be
1081
+	 *                                  numerically-indexed arrays, where 0 is the selection and 1 is the data type.
1082
+	 *                                  Eg, array('count'=>array('COUNT(REG_ID)','%d'))
1083
+	 * @return array|stdClass[] like results of $wpdb->get_results($sql,OBJECT), (ie, output type is OBJECT)
1084
+	 * @throws EE_Error
1085
+	 */
1086
+	public function get_all_wpdb_results($query_params = array(), $output = ARRAY_A, $columns_to_select = null)
1087
+	{
1088
+		return $this->_get_all_wpdb_results($query_params, $output, $columns_to_select);
1089
+	}
1090
+
1091
+
1092
+
1093
+	/**
1094
+	 * For creating a custom select statement
1095
+	 *
1096
+	 * @param mixed $columns_to_select either a string to be inserted directly as the select statement,
1097
+	 *                                 or an array where keys are aliases, and values are arrays where 0=>the selection
1098
+	 *                                 SQL, and 1=>is the datatype
1099
+	 * @throws EE_Error
1100
+	 * @return string
1101
+	 */
1102
+	private function _construct_select_from_input($columns_to_select)
1103
+	{
1104
+		if (is_array($columns_to_select)) {
1105
+			$select_sql_array = array();
1106
+			foreach ($columns_to_select as $alias => $selection_and_datatype) {
1107
+				if (! is_array($selection_and_datatype) || ! isset($selection_and_datatype[1])) {
1108
+					throw new EE_Error(
1109
+						sprintf(
1110
+							__(
1111
+								"Custom selection %s (alias %s) needs to be an array like array('COUNT(REG_ID)','%%d')",
1112
+								'event_espresso'
1113
+							),
1114
+							$selection_and_datatype,
1115
+							$alias
1116
+						)
1117
+					);
1118
+				}
1119
+				if (! in_array($selection_and_datatype[1], $this->_valid_wpdb_data_types, true)) {
1120
+					throw new EE_Error(
1121
+						sprintf(
1122
+							esc_html__(
1123
+								"Datatype %s (for selection '%s' and alias '%s') is not a valid wpdb datatype (eg %%s)",
1124
+								'event_espresso'
1125
+							),
1126
+							$selection_and_datatype[1],
1127
+							$selection_and_datatype[0],
1128
+							$alias,
1129
+							implode(', ', $this->_valid_wpdb_data_types)
1130
+						)
1131
+					);
1132
+				}
1133
+				$select_sql_array[] = "{$selection_and_datatype[0]} AS $alias";
1134
+			}
1135
+			$columns_to_select_string = implode(', ', $select_sql_array);
1136
+		} else {
1137
+			$columns_to_select_string = $columns_to_select;
1138
+		}
1139
+		return $columns_to_select_string;
1140
+	}
1141
+
1142
+
1143
+
1144
+	/**
1145
+	 * Convenient wrapper for getting the primary key field's name. Eg, on Registration, this would be 'REG_ID'
1146
+	 *
1147
+	 * @return string
1148
+	 * @throws EE_Error
1149
+	 */
1150
+	public function primary_key_name()
1151
+	{
1152
+		return $this->get_primary_key_field()->get_name();
1153
+	}
1154
+
1155
+
1156
+
1157
+	/**
1158
+	 * Gets a single item for this model from the DB, given only its ID (or null if none is found).
1159
+	 * If there is no primary key on this model, $id is treated as primary key string
1160
+	 *
1161
+	 * @param mixed $id int or string, depending on the type of the model's primary key
1162
+	 * @return EE_Base_Class
1163
+	 */
1164
+	public function get_one_by_ID($id)
1165
+	{
1166
+		if ($this->get_from_entity_map($id)) {
1167
+			return $this->get_from_entity_map($id);
1168
+		}
1169
+		return $this->get_one(
1170
+			$this->alter_query_params_to_restrict_by_ID(
1171
+				$id,
1172
+				array('default_where_conditions' => EEM_Base::default_where_conditions_minimum_all)
1173
+			)
1174
+		);
1175
+	}
1176
+
1177
+
1178
+
1179
+	/**
1180
+	 * Alters query parameters to only get items with this ID are returned.
1181
+	 * Takes into account that the ID might be a string produced by EEM_Base::get_index_primary_key_string(),
1182
+	 * or could just be a simple primary key ID
1183
+	 *
1184
+	 * @param int   $id
1185
+	 * @param array $query_params
1186
+	 * @return array of normal query params, @see EEM_Base::get_all
1187
+	 * @throws EE_Error
1188
+	 */
1189
+	public function alter_query_params_to_restrict_by_ID($id, $query_params = array())
1190
+	{
1191
+		if (! isset($query_params[0])) {
1192
+			$query_params[0] = array();
1193
+		}
1194
+		$conditions_from_id = $this->parse_index_primary_key_string($id);
1195
+		if ($conditions_from_id === null) {
1196
+			$query_params[0][$this->primary_key_name()] = $id;
1197
+		} else {
1198
+			//no primary key, so the $id must be from the get_index_primary_key_string()
1199
+			$query_params[0] = array_replace_recursive($query_params[0], $this->parse_index_primary_key_string($id));
1200
+		}
1201
+		return $query_params;
1202
+	}
1203
+
1204
+
1205
+
1206
+	/**
1207
+	 * Gets a single item for this model from the DB, given the $query_params. Only returns a single class, not an
1208
+	 * array. If no item is found, null is returned.
1209
+	 *
1210
+	 * @param array $query_params like EEM_Base's $query_params variable.
1211
+	 * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1212
+	 * @throws EE_Error
1213
+	 */
1214
+	public function get_one($query_params = array())
1215
+	{
1216
+		if (! is_array($query_params)) {
1217
+			EE_Error::doing_it_wrong('EEM_Base::get_one',
1218
+				sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
1219
+					gettype($query_params)), '4.6.0');
1220
+			$query_params = array();
1221
+		}
1222
+		$query_params['limit'] = 1;
1223
+		$items = $this->get_all($query_params);
1224
+		if (empty($items)) {
1225
+			return null;
1226
+		}
1227
+		return array_shift($items);
1228
+	}
1229
+
1230
+
1231
+
1232
+	/**
1233
+	 * Returns the next x number of items in sequence from the given value as
1234
+	 * found in the database matching the given query conditions.
1235
+	 *
1236
+	 * @param mixed $current_field_value    Value used for the reference point.
1237
+	 * @param null  $field_to_order_by      What field is used for the
1238
+	 *                                      reference point.
1239
+	 * @param int   $limit                  How many to return.
1240
+	 * @param array $query_params           Extra conditions on the query.
1241
+	 * @param null  $columns_to_select      If left null, then an array of
1242
+	 *                                      EE_Base_Class objects is returned,
1243
+	 *                                      otherwise you can indicate just the
1244
+	 *                                      columns you want returned.
1245
+	 * @return EE_Base_Class[]|array
1246
+	 * @throws EE_Error
1247
+	 */
1248
+	public function next_x(
1249
+		$current_field_value,
1250
+		$field_to_order_by = null,
1251
+		$limit = 1,
1252
+		$query_params = array(),
1253
+		$columns_to_select = null
1254
+	) {
1255
+		return $this->_get_consecutive(
1256
+			$current_field_value,
1257
+			'>',
1258
+			$field_to_order_by,
1259
+			$limit,
1260
+			$query_params,
1261
+			$columns_to_select
1262
+		);
1263
+	}
1264
+
1265
+
1266
+
1267
+	/**
1268
+	 * Returns the previous x number of items in sequence from the given value
1269
+	 * as found in the database matching the given query conditions.
1270
+	 *
1271
+	 * @param mixed $current_field_value    Value used for the reference point.
1272
+	 * @param null  $field_to_order_by      What field is used for the
1273
+	 *                                      reference point.
1274
+	 * @param int   $limit                  How many to return.
1275
+	 * @param array $query_params           Extra conditions on the query.
1276
+	 * @param null  $columns_to_select      If left null, then an array of
1277
+	 *                                      EE_Base_Class objects is returned,
1278
+	 *                                      otherwise you can indicate just the
1279
+	 *                                      columns you want returned.
1280
+	 * @return EE_Base_Class[]|array
1281
+	 * @throws EE_Error
1282
+	 */
1283
+	public function previous_x(
1284
+		$current_field_value,
1285
+		$field_to_order_by = null,
1286
+		$limit = 1,
1287
+		$query_params = array(),
1288
+		$columns_to_select = null
1289
+	) {
1290
+		return $this->_get_consecutive(
1291
+			$current_field_value,
1292
+			'<',
1293
+			$field_to_order_by,
1294
+			$limit,
1295
+			$query_params,
1296
+			$columns_to_select
1297
+		);
1298
+	}
1299
+
1300
+
1301
+
1302
+	/**
1303
+	 * Returns the next item in sequence from the given value as found in the
1304
+	 * database matching the given query conditions.
1305
+	 *
1306
+	 * @param mixed $current_field_value    Value used for the reference point.
1307
+	 * @param null  $field_to_order_by      What field is used for the
1308
+	 *                                      reference point.
1309
+	 * @param array $query_params           Extra conditions on the query.
1310
+	 * @param null  $columns_to_select      If left null, then an EE_Base_Class
1311
+	 *                                      object is returned, otherwise you
1312
+	 *                                      can indicate just the columns you
1313
+	 *                                      want and a single array indexed by
1314
+	 *                                      the columns will be returned.
1315
+	 * @return EE_Base_Class|null|array()
1316
+	 * @throws EE_Error
1317
+	 */
1318
+	public function next(
1319
+		$current_field_value,
1320
+		$field_to_order_by = null,
1321
+		$query_params = array(),
1322
+		$columns_to_select = null
1323
+	) {
1324
+		$results = $this->_get_consecutive(
1325
+			$current_field_value,
1326
+			'>',
1327
+			$field_to_order_by,
1328
+			1,
1329
+			$query_params,
1330
+			$columns_to_select
1331
+		);
1332
+		return empty($results) ? null : reset($results);
1333
+	}
1334
+
1335
+
1336
+
1337
+	/**
1338
+	 * Returns the previous item in sequence from the given value as found in
1339
+	 * the database matching the given query conditions.
1340
+	 *
1341
+	 * @param mixed $current_field_value    Value used for the reference point.
1342
+	 * @param null  $field_to_order_by      What field is used for the
1343
+	 *                                      reference point.
1344
+	 * @param array $query_params           Extra conditions on the query.
1345
+	 * @param null  $columns_to_select      If left null, then an EE_Base_Class
1346
+	 *                                      object is returned, otherwise you
1347
+	 *                                      can indicate just the columns you
1348
+	 *                                      want and a single array indexed by
1349
+	 *                                      the columns will be returned.
1350
+	 * @return EE_Base_Class|null|array()
1351
+	 * @throws EE_Error
1352
+	 */
1353
+	public function previous(
1354
+		$current_field_value,
1355
+		$field_to_order_by = null,
1356
+		$query_params = array(),
1357
+		$columns_to_select = null
1358
+	) {
1359
+		$results = $this->_get_consecutive(
1360
+			$current_field_value,
1361
+			'<',
1362
+			$field_to_order_by,
1363
+			1,
1364
+			$query_params,
1365
+			$columns_to_select
1366
+		);
1367
+		return empty($results) ? null : reset($results);
1368
+	}
1369
+
1370
+
1371
+
1372
+	/**
1373
+	 * Returns the a consecutive number of items in sequence from the given
1374
+	 * value as found in the database matching the given query conditions.
1375
+	 *
1376
+	 * @param mixed  $current_field_value   Value used for the reference point.
1377
+	 * @param string $operand               What operand is used for the sequence.
1378
+	 * @param string $field_to_order_by     What field is used for the reference point.
1379
+	 * @param int    $limit                 How many to return.
1380
+	 * @param array  $query_params          Extra conditions on the query.
1381
+	 * @param null   $columns_to_select     If left null, then an array of EE_Base_Class objects is returned,
1382
+	 *                                      otherwise you can indicate just the columns you want returned.
1383
+	 * @return EE_Base_Class[]|array
1384
+	 * @throws EE_Error
1385
+	 */
1386
+	protected function _get_consecutive(
1387
+		$current_field_value,
1388
+		$operand = '>',
1389
+		$field_to_order_by = null,
1390
+		$limit = 1,
1391
+		$query_params = array(),
1392
+		$columns_to_select = null
1393
+	) {
1394
+		//if $field_to_order_by is empty then let's assume we're ordering by the primary key.
1395
+		if (empty($field_to_order_by)) {
1396
+			if ($this->has_primary_key_field()) {
1397
+				$field_to_order_by = $this->get_primary_key_field()->get_name();
1398
+			} else {
1399
+				if (WP_DEBUG) {
1400
+					throw new EE_Error(__('EEM_Base::_get_consecutive() has been called with no $field_to_order_by argument and there is no primary key on the field.  Please provide the field you would like to use as the base for retrieving the next item(s).',
1401
+						'event_espresso'));
1402
+				}
1403
+				EE_Error::add_error(__('There was an error with the query.', 'event_espresso'));
1404
+				return array();
1405
+			}
1406
+		}
1407
+		if (! is_array($query_params)) {
1408
+			EE_Error::doing_it_wrong('EEM_Base::_get_consecutive',
1409
+				sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
1410
+					gettype($query_params)), '4.6.0');
1411
+			$query_params = array();
1412
+		}
1413
+		//let's add the where query param for consecutive look up.
1414
+		$query_params[0][$field_to_order_by] = array($operand, $current_field_value);
1415
+		$query_params['limit'] = $limit;
1416
+		//set direction
1417
+		$incoming_orderby = isset($query_params['order_by']) ? (array)$query_params['order_by'] : array();
1418
+		$query_params['order_by'] = $operand === '>'
1419
+			? array($field_to_order_by => 'ASC') + $incoming_orderby
1420
+			: array($field_to_order_by => 'DESC') + $incoming_orderby;
1421
+		//if $columns_to_select is empty then that means we're returning EE_Base_Class objects
1422
+		if (empty($columns_to_select)) {
1423
+			return $this->get_all($query_params);
1424
+		}
1425
+		//getting just the fields
1426
+		return $this->_get_all_wpdb_results($query_params, ARRAY_A, $columns_to_select);
1427
+	}
1428
+
1429
+
1430
+
1431
+	/**
1432
+	 * This sets the _timezone property after model object has been instantiated.
1433
+	 *
1434
+	 * @param null | string $timezone valid PHP DateTimeZone timezone string
1435
+	 */
1436
+	public function set_timezone($timezone)
1437
+	{
1438
+		if ($timezone !== null) {
1439
+			$this->_timezone = $timezone;
1440
+		}
1441
+		//note we need to loop through relations and set the timezone on those objects as well.
1442
+		foreach ($this->_model_relations as $relation) {
1443
+			$relation->set_timezone($timezone);
1444
+		}
1445
+		//and finally we do the same for any datetime fields
1446
+		foreach ($this->_fields as $field) {
1447
+			if ($field instanceof EE_Datetime_Field) {
1448
+				$field->set_timezone($timezone);
1449
+			}
1450
+		}
1451
+	}
1452
+
1453
+
1454
+
1455
+	/**
1456
+	 * This just returns whatever is set for the current timezone.
1457
+	 *
1458
+	 * @access public
1459
+	 * @return string
1460
+	 */
1461
+	public function get_timezone()
1462
+	{
1463
+		//first validate if timezone is set.  If not, then let's set it be whatever is set on the model fields.
1464
+		if (empty($this->_timezone)) {
1465
+			foreach ($this->_fields as $field) {
1466
+				if ($field instanceof EE_Datetime_Field) {
1467
+					$this->set_timezone($field->get_timezone());
1468
+					break;
1469
+				}
1470
+			}
1471
+		}
1472
+		//if timezone STILL empty then return the default timezone for the site.
1473
+		if (empty($this->_timezone)) {
1474
+			$this->set_timezone(EEH_DTT_Helper::get_timezone());
1475
+		}
1476
+		return $this->_timezone;
1477
+	}
1478
+
1479
+
1480
+
1481
+	/**
1482
+	 * This returns the date formats set for the given field name and also ensures that
1483
+	 * $this->_timezone property is set correctly.
1484
+	 *
1485
+	 * @since 4.6.x
1486
+	 * @param string $field_name The name of the field the formats are being retrieved for.
1487
+	 * @param bool   $pretty     Whether to return the pretty formats (true) or not (false).
1488
+	 * @throws EE_Error   If the given field_name is not of the EE_Datetime_Field type.
1489
+	 * @return array formats in an array with the date format first, and the time format last.
1490
+	 */
1491
+	public function get_formats_for($field_name, $pretty = false)
1492
+	{
1493
+		$field_settings = $this->field_settings_for($field_name);
1494
+		//if not a valid EE_Datetime_Field then throw error
1495
+		if (! $field_settings instanceof EE_Datetime_Field) {
1496
+			throw new EE_Error(sprintf(__('The field sent into EEM_Base::get_formats_for (%s) is not registered as a EE_Datetime_Field. Please check the spelling and make sure you are submitting the right field name to retrieve date_formats for.',
1497
+				'event_espresso'), $field_name));
1498
+		}
1499
+		//while we are here, let's make sure the timezone internally in EEM_Base matches what is stored on
1500
+		//the field.
1501
+		$this->_timezone = $field_settings->get_timezone();
1502
+		return array($field_settings->get_date_format($pretty), $field_settings->get_time_format($pretty));
1503
+	}
1504
+
1505
+
1506
+
1507
+	/**
1508
+	 * This returns the current time in a format setup for a query on this model.
1509
+	 * Usage of this method makes it easier to setup queries against EE_Datetime_Field columns because
1510
+	 * it will return:
1511
+	 *  - a formatted string in the timezone and format currently set on the EE_Datetime_Field for the given field for
1512
+	 *  NOW
1513
+	 *  - or a unix timestamp (equivalent to time())
1514
+	 * Note: When requesting a formatted string, if the date or time format doesn't include seconds, for example,
1515
+	 * the time returned, because it uses that format, will also NOT include seconds. For this reason, if you want
1516
+	 * the time returned to be the current time down to the exact second, set $timestamp to true.
1517
+	 * @since 4.6.x
1518
+	 * @param string $field_name       The field the current time is needed for.
1519
+	 * @param bool   $timestamp        True means to return a unix timestamp. Otherwise a
1520
+	 *                                 formatted string matching the set format for the field in the set timezone will
1521
+	 *                                 be returned.
1522
+	 * @param string $what             Whether to return the string in just the time format, the date format, or both.
1523
+	 * @throws EE_Error    If the given field_name is not of the EE_Datetime_Field type.
1524
+	 * @return int|string  If the given field_name is not of the EE_Datetime_Field type, then an EE_Error
1525
+	 *                                 exception is triggered.
1526
+	 */
1527
+	public function current_time_for_query($field_name, $timestamp = false, $what = 'both')
1528
+	{
1529
+		$formats = $this->get_formats_for($field_name);
1530
+		$DateTime = new DateTime("now", new DateTimeZone($this->_timezone));
1531
+		if ($timestamp) {
1532
+			return $DateTime->format('U');
1533
+		}
1534
+		//not returning timestamp, so return formatted string in timezone.
1535
+		switch ($what) {
1536
+			case 'time' :
1537
+				return $DateTime->format($formats[1]);
1538
+				break;
1539
+			case 'date' :
1540
+				return $DateTime->format($formats[0]);
1541
+				break;
1542
+			default :
1543
+				return $DateTime->format(implode(' ', $formats));
1544
+				break;
1545
+		}
1546
+	}
1547
+
1548
+
1549
+
1550
+	/**
1551
+	 * This receives a time string for a given field and ensures that it is setup to match what the internal settings
1552
+	 * for the model are.  Returns a DateTime object.
1553
+	 * Note: a gotcha for when you send in unix timestamp.  Remember a unix timestamp is already timezone agnostic,
1554
+	 * (functionally the equivalent of UTC+0).  So when you send it in, whatever timezone string you include is
1555
+	 * ignored.
1556
+	 *
1557
+	 * @param string $field_name      The field being setup.
1558
+	 * @param string $timestring      The date time string being used.
1559
+	 * @param string $incoming_format The format for the time string.
1560
+	 * @param string $timezone        By default, it is assumed the incoming time string is in timezone for
1561
+	 *                                the blog.  If this is not the case, then it can be specified here.  If incoming
1562
+	 *                                format is
1563
+	 *                                'U', this is ignored.
1564
+	 * @return DateTime
1565
+	 * @throws EE_Error
1566
+	 */
1567
+	public function convert_datetime_for_query($field_name, $timestring, $incoming_format, $timezone = '')
1568
+	{
1569
+		//just using this to ensure the timezone is set correctly internally
1570
+		$this->get_formats_for($field_name);
1571
+		//load EEH_DTT_Helper
1572
+		$set_timezone = empty($timezone) ? EEH_DTT_Helper::get_timezone() : $timezone;
1573
+		$incomingDateTime = date_create_from_format($incoming_format, $timestring, new DateTimeZone($set_timezone));
1574
+		return \EventEspresso\core\domain\entities\DbSafeDateTime::createFromDateTime( $incomingDateTime->setTimezone(new DateTimeZone($this->_timezone)) );
1575
+	}
1576
+
1577
+
1578
+
1579
+	/**
1580
+	 * Gets all the tables comprising this model. Array keys are the table aliases, and values are EE_Table objects
1581
+	 *
1582
+	 * @return EE_Table_Base[]
1583
+	 */
1584
+	public function get_tables()
1585
+	{
1586
+		return $this->_tables;
1587
+	}
1588
+
1589
+
1590
+
1591
+	/**
1592
+	 * Updates all the database entries (in each table for this model) according to $fields_n_values and optionally
1593
+	 * also updates all the model objects, where the criteria expressed in $query_params are met..
1594
+	 * Also note: if this model has multiple tables, this update verifies all the secondary tables have an entry for
1595
+	 * each row (in the primary table) we're trying to update; if not, it inserts an entry in the secondary table. Eg:
1596
+	 * if our model has 2 tables: wp_posts (primary), and wp_esp_event (secondary). Let's say we are trying to update a
1597
+	 * model object with EVT_ID = 1
1598
+	 * (which means where wp_posts has ID = 1, because wp_posts.ID is the primary key's column), which exists, but
1599
+	 * there is no entry in wp_esp_event for this entry in wp_posts. So, this update script will insert a row into
1600
+	 * wp_esp_event, using any available parameters from $fields_n_values (eg, if "EVT_limit" => 40 is in
1601
+	 * $fields_n_values, the new entry in wp_esp_event will set EVT_limit = 40, and use default for other columns which
1602
+	 * are not specified)
1603
+	 *
1604
+	 * @param array   $fields_n_values         keys are model fields (exactly like keys in EEM_Base::_fields, NOT db
1605
+	 *                                         columns!), values are strings, ints, floats, and maybe arrays if they
1606
+	 *                                         are to be serialized. Basically, the values are what you'd expect to be
1607
+	 *                                         values on the model, NOT necessarily what's in the DB. For example, if
1608
+	 *                                         we wanted to update only the TXN_details on any Transactions where its
1609
+	 *                                         ID=34, we'd use this method as follows:
1610
+	 *                                         EEM_Transaction::instance()->update(
1611
+	 *                                         array('TXN_details'=>array('detail1'=>'monkey','detail2'=>'banana'),
1612
+	 *                                         array(array('TXN_ID'=>34)));
1613
+	 * @param array   $query_params            very much like EEM_Base::get_all's $query_params
1614
+	 *                                         in client code into what's expected to be stored on each field. Eg,
1615
+	 *                                         consider updating Question's QST_admin_label field is of type
1616
+	 *                                         Simple_HTML. If you use this function to update that field to $new_value
1617
+	 *                                         = (note replace 8's with appropriate opening and closing tags in the
1618
+	 *                                         following example)"8script8alert('I hack all');8/script88b8boom
1619
+	 *                                         baby8/b8", then if you set $values_already_prepared_by_model_object to
1620
+	 *                                         TRUE, it is assumed that you've already called
1621
+	 *                                         EE_Simple_HTML_Field->prepare_for_set($new_value), which removes the
1622
+	 *                                         malicious javascript. However, if
1623
+	 *                                         $values_already_prepared_by_model_object is left as FALSE, then
1624
+	 *                                         EE_Simple_HTML_Field->prepare_for_set($new_value) will be called on it,
1625
+	 *                                         and every other field, before insertion. We provide this parameter
1626
+	 *                                         because model objects perform their prepare_for_set function on all
1627
+	 *                                         their values, and so don't need to be called again (and in many cases,
1628
+	 *                                         shouldn't be called again. Eg: if we escape HTML characters in the
1629
+	 *                                         prepare_for_set method...)
1630
+	 * @param boolean $keep_model_objs_in_sync if TRUE, makes sure we ALSO update model objects
1631
+	 *                                         in this model's entity map according to $fields_n_values that match
1632
+	 *                                         $query_params. This obviously has some overhead, so you can disable it
1633
+	 *                                         by setting this to FALSE, but be aware that model objects being used
1634
+	 *                                         could get out-of-sync with the database
1635
+	 * @return int how many rows got updated or FALSE if something went wrong with the query (wp returns FALSE or num
1636
+	 *                                         rows affected which *could* include 0 which DOES NOT mean the query was
1637
+	 *                                         bad)
1638
+	 * @throws EE_Error
1639
+	 */
1640
+	public function update($fields_n_values, $query_params, $keep_model_objs_in_sync = true)
1641
+	{
1642
+		if (! is_array($query_params)) {
1643
+			EE_Error::doing_it_wrong('EEM_Base::update',
1644
+				sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
1645
+					gettype($query_params)), '4.6.0');
1646
+			$query_params = array();
1647
+		}
1648
+		/**
1649
+		 * Action called before a model update call has been made.
1650
+		 *
1651
+		 * @param EEM_Base $model
1652
+		 * @param array    $fields_n_values the updated fields and their new values
1653
+		 * @param array    $query_params    @see EEM_Base::get_all()
1654
+		 */
1655
+		do_action('AHEE__EEM_Base__update__begin', $this, $fields_n_values, $query_params);
1656
+		/**
1657
+		 * Filters the fields about to be updated given the query parameters. You can provide the
1658
+		 * $query_params to $this->get_all() to find exactly which records will be updated
1659
+		 *
1660
+		 * @param array    $fields_n_values fields and their new values
1661
+		 * @param EEM_Base $model           the model being queried
1662
+		 * @param array    $query_params    see EEM_Base::get_all()
1663
+		 */
1664
+		$fields_n_values = (array)apply_filters('FHEE__EEM_Base__update__fields_n_values', $fields_n_values, $this,
1665
+			$query_params);
1666
+		//need to verify that, for any entry we want to update, there are entries in each secondary table.
1667
+		//to do that, for each table, verify that it's PK isn't null.
1668
+		$tables = $this->get_tables();
1669
+		//and if the other tables don't have a row for each table-to-be-updated, we'll insert one with whatever values available in the current update query
1670
+		//NOTE: we should make this code more efficient by NOT querying twice
1671
+		//before the real update, but that needs to first go through ALPHA testing
1672
+		//as it's dangerous. says Mike August 8 2014
1673
+		//we want to make sure the default_where strategy is ignored
1674
+		$this->_ignore_where_strategy = true;
1675
+		$wpdb_select_results = $this->_get_all_wpdb_results($query_params);
1676
+		foreach ($wpdb_select_results as $wpdb_result) {
1677
+			// type cast stdClass as array
1678
+			$wpdb_result = (array)$wpdb_result;
1679
+			//get the model object's PK, as we'll want this if we need to insert a row into secondary tables
1680
+			if ($this->has_primary_key_field()) {
1681
+				$main_table_pk_value = $wpdb_result[$this->get_primary_key_field()->get_qualified_column()];
1682
+			} else {
1683
+				//if there's no primary key, we basically can't support having a 2nd table on the model (we could but it would be lots of work)
1684
+				$main_table_pk_value = null;
1685
+			}
1686
+			//if there are more than 1 tables, we'll want to verify that each table for this model has an entry in the other tables
1687
+			//and if the other tables don't have a row for each table-to-be-updated, we'll insert one with whatever values available in the current update query
1688
+			if (count($tables) > 1) {
1689
+				//foreach matching row in the DB, ensure that each table's PK isn't null. If so, there must not be an entry
1690
+				//in that table, and so we'll want to insert one
1691
+				foreach ($tables as $table_obj) {
1692
+					$this_table_pk_column = $table_obj->get_fully_qualified_pk_column();
1693
+					//if there is no private key for this table on the results, it means there's no entry
1694
+					//in this table, right? so insert a row in the current table, using any fields available
1695
+					if (! (array_key_exists($this_table_pk_column, $wpdb_result)
1696
+						   && $wpdb_result[$this_table_pk_column])
1697
+					) {
1698
+						$success = $this->_insert_into_specific_table($table_obj, $fields_n_values,
1699
+							$main_table_pk_value);
1700
+						//if we died here, report the error
1701
+						if (! $success) {
1702
+							return false;
1703
+						}
1704
+					}
1705
+				}
1706
+			}
1707
+			//				//and now check that if we have cached any models by that ID on the model, that
1708
+			//				//they also get updated properly
1709
+			//				$model_object = $this->get_from_entity_map( $main_table_pk_value );
1710
+			//				if( $model_object ){
1711
+			//					foreach( $fields_n_values as $field => $value ){
1712
+			//						$model_object->set($field, $value);
1713
+			//let's make sure default_where strategy is followed now
1714
+			$this->_ignore_where_strategy = false;
1715
+		}
1716
+		//if we want to keep model objects in sync, AND
1717
+		//if this wasn't called from a model object (to update itself)
1718
+		//then we want to make sure we keep all the existing
1719
+		//model objects in sync with the db
1720
+		if ($keep_model_objs_in_sync && ! $this->_values_already_prepared_by_model_object) {
1721
+			if ($this->has_primary_key_field()) {
1722
+				$model_objs_affected_ids = $this->get_col($query_params);
1723
+			} else {
1724
+				//we need to select a bunch of columns and then combine them into the the "index primary key string"s
1725
+				$models_affected_key_columns = $this->_get_all_wpdb_results($query_params, ARRAY_A);
1726
+				$model_objs_affected_ids = array();
1727
+				foreach ($models_affected_key_columns as $row) {
1728
+					$combined_index_key = $this->get_index_primary_key_string($row);
1729
+					$model_objs_affected_ids[$combined_index_key] = $combined_index_key;
1730
+				}
1731
+			}
1732
+			if (! $model_objs_affected_ids) {
1733
+				//wait wait wait- if nothing was affected let's stop here
1734
+				return 0;
1735
+			}
1736
+			foreach ($model_objs_affected_ids as $id) {
1737
+				$model_obj_in_entity_map = $this->get_from_entity_map($id);
1738
+				if ($model_obj_in_entity_map) {
1739
+					foreach ($fields_n_values as $field => $new_value) {
1740
+						$model_obj_in_entity_map->set($field, $new_value);
1741
+					}
1742
+				}
1743
+			}
1744
+			//if there is a primary key on this model, we can now do a slight optimization
1745
+			if ($this->has_primary_key_field()) {
1746
+				//we already know what we want to update. So let's make the query simpler so it's a little more efficient
1747
+				$query_params = array(
1748
+					array($this->primary_key_name() => array('IN', $model_objs_affected_ids)),
1749
+					'limit'                    => count($model_objs_affected_ids),
1750
+					'default_where_conditions' => EEM_Base::default_where_conditions_none,
1751
+				);
1752
+			}
1753
+		}
1754
+		$model_query_info = $this->_create_model_query_info_carrier($query_params);
1755
+		$SQL = "UPDATE "
1756
+			   . $model_query_info->get_full_join_sql()
1757
+			   . " SET "
1758
+			   . $this->_construct_update_sql($fields_n_values)
1759
+			   . $model_query_info->get_where_sql();//note: doesn't use _construct_2nd_half_of_select_query() because doesn't accept LIMIT, ORDER BY, etc.
1760
+		$rows_affected = $this->_do_wpdb_query('query', array($SQL));
1761
+		/**
1762
+		 * Action called after a model update call has been made.
1763
+		 *
1764
+		 * @param EEM_Base $model
1765
+		 * @param array    $fields_n_values the updated fields and their new values
1766
+		 * @param array    $query_params    @see EEM_Base::get_all()
1767
+		 * @param int      $rows_affected
1768
+		 */
1769
+		do_action('AHEE__EEM_Base__update__end', $this, $fields_n_values, $query_params, $rows_affected);
1770
+		return $rows_affected;//how many supposedly got updated
1771
+	}
1772
+
1773
+
1774
+
1775
+	/**
1776
+	 * Analogous to $wpdb->get_col, returns a 1-dimensional array where teh values
1777
+	 * are teh values of the field specified (or by default the primary key field)
1778
+	 * that matched the query params. Note that you should pass the name of the
1779
+	 * model FIELD, not the database table's column name.
1780
+	 *
1781
+	 * @param array  $query_params @see EEM_Base::get_all()
1782
+	 * @param string $field_to_select
1783
+	 * @return array just like $wpdb->get_col()
1784
+	 * @throws EE_Error
1785
+	 */
1786
+	public function get_col($query_params = array(), $field_to_select = null)
1787
+	{
1788
+		if ($field_to_select) {
1789
+			$field = $this->field_settings_for($field_to_select);
1790
+		} elseif ($this->has_primary_key_field()) {
1791
+			$field = $this->get_primary_key_field();
1792
+		} else {
1793
+			//no primary key, just grab the first column
1794
+			$field = reset($this->field_settings());
1795
+		}
1796
+		$model_query_info = $this->_create_model_query_info_carrier($query_params);
1797
+		$select_expressions = $field->get_qualified_column();
1798
+		$SQL = "SELECT $select_expressions " . $this->_construct_2nd_half_of_select_query($model_query_info);
1799
+		return $this->_do_wpdb_query('get_col', array($SQL));
1800
+	}
1801
+
1802
+
1803
+
1804
+	/**
1805
+	 * Returns a single column value for a single row from the database
1806
+	 *
1807
+	 * @param array  $query_params    @see EEM_Base::get_all()
1808
+	 * @param string $field_to_select @see EEM_Base::get_col()
1809
+	 * @return string
1810
+	 * @throws EE_Error
1811
+	 */
1812
+	public function get_var($query_params = array(), $field_to_select = null)
1813
+	{
1814
+		$query_params['limit'] = 1;
1815
+		$col = $this->get_col($query_params, $field_to_select);
1816
+		if (! empty($col)) {
1817
+			return reset($col);
1818
+		}
1819
+		return null;
1820
+	}
1821
+
1822
+
1823
+
1824
+	/**
1825
+	 * Makes the SQL for after "UPDATE table_X inner join table_Y..." and before "...WHERE". Eg "Question.name='party
1826
+	 * time?', Question.desc='what do you think?',..." Values are filtered through wpdb->prepare to avoid against SQL
1827
+	 * injection, but currently no further filtering is done
1828
+	 *
1829
+	 * @global      $wpdb
1830
+	 * @param array $fields_n_values array keys are field names on this model, and values are what those fields should
1831
+	 *                               be updated to in the DB
1832
+	 * @return string of SQL
1833
+	 * @throws EE_Error
1834
+	 */
1835
+	public function _construct_update_sql($fields_n_values)
1836
+	{
1837
+		/** @type WPDB $wpdb */
1838
+		global $wpdb;
1839
+		$cols_n_values = array();
1840
+		foreach ($fields_n_values as $field_name => $value) {
1841
+			$field_obj = $this->field_settings_for($field_name);
1842
+			//if the value is NULL, we want to assign the value to that.
1843
+			//wpdb->prepare doesn't really handle that properly
1844
+			$prepared_value = $this->_prepare_value_or_use_default($field_obj, $fields_n_values);
1845
+			$value_sql = $prepared_value === null ? 'NULL'
1846
+				: $wpdb->prepare($field_obj->get_wpdb_data_type(), $prepared_value);
1847
+			$cols_n_values[] = $field_obj->get_qualified_column() . "=" . $value_sql;
1848
+		}
1849
+		return implode(",", $cols_n_values);
1850
+	}
1851
+
1852
+
1853
+
1854
+	/**
1855
+	 * Deletes a single row from the DB given the model object's primary key value. (eg, EE_Attendee->ID()'s value).
1856
+	 * Performs a HARD delete, meaning the database row should always be removed,
1857
+	 * not just have a flag field on it switched
1858
+	 * Wrapper for EEM_Base::delete_permanently()
1859
+	 *
1860
+	 * @param mixed $id
1861
+	 * @param boolean $allow_blocking
1862
+	 * @return int the number of rows deleted
1863
+	 * @throws EE_Error
1864
+	 */
1865
+	public function delete_permanently_by_ID($id, $allow_blocking = true)
1866
+	{
1867
+		return $this->delete_permanently(
1868
+			array(
1869
+				array($this->get_primary_key_field()->get_name() => $id),
1870
+				'limit' => 1,
1871
+			),
1872
+			$allow_blocking
1873
+		);
1874
+	}
1875
+
1876
+
1877
+
1878
+	/**
1879
+	 * Deletes a single row from the DB given the model object's primary key value. (eg, EE_Attendee->ID()'s value).
1880
+	 * Wrapper for EEM_Base::delete()
1881
+	 *
1882
+	 * @param mixed $id
1883
+	 * @param boolean $allow_blocking
1884
+	 * @return int the number of rows deleted
1885
+	 * @throws EE_Error
1886
+	 */
1887
+	public function delete_by_ID($id, $allow_blocking = true)
1888
+	{
1889
+		return $this->delete(
1890
+			array(
1891
+				array($this->get_primary_key_field()->get_name() => $id),
1892
+				'limit' => 1,
1893
+			),
1894
+			$allow_blocking
1895
+		);
1896
+	}
1897
+
1898
+
1899
+
1900
+	/**
1901
+	 * Identical to delete_permanently, but does a "soft" delete if possible,
1902
+	 * meaning if the model has a field that indicates its been "trashed" or
1903
+	 * "soft deleted", we will just set that instead of actually deleting the rows.
1904
+	 *
1905
+	 * @see EEM_Base::delete_permanently
1906
+	 * @param array   $query_params
1907
+	 * @param boolean $allow_blocking
1908
+	 * @return int how many rows got deleted
1909
+	 * @throws EE_Error
1910
+	 */
1911
+	public function delete($query_params, $allow_blocking = true)
1912
+	{
1913
+		return $this->delete_permanently($query_params, $allow_blocking);
1914
+	}
1915
+
1916
+
1917
+
1918
+	/**
1919
+	 * Deletes the model objects that meet the query params. Note: this method is overridden
1920
+	 * in EEM_Soft_Delete_Base so that soft-deleted model objects are instead only flagged
1921
+	 * as archived, not actually deleted
1922
+	 *
1923
+	 * @param array   $query_params   very much like EEM_Base::get_all's $query_params
1924
+	 * @param boolean $allow_blocking if TRUE, matched objects will only be deleted if there is no related model info
1925
+	 *                                that blocks it (ie, there' sno other data that depends on this data); if false,
1926
+	 *                                deletes regardless of other objects which may depend on it. Its generally
1927
+	 *                                advisable to always leave this as TRUE, otherwise you could easily corrupt your
1928
+	 *                                DB
1929
+	 * @return int how many rows got deleted
1930
+	 * @throws EE_Error
1931
+	 */
1932
+	public function delete_permanently($query_params, $allow_blocking = true)
1933
+	{
1934
+		/**
1935
+		 * Action called just before performing a real deletion query. You can use the
1936
+		 * model and its $query_params to find exactly which items will be deleted
1937
+		 *
1938
+		 * @param EEM_Base $model
1939
+		 * @param array    $query_params   @see EEM_Base::get_all()
1940
+		 * @param boolean  $allow_blocking whether or not to allow related model objects
1941
+		 *                                 to block (prevent) this deletion
1942
+		 */
1943
+		do_action('AHEE__EEM_Base__delete__begin', $this, $query_params, $allow_blocking);
1944
+		//some MySQL databases may be running safe mode, which may restrict
1945
+		//deletion if there is no KEY column used in the WHERE statement of a deletion.
1946
+		//to get around this, we first do a SELECT, get all the IDs, and then run another query
1947
+		//to delete them
1948
+		$items_for_deletion = $this->_get_all_wpdb_results($query_params);
1949
+		$columns_and_ids_for_deleting = $this->_get_ids_for_delete($items_for_deletion, $allow_blocking);
1950
+		$deletion_where_query_part = $this->_build_query_part_for_deleting_from_columns_and_values(
1951
+			$columns_and_ids_for_deleting
1952
+		);
1953
+		/**
1954
+		 * Allows client code to act on the items being deleted before the query is actually executed.
1955
+		 *
1956
+		 * @param EEM_Base $this  The model instance being acted on.
1957
+		 * @param array    $query_params  The incoming array of query parameters influencing what gets deleted.
1958
+		 * @param bool     $allow_blocking @see param description in method phpdoc block.
1959
+		 * @param array $columns_and_ids_for_deleting       An array indicating what entities will get removed as
1960
+		 *                                                  derived from the incoming query parameters.
1961
+		 *                                                  @see details on the structure of this array in the phpdocs
1962
+		 *                                                  for the `_get_ids_for_delete_method`
1963
+		 *
1964
+		 */
1965
+		do_action('AHEE__EEM_Base__delete__before_query',
1966
+			$this,
1967
+			$query_params,
1968
+			$allow_blocking,
1969
+			$columns_and_ids_for_deleting
1970
+		);
1971
+		if ($deletion_where_query_part) {
1972
+			$model_query_info = $this->_create_model_query_info_carrier($query_params);
1973
+			$table_aliases = array_keys($this->_tables);
1974
+			$SQL = "DELETE "
1975
+				   . implode(", ", $table_aliases)
1976
+				   . " FROM "
1977
+				   . $model_query_info->get_full_join_sql()
1978
+				   . " WHERE "
1979
+				   . $deletion_where_query_part;
1980
+			$rows_deleted = $this->_do_wpdb_query('query', array($SQL));
1981
+		} else {
1982
+			$rows_deleted = 0;
1983
+		}
1984
+
1985
+		//Next, make sure those items are removed from the entity map; if they could be put into it at all; and if
1986
+		//there was no error with the delete query.
1987
+		if ($this->has_primary_key_field()
1988
+			&& $rows_deleted !== false
1989
+			&& isset($columns_and_ids_for_deleting[$this->get_primary_key_field()->get_qualified_column()])
1990
+		) {
1991
+			$ids_for_removal = $columns_and_ids_for_deleting[$this->get_primary_key_field()->get_qualified_column()];
1992
+			foreach ($ids_for_removal as $id) {
1993
+				if (isset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id])) {
1994
+					unset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id]);
1995
+				}
1996
+			}
1997
+
1998
+			// delete any extra meta attached to the deleted entities but ONLY if this model is not an instance of
1999
+			//`EEM_Extra_Meta`.  In other words we want to prevent recursion on EEM_Extra_Meta::delete_permanently calls
2000
+			//unnecessarily.  It's very unlikely that users will have assigned Extra Meta to Extra Meta
2001
+			// (although it is possible).
2002
+			//Note this can be skipped by using the provided filter and returning false.
2003
+			if (apply_filters(
2004
+				'FHEE__EEM_Base__delete_permanently__dont_delete_extra_meta_for_extra_meta',
2005
+				! $this instanceof EEM_Extra_Meta,
2006
+				$this
2007
+			)) {
2008
+				EEM_Extra_Meta::instance()->delete_permanently(array(
2009
+					0 => array(
2010
+						'EXM_type' => $this->get_this_model_name(),
2011
+						'OBJ_ID'   => array(
2012
+							'IN',
2013
+							$ids_for_removal
2014
+						)
2015
+					)
2016
+				));
2017
+			}
2018
+		}
2019
+
2020
+		/**
2021
+		 * Action called just after performing a real deletion query. Although at this point the
2022
+		 * items should have been deleted
2023
+		 *
2024
+		 * @param EEM_Base $model
2025
+		 * @param array    $query_params @see EEM_Base::get_all()
2026
+		 * @param int      $rows_deleted
2027
+		 */
2028
+		do_action('AHEE__EEM_Base__delete__end', $this, $query_params, $rows_deleted, $columns_and_ids_for_deleting);
2029
+		return $rows_deleted;//how many supposedly got deleted
2030
+	}
2031
+
2032
+
2033
+
2034
+	/**
2035
+	 * Checks all the relations that throw error messages when there are blocking related objects
2036
+	 * for related model objects. If there are any related model objects on those relations,
2037
+	 * adds an EE_Error, and return true
2038
+	 *
2039
+	 * @param EE_Base_Class|int $this_model_obj_or_id
2040
+	 * @param EE_Base_Class     $ignore_this_model_obj a model object like 'EE_Event', or 'EE_Term_Taxonomy', which
2041
+	 *                                                 should be ignored when determining whether there are related
2042
+	 *                                                 model objects which block this model object's deletion. Useful
2043
+	 *                                                 if you know A is related to B and are considering deleting A,
2044
+	 *                                                 but want to see if A has any other objects blocking its deletion
2045
+	 *                                                 before removing the relation between A and B
2046
+	 * @return boolean
2047
+	 * @throws EE_Error
2048
+	 */
2049
+	public function delete_is_blocked_by_related_models($this_model_obj_or_id, $ignore_this_model_obj = null)
2050
+	{
2051
+		//first, if $ignore_this_model_obj was supplied, get its model
2052
+		if ($ignore_this_model_obj && $ignore_this_model_obj instanceof EE_Base_Class) {
2053
+			$ignored_model = $ignore_this_model_obj->get_model();
2054
+		} else {
2055
+			$ignored_model = null;
2056
+		}
2057
+		//now check all the relations of $this_model_obj_or_id and see if there
2058
+		//are any related model objects blocking it?
2059
+		$is_blocked = false;
2060
+		foreach ($this->_model_relations as $relation_name => $relation_obj) {
2061
+			if ($relation_obj->block_delete_if_related_models_exist()) {
2062
+				//if $ignore_this_model_obj was supplied, then for the query
2063
+				//on that model needs to be told to ignore $ignore_this_model_obj
2064
+				if ($ignored_model && $relation_name === $ignored_model->get_this_model_name()) {
2065
+					$related_model_objects = $relation_obj->get_all_related($this_model_obj_or_id, array(
2066
+						array(
2067
+							$ignored_model->get_primary_key_field()->get_name() => array(
2068
+								'!=',
2069
+								$ignore_this_model_obj->ID(),
2070
+							),
2071
+						),
2072
+					));
2073
+				} else {
2074
+					$related_model_objects = $relation_obj->get_all_related($this_model_obj_or_id);
2075
+				}
2076
+				if ($related_model_objects) {
2077
+					EE_Error::add_error($relation_obj->get_deletion_error_message(), __FILE__, __FUNCTION__, __LINE__);
2078
+					$is_blocked = true;
2079
+				}
2080
+			}
2081
+		}
2082
+		return $is_blocked;
2083
+	}
2084
+
2085
+
2086
+	/**
2087
+	 * Builds the columns and values for items to delete from the incoming $row_results_for_deleting array.
2088
+	 * @param array $row_results_for_deleting
2089
+	 * @param bool  $allow_blocking
2090
+	 * @return array   The shape of this array depends on whether the model `has_primary_key_field` or not.  If the
2091
+	 *                 model DOES have a primary_key_field, then the array will be a simple single dimension array where
2092
+	 *                 the key is the fully qualified primary key column and the value is an array of ids that will be
2093
+	 *                 deleted. Example:
2094
+	 *                      array('Event.EVT_ID' => array( 1,2,3))
2095
+	 *                 If the model DOES NOT have a primary_key_field, then the array will be a two dimensional array
2096
+	 *                 where each element is a group of columns and values that get deleted. Example:
2097
+	 *                      array(
2098
+	 *                          0 => array(
2099
+	 *                              'Term_Relationship.object_id' => 1
2100
+	 *                              'Term_Relationship.term_taxonomy_id' => 5
2101
+	 *                          ),
2102
+	 *                          1 => array(
2103
+	 *                              'Term_Relationship.object_id' => 1
2104
+	 *                              'Term_Relationship.term_taxonomy_id' => 6
2105
+	 *                          )
2106
+	 *                      )
2107
+	 * @throws EE_Error
2108
+	 */
2109
+	protected function _get_ids_for_delete(array $row_results_for_deleting, $allow_blocking = true)
2110
+	{
2111
+		$ids_to_delete_indexed_by_column = array();
2112
+		if ($this->has_primary_key_field()) {
2113
+			$primary_table = $this->_get_main_table();
2114
+			$primary_table_pk_field = $this->get_field_by_column($primary_table->get_fully_qualified_pk_column());
2115
+			$other_tables = $this->_get_other_tables();
2116
+			$ids_to_delete_indexed_by_column = $query = array();
2117
+			foreach ($row_results_for_deleting as $item_to_delete) {
2118
+				//before we mark this item for deletion,
2119
+				//make sure there's no related entities blocking its deletion (if we're checking)
2120
+				if (
2121
+					$allow_blocking
2122
+					&& $this->delete_is_blocked_by_related_models(
2123
+						$item_to_delete[$primary_table->get_fully_qualified_pk_column()]
2124
+					)
2125
+				) {
2126
+					continue;
2127
+				}
2128
+				//primary table deletes
2129
+				if (isset($item_to_delete[$primary_table->get_fully_qualified_pk_column()])) {
2130
+					$ids_to_delete_indexed_by_column[$primary_table->get_fully_qualified_pk_column()][] =
2131
+						$item_to_delete[$primary_table->get_fully_qualified_pk_column()];
2132
+				}
2133
+			}
2134
+		} elseif (count($this->get_combined_primary_key_fields()) > 1) {
2135
+			$fields = $this->get_combined_primary_key_fields();
2136
+			foreach ($row_results_for_deleting as $item_to_delete) {
2137
+				$ids_to_delete_indexed_by_column_for_row = array();
2138
+				foreach ($fields as $cpk_field) {
2139
+					if ($cpk_field instanceof EE_Model_Field_Base) {
2140
+						$ids_to_delete_indexed_by_column_for_row[$cpk_field->get_qualified_column()] =
2141
+							$item_to_delete[$cpk_field->get_qualified_column()];
2142
+					}
2143
+				}
2144
+				$ids_to_delete_indexed_by_column[] = $ids_to_delete_indexed_by_column_for_row;
2145
+			}
2146
+		} else {
2147
+			//so there's no primary key and no combined key...
2148
+			//sorry, can't help you
2149
+			throw new EE_Error(
2150
+				sprintf(
2151
+					__(
2152
+						"Cannot delete objects of type %s because there is no primary key NOR combined key",
2153
+						"event_espresso"
2154
+					), get_class($this)
2155
+				)
2156
+			);
2157
+		}
2158
+		return $ids_to_delete_indexed_by_column;
2159
+	}
2160
+
2161
+
2162
+	/**
2163
+	 * This receives an array of columns and values set to be deleted (as prepared by _get_ids_for_delete) and prepares
2164
+	 * the corresponding query_part for the query performing the delete.
2165
+	 *
2166
+	 * @param array $ids_to_delete_indexed_by_column @see _get_ids_for_delete for how this array might be shaped.
2167
+	 * @return string
2168
+	 * @throws EE_Error
2169
+	 */
2170
+	protected function _build_query_part_for_deleting_from_columns_and_values(array $ids_to_delete_indexed_by_column) {
2171
+		$query_part = '';
2172
+		if (empty($ids_to_delete_indexed_by_column)) {
2173
+			return $query_part;
2174
+		} elseif ($this->has_primary_key_field()) {
2175
+			$query = array();
2176
+			foreach ($ids_to_delete_indexed_by_column as $column => $ids) {
2177
+				//make sure we have unique $ids
2178
+				$ids = array_unique($ids);
2179
+				$query[] = $column . ' IN(' . implode(',', $ids) . ')';
2180
+			}
2181
+			$query_part = ! empty($query) ? implode(' AND ', $query) : $query_part;
2182
+		} elseif (count($this->get_combined_primary_key_fields()) > 1) {
2183
+			$ways_to_identify_a_row = array();
2184
+			foreach ($ids_to_delete_indexed_by_column as $ids_to_delete_indexed_by_column_for_each_row) {
2185
+				$values_for_each_combined_primary_key_for_a_row = array();
2186
+				foreach ($ids_to_delete_indexed_by_column_for_each_row as $column => $id) {
2187
+					$values_for_each_combined_primary_key_for_a_row[] = $column . '=' . $id;
2188
+				}
2189
+				$ways_to_identify_a_row[] = '(' . implode(' AND ', $values_for_each_combined_primary_key_for_a_row);
2190
+			}
2191
+			$query_part = implode(' OR ', $ways_to_identify_a_row);
2192
+		}
2193
+		return $query_part;
2194
+	}
2195
+
2196
+
2197
+
2198
+	/**
2199
+	 * Gets the model field by the fully qualified name
2200
+	 * @param string $qualified_column_name eg 'Event_CPT.post_name' or $field_obj->get_qualified_column()
2201
+	 * @return EE_Model_Field_Base
2202
+	 */
2203
+	public function get_field_by_column($qualified_column_name)
2204
+	{
2205
+	   foreach($this->field_settings(true) as $field_name => $field_obj){
2206
+		   if($field_obj->get_qualified_column() === $qualified_column_name){
2207
+			   return $field_obj;
2208
+		   }
2209
+	   }
2210
+		throw new EE_Error(
2211
+			sprintf(
2212
+				esc_html__('Could not find a field on the model "%1$s" for qualified column "%2$s"', 'event_espresso'),
2213
+				$this->get_this_model_name(),
2214
+				$qualified_column_name
2215
+			)
2216
+		);
2217
+	}
2218
+
2219
+
2220
+
2221
+	/**
2222
+	 * Count all the rows that match criteria expressed in $query_params (an array just like arg to EEM_Base::get_all).
2223
+	 * If $field_to_count isn't provided, the model's primary key is used. Otherwise, we count by field_to_count's
2224
+	 * column
2225
+	 *
2226
+	 * @param array  $query_params   like EEM_Base::get_all's
2227
+	 * @param string $field_to_count field on model to count by (not column name)
2228
+	 * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2229
+	 *                               that by the setting $distinct to TRUE;
2230
+	 * @return int
2231
+	 * @throws EE_Error
2232
+	 */
2233
+	public function count($query_params = array(), $field_to_count = null, $distinct = false)
2234
+	{
2235
+		$model_query_info = $this->_create_model_query_info_carrier($query_params);
2236
+		if ($field_to_count) {
2237
+			$field_obj = $this->field_settings_for($field_to_count);
2238
+			$column_to_count = $field_obj->get_qualified_column();
2239
+		} elseif ($this->has_primary_key_field()) {
2240
+			$pk_field_obj = $this->get_primary_key_field();
2241
+			$column_to_count = $pk_field_obj->get_qualified_column();
2242
+		} else {
2243
+			//there's no primary key
2244
+			//if we're counting distinct items, and there's no primary key,
2245
+			//we need to list out the columns for distinction;
2246
+			//otherwise we can just use star
2247
+			if ($distinct) {
2248
+				$columns_to_use = array();
2249
+				foreach ($this->get_combined_primary_key_fields() as $field_obj) {
2250
+					$columns_to_use[] = $field_obj->get_qualified_column();
2251
+				}
2252
+				$column_to_count = implode(',', $columns_to_use);
2253
+			} else {
2254
+				$column_to_count = '*';
2255
+			}
2256
+		}
2257
+		$column_to_count = $distinct ? "DISTINCT " . $column_to_count : $column_to_count;
2258
+		$SQL = "SELECT COUNT(" . $column_to_count . ")" . $this->_construct_2nd_half_of_select_query($model_query_info);
2259
+		return (int)$this->_do_wpdb_query('get_var', array($SQL));
2260
+	}
2261
+
2262
+
2263
+
2264
+	/**
2265
+	 * Sums up the value of the $field_to_sum (defaults to the primary key, which isn't terribly useful)
2266
+	 *
2267
+	 * @param array  $query_params like EEM_Base::get_all
2268
+	 * @param string $field_to_sum name of field (array key in $_fields array)
2269
+	 * @return float
2270
+	 * @throws EE_Error
2271
+	 */
2272
+	public function sum($query_params, $field_to_sum = null)
2273
+	{
2274
+		$model_query_info = $this->_create_model_query_info_carrier($query_params);
2275
+		if ($field_to_sum) {
2276
+			$field_obj = $this->field_settings_for($field_to_sum);
2277
+		} else {
2278
+			$field_obj = $this->get_primary_key_field();
2279
+		}
2280
+		$column_to_count = $field_obj->get_qualified_column();
2281
+		$SQL = "SELECT SUM(" . $column_to_count . ")" . $this->_construct_2nd_half_of_select_query($model_query_info);
2282
+		$return_value = $this->_do_wpdb_query('get_var', array($SQL));
2283
+		$data_type = $field_obj->get_wpdb_data_type();
2284
+		if ($data_type === '%d' || $data_type === '%s') {
2285
+			return (float)$return_value;
2286
+		}
2287
+		//must be %f
2288
+		return (float)$return_value;
2289
+	}
2290
+
2291
+
2292
+
2293
+	/**
2294
+	 * Just calls the specified method on $wpdb with the given arguments
2295
+	 * Consolidates a little extra error handling code
2296
+	 *
2297
+	 * @param string $wpdb_method
2298
+	 * @param array  $arguments_to_provide
2299
+	 * @throws EE_Error
2300
+	 * @global wpdb  $wpdb
2301
+	 * @return mixed
2302
+	 */
2303
+	protected function _do_wpdb_query($wpdb_method, $arguments_to_provide)
2304
+	{
2305
+		//if we're in maintenance mode level 2, DON'T run any queries
2306
+		//because level 2 indicates the database needs updating and
2307
+		//is probably out of sync with the code
2308
+		if (! EE_Maintenance_Mode::instance()->models_can_query()) {
2309
+			throw new EE_Error(sprintf(__("Event Espresso Level 2 Maintenance mode is active. That means EE can not run ANY database queries until the necessary migration scripts have run which will take EE out of maintenance mode level 2. Please inform support of this error.",
2310
+				"event_espresso")));
2311
+		}
2312
+		/** @type WPDB $wpdb */
2313
+		global $wpdb;
2314
+		if (! method_exists($wpdb, $wpdb_method)) {
2315
+			throw new EE_Error(sprintf(__('There is no method named "%s" on Wordpress\' $wpdb object',
2316
+				'event_espresso'), $wpdb_method));
2317
+		}
2318
+		if (WP_DEBUG) {
2319
+			$old_show_errors_value = $wpdb->show_errors;
2320
+			$wpdb->show_errors(false);
2321
+		}
2322
+		$result = $this->_process_wpdb_query($wpdb_method, $arguments_to_provide);
2323
+		$this->show_db_query_if_previously_requested($wpdb->last_query);
2324
+		if (WP_DEBUG) {
2325
+			$wpdb->show_errors($old_show_errors_value);
2326
+			if (! empty($wpdb->last_error)) {
2327
+				throw new EE_Error(sprintf(__('WPDB Error: "%s"', 'event_espresso'), $wpdb->last_error));
2328
+			}
2329
+			if ($result === false) {
2330
+				throw new EE_Error(sprintf(__('WPDB Error occurred, but no error message was logged by wpdb! The wpdb method called was "%1$s" and the arguments were "%2$s"',
2331
+					'event_espresso'), $wpdb_method, var_export($arguments_to_provide, true)));
2332
+			}
2333
+		} elseif ($result === false) {
2334
+			EE_Error::add_error(
2335
+				sprintf(
2336
+					__('A database error has occurred. Turn on WP_DEBUG for more information.||A database error occurred doing wpdb method "%1$s", with arguments "%2$s". The error was "%3$s"',
2337
+						'event_espresso'),
2338
+					$wpdb_method,
2339
+					var_export($arguments_to_provide, true),
2340
+					$wpdb->last_error
2341
+				),
2342
+				__FILE__,
2343
+				__FUNCTION__,
2344
+				__LINE__
2345
+			);
2346
+		}
2347
+		return $result;
2348
+	}
2349
+
2350
+
2351
+
2352
+	/**
2353
+	 * Attempts to run the indicated WPDB method with the provided arguments,
2354
+	 * and if there's an error tries to verify the DB is correct. Uses
2355
+	 * the static property EEM_Base::$_db_verification_level to determine whether
2356
+	 * we should try to fix the EE core db, the addons, or just give up
2357
+	 *
2358
+	 * @param string $wpdb_method
2359
+	 * @param array  $arguments_to_provide
2360
+	 * @return mixed
2361
+	 */
2362
+	private function _process_wpdb_query($wpdb_method, $arguments_to_provide)
2363
+	{
2364
+		/** @type WPDB $wpdb */
2365
+		global $wpdb;
2366
+		$wpdb->last_error = null;
2367
+		$result = call_user_func_array(array($wpdb, $wpdb_method), $arguments_to_provide);
2368
+		// was there an error running the query? but we don't care on new activations
2369
+		// (we're going to setup the DB anyway on new activations)
2370
+		if (($result === false || ! empty($wpdb->last_error))
2371
+			&& EE_System::instance()->detect_req_type() !== EE_System::req_type_new_activation
2372
+		) {
2373
+			switch (EEM_Base::$_db_verification_level) {
2374
+				case EEM_Base::db_verified_none :
2375
+					// let's double-check core's DB
2376
+					$error_message = $this->_verify_core_db($wpdb_method, $arguments_to_provide);
2377
+					break;
2378
+				case EEM_Base::db_verified_core :
2379
+					// STILL NO LOVE?? verify all the addons too. Maybe they need to be fixed
2380
+					$error_message = $this->_verify_addons_db($wpdb_method, $arguments_to_provide);
2381
+					break;
2382
+				case EEM_Base::db_verified_addons :
2383
+					// ummmm... you in trouble
2384
+					return $result;
2385
+					break;
2386
+			}
2387
+			if (! empty($error_message)) {
2388
+				EE_Log::instance()->log(__FILE__, __FUNCTION__, $error_message, 'error');
2389
+				trigger_error($error_message);
2390
+			}
2391
+			return $this->_process_wpdb_query($wpdb_method, $arguments_to_provide);
2392
+		}
2393
+		return $result;
2394
+	}
2395
+
2396
+
2397
+
2398
+	/**
2399
+	 * Verifies the EE core database is up-to-date and records that we've done it on
2400
+	 * EEM_Base::$_db_verification_level
2401
+	 *
2402
+	 * @param string $wpdb_method
2403
+	 * @param array  $arguments_to_provide
2404
+	 * @return string
2405
+	 */
2406
+	private function _verify_core_db($wpdb_method, $arguments_to_provide)
2407
+	{
2408
+		/** @type WPDB $wpdb */
2409
+		global $wpdb;
2410
+		//ok remember that we've already attempted fixing the core db, in case the problem persists
2411
+		EEM_Base::$_db_verification_level = EEM_Base::db_verified_core;
2412
+		$error_message = sprintf(
2413
+			__('WPDB Error "%1$s" while running wpdb method "%2$s" with arguments %3$s. Automatically attempting to fix EE Core DB',
2414
+				'event_espresso'),
2415
+			$wpdb->last_error,
2416
+			$wpdb_method,
2417
+			wp_json_encode($arguments_to_provide)
2418
+		);
2419
+		EE_System::instance()->initialize_db_if_no_migrations_required(false, true);
2420
+		return $error_message;
2421
+	}
2422
+
2423
+
2424
+
2425
+	/**
2426
+	 * Verifies the EE addons' database is up-to-date and records that we've done it on
2427
+	 * EEM_Base::$_db_verification_level
2428
+	 *
2429
+	 * @param $wpdb_method
2430
+	 * @param $arguments_to_provide
2431
+	 * @return string
2432
+	 */
2433
+	private function _verify_addons_db($wpdb_method, $arguments_to_provide)
2434
+	{
2435
+		/** @type WPDB $wpdb */
2436
+		global $wpdb;
2437
+		//ok remember that we've already attempted fixing the addons dbs, in case the problem persists
2438
+		EEM_Base::$_db_verification_level = EEM_Base::db_verified_addons;
2439
+		$error_message = sprintf(
2440
+			__('WPDB AGAIN: Error "%1$s" while running the same method and arguments as before. Automatically attempting to fix EE Addons DB',
2441
+				'event_espresso'),
2442
+			$wpdb->last_error,
2443
+			$wpdb_method,
2444
+			wp_json_encode($arguments_to_provide)
2445
+		);
2446
+		EE_System::instance()->initialize_addons();
2447
+		return $error_message;
2448
+	}
2449
+
2450
+
2451
+
2452
+	/**
2453
+	 * In order to avoid repeating this code for the get_all, sum, and count functions, put the code parts
2454
+	 * that are identical in here. Returns a string of SQL of everything in a SELECT query except the beginning
2455
+	 * SELECT clause, eg " FROM wp_posts AS Event INNER JOIN ... WHERE ... ORDER BY ... LIMIT ... GROUP BY ... HAVING
2456
+	 * ..."
2457
+	 *
2458
+	 * @param EE_Model_Query_Info_Carrier $model_query_info
2459
+	 * @return string
2460
+	 */
2461
+	private function _construct_2nd_half_of_select_query(EE_Model_Query_Info_Carrier $model_query_info)
2462
+	{
2463
+		return " FROM " . $model_query_info->get_full_join_sql() .
2464
+			   $model_query_info->get_where_sql() .
2465
+			   $model_query_info->get_group_by_sql() .
2466
+			   $model_query_info->get_having_sql() .
2467
+			   $model_query_info->get_order_by_sql() .
2468
+			   $model_query_info->get_limit_sql();
2469
+	}
2470
+
2471
+
2472
+
2473
+	/**
2474
+	 * Set to easily debug the next X queries ran from this model.
2475
+	 *
2476
+	 * @param int $count
2477
+	 */
2478
+	public function show_next_x_db_queries($count = 1)
2479
+	{
2480
+		$this->_show_next_x_db_queries = $count;
2481
+	}
2482
+
2483
+
2484
+
2485
+	/**
2486
+	 * @param $sql_query
2487
+	 */
2488
+	public function show_db_query_if_previously_requested($sql_query)
2489
+	{
2490
+		if ($this->_show_next_x_db_queries > 0) {
2491
+			echo $sql_query;
2492
+			$this->_show_next_x_db_queries--;
2493
+		}
2494
+	}
2495
+
2496
+
2497
+
2498
+	/**
2499
+	 * Adds a relationship of the correct type between $modelObject and $otherModelObject.
2500
+	 * There are the 3 cases:
2501
+	 * 'belongsTo' relationship: sets $id_or_obj's foreign_key to be $other_model_id_or_obj's primary_key. If
2502
+	 * $otherModelObject has no ID, it is first saved.
2503
+	 * 'hasMany' relationship: sets $other_model_id_or_obj's foreign_key to be $id_or_obj's primary_key. If $id_or_obj
2504
+	 * has no ID, it is first saved.
2505
+	 * 'hasAndBelongsToMany' relationships: checks that there isn't already an entry in the join table, and adds one.
2506
+	 * If one of the model Objects has not yet been saved to the database, it is saved before adding the entry in the
2507
+	 * join table
2508
+	 *
2509
+	 * @param        EE_Base_Class                     /int $thisModelObject
2510
+	 * @param        EE_Base_Class                     /int $id_or_obj EE_base_Class or ID of other Model Object
2511
+	 * @param string $relationName                     , key in EEM_Base::_relations
2512
+	 *                                                 an attendee to a group, you also want to specify which role they
2513
+	 *                                                 will have in that group. So you would use this parameter to
2514
+	 *                                                 specify array('role-column-name'=>'role-id')
2515
+	 * @param array  $extra_join_model_fields_n_values This allows you to enter further query params for the relation
2516
+	 *                                                 to for relation to methods that allow you to further specify
2517
+	 *                                                 extra columns to join by (such as HABTM).  Keep in mind that the
2518
+	 *                                                 only acceptable query_params is strict "col" => "value" pairs
2519
+	 *                                                 because these will be inserted in any new rows created as well.
2520
+	 * @return EE_Base_Class which was added as a relation. Object referred to by $other_model_id_or_obj
2521
+	 * @throws EE_Error
2522
+	 */
2523
+	public function add_relationship_to(
2524
+		$id_or_obj,
2525
+		$other_model_id_or_obj,
2526
+		$relationName,
2527
+		$extra_join_model_fields_n_values = array()
2528
+	) {
2529
+		$relation_obj = $this->related_settings_for($relationName);
2530
+		return $relation_obj->add_relation_to($id_or_obj, $other_model_id_or_obj, $extra_join_model_fields_n_values);
2531
+	}
2532
+
2533
+
2534
+
2535
+	/**
2536
+	 * Removes a relationship of the correct type between $modelObject and $otherModelObject.
2537
+	 * There are the 3 cases:
2538
+	 * 'belongsTo' relationship: sets $modelObject's foreign_key to null, if that field is nullable.Otherwise throws an
2539
+	 * error
2540
+	 * 'hasMany' relationship: sets $otherModelObject's foreign_key to null,if that field is nullable.Otherwise throws
2541
+	 * an error
2542
+	 * 'hasAndBelongsToMany' relationships:removes any existing entry in the join table between the two models.
2543
+	 *
2544
+	 * @param        EE_Base_Class /int $id_or_obj
2545
+	 * @param        EE_Base_Class /int $other_model_id_or_obj EE_Base_Class or ID of other Model Object
2546
+	 * @param string $relationName key in EEM_Base::_relations
2547
+	 * @return boolean of success
2548
+	 * @throws EE_Error
2549
+	 * @param array  $where_query  This allows you to enter further query params for the relation to for relation to
2550
+	 *                             methods that allow you to further specify extra columns to join by (such as HABTM).
2551
+	 *                             Keep in mind that the only acceptable query_params is strict "col" => "value" pairs
2552
+	 *                             because these will be inserted in any new rows created as well.
2553
+	 */
2554
+	public function remove_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query = array())
2555
+	{
2556
+		$relation_obj = $this->related_settings_for($relationName);
2557
+		return $relation_obj->remove_relation_to($id_or_obj, $other_model_id_or_obj, $where_query);
2558
+	}
2559
+
2560
+
2561
+
2562
+	/**
2563
+	 * @param mixed           $id_or_obj
2564
+	 * @param string          $relationName
2565
+	 * @param array           $where_query_params
2566
+	 * @param EE_Base_Class[] objects to which relations were removed
2567
+	 * @return \EE_Base_Class[]
2568
+	 * @throws EE_Error
2569
+	 */
2570
+	public function remove_relations($id_or_obj, $relationName, $where_query_params = array())
2571
+	{
2572
+		$relation_obj = $this->related_settings_for($relationName);
2573
+		return $relation_obj->remove_relations($id_or_obj, $where_query_params);
2574
+	}
2575
+
2576
+
2577
+
2578
+	/**
2579
+	 * Gets all the related items of the specified $model_name, using $query_params.
2580
+	 * Note: by default, we remove the "default query params"
2581
+	 * because we want to get even deleted items etc.
2582
+	 *
2583
+	 * @param mixed  $id_or_obj    EE_Base_Class child or its ID
2584
+	 * @param string $model_name   like 'Event', 'Registration', etc. always singular
2585
+	 * @param array  $query_params like EEM_Base::get_all
2586
+	 * @return EE_Base_Class[]
2587
+	 * @throws EE_Error
2588
+	 */
2589
+	public function get_all_related($id_or_obj, $model_name, $query_params = null)
2590
+	{
2591
+		$model_obj = $this->ensure_is_obj($id_or_obj);
2592
+		$relation_settings = $this->related_settings_for($model_name);
2593
+		return $relation_settings->get_all_related($model_obj, $query_params);
2594
+	}
2595
+
2596
+
2597
+
2598
+	/**
2599
+	 * Deletes all the model objects across the relation indicated by $model_name
2600
+	 * which are related to $id_or_obj which meet the criteria set in $query_params.
2601
+	 * However, if the model objects can't be deleted because of blocking related model objects, then
2602
+	 * they aren't deleted. (Unless the thing that would have been deleted can be soft-deleted, that still happens).
2603
+	 *
2604
+	 * @param EE_Base_Class|int|string $id_or_obj
2605
+	 * @param string                   $model_name
2606
+	 * @param array                    $query_params
2607
+	 * @return int how many deleted
2608
+	 * @throws EE_Error
2609
+	 */
2610
+	public function delete_related($id_or_obj, $model_name, $query_params = array())
2611
+	{
2612
+		$model_obj = $this->ensure_is_obj($id_or_obj);
2613
+		$relation_settings = $this->related_settings_for($model_name);
2614
+		return $relation_settings->delete_all_related($model_obj, $query_params);
2615
+	}
2616
+
2617
+
2618
+
2619
+	/**
2620
+	 * Hard deletes all the model objects across the relation indicated by $model_name
2621
+	 * which are related to $id_or_obj which meet the criteria set in $query_params. If
2622
+	 * the model objects can't be hard deleted because of blocking related model objects,
2623
+	 * just does a soft-delete on them instead.
2624
+	 *
2625
+	 * @param EE_Base_Class|int|string $id_or_obj
2626
+	 * @param string                   $model_name
2627
+	 * @param array                    $query_params
2628
+	 * @return int how many deleted
2629
+	 * @throws EE_Error
2630
+	 */
2631
+	public function delete_related_permanently($id_or_obj, $model_name, $query_params = array())
2632
+	{
2633
+		$model_obj = $this->ensure_is_obj($id_or_obj);
2634
+		$relation_settings = $this->related_settings_for($model_name);
2635
+		return $relation_settings->delete_related_permanently($model_obj, $query_params);
2636
+	}
2637
+
2638
+
2639
+
2640
+	/**
2641
+	 * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2642
+	 * unless otherwise specified in the $query_params
2643
+	 *
2644
+	 * @param        int             /EE_Base_Class $id_or_obj
2645
+	 * @param string $model_name     like 'Event', or 'Registration'
2646
+	 * @param array  $query_params   like EEM_Base::get_all's
2647
+	 * @param string $field_to_count name of field to count by. By default, uses primary key
2648
+	 * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2649
+	 *                               that by the setting $distinct to TRUE;
2650
+	 * @return int
2651
+	 * @throws EE_Error
2652
+	 */
2653
+	public function count_related(
2654
+		$id_or_obj,
2655
+		$model_name,
2656
+		$query_params = array(),
2657
+		$field_to_count = null,
2658
+		$distinct = false
2659
+	) {
2660
+		$related_model = $this->get_related_model_obj($model_name);
2661
+		//we're just going to use the query params on the related model's normal get_all query,
2662
+		//except add a condition to say to match the current mod
2663
+		if (! isset($query_params['default_where_conditions'])) {
2664
+			$query_params['default_where_conditions'] = EEM_Base::default_where_conditions_none;
2665
+		}
2666
+		$this_model_name = $this->get_this_model_name();
2667
+		$this_pk_field_name = $this->get_primary_key_field()->get_name();
2668
+		$query_params[0][$this_model_name . "." . $this_pk_field_name] = $id_or_obj;
2669
+		return $related_model->count($query_params, $field_to_count, $distinct);
2670
+	}
2671
+
2672
+
2673
+
2674
+	/**
2675
+	 * Instead of getting the related model objects, simply sums up the values of the specified field.
2676
+	 * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2677
+	 *
2678
+	 * @param        int           /EE_Base_Class $id_or_obj
2679
+	 * @param string $model_name   like 'Event', or 'Registration'
2680
+	 * @param array  $query_params like EEM_Base::get_all's
2681
+	 * @param string $field_to_sum name of field to count by. By default, uses primary key
2682
+	 * @return float
2683
+	 * @throws EE_Error
2684
+	 */
2685
+	public function sum_related($id_or_obj, $model_name, $query_params, $field_to_sum = null)
2686
+	{
2687
+		$related_model = $this->get_related_model_obj($model_name);
2688
+		if (! is_array($query_params)) {
2689
+			EE_Error::doing_it_wrong('EEM_Base::sum_related',
2690
+				sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
2691
+					gettype($query_params)), '4.6.0');
2692
+			$query_params = array();
2693
+		}
2694
+		//we're just going to use the query params on the related model's normal get_all query,
2695
+		//except add a condition to say to match the current mod
2696
+		if (! isset($query_params['default_where_conditions'])) {
2697
+			$query_params['default_where_conditions'] = EEM_Base::default_where_conditions_none;
2698
+		}
2699
+		$this_model_name = $this->get_this_model_name();
2700
+		$this_pk_field_name = $this->get_primary_key_field()->get_name();
2701
+		$query_params[0][$this_model_name . "." . $this_pk_field_name] = $id_or_obj;
2702
+		return $related_model->sum($query_params, $field_to_sum);
2703
+	}
2704
+
2705
+
2706
+
2707
+	/**
2708
+	 * Uses $this->_relatedModels info to find the first related model object of relation $relationName to the given
2709
+	 * $modelObject
2710
+	 *
2711
+	 * @param int | EE_Base_Class $id_or_obj        EE_Base_Class child or its ID
2712
+	 * @param string              $other_model_name , key in $this->_relatedModels, eg 'Registration', or 'Events'
2713
+	 * @param array               $query_params     like EEM_Base::get_all's
2714
+	 * @return EE_Base_Class
2715
+	 * @throws EE_Error
2716
+	 */
2717
+	public function get_first_related(EE_Base_Class $id_or_obj, $other_model_name, $query_params)
2718
+	{
2719
+		$query_params['limit'] = 1;
2720
+		$results = $this->get_all_related($id_or_obj, $other_model_name, $query_params);
2721
+		if ($results) {
2722
+			return array_shift($results);
2723
+		}
2724
+		return null;
2725
+	}
2726
+
2727
+
2728
+
2729
+	/**
2730
+	 * Gets the model's name as it's expected in queries. For example, if this is EEM_Event model, that would be Event
2731
+	 *
2732
+	 * @return string
2733
+	 */
2734
+	public function get_this_model_name()
2735
+	{
2736
+		return str_replace("EEM_", "", get_class($this));
2737
+	}
2738
+
2739
+
2740
+
2741
+	/**
2742
+	 * Gets the model field on this model which is of type EE_Any_Foreign_Model_Name_Field
2743
+	 *
2744
+	 * @return EE_Any_Foreign_Model_Name_Field
2745
+	 * @throws EE_Error
2746
+	 */
2747
+	public function get_field_containing_related_model_name()
2748
+	{
2749
+		foreach ($this->field_settings(true) as $field) {
2750
+			if ($field instanceof EE_Any_Foreign_Model_Name_Field) {
2751
+				$field_with_model_name = $field;
2752
+			}
2753
+		}
2754
+		if (! isset($field_with_model_name) || ! $field_with_model_name) {
2755
+			throw new EE_Error(sprintf(__("There is no EE_Any_Foreign_Model_Name field on model %s", "event_espresso"),
2756
+				$this->get_this_model_name()));
2757
+		}
2758
+		return $field_with_model_name;
2759
+	}
2760
+
2761
+
2762
+
2763
+	/**
2764
+	 * Inserts a new entry into the database, for each table.
2765
+	 * Note: does not add the item to the entity map because that is done by EE_Base_Class::save() right after this.
2766
+	 * If client code uses EEM_Base::insert() directly, then although the item isn't in the entity map,
2767
+	 * we also know there is no model object with the newly inserted item's ID at the moment (because
2768
+	 * if there were, then they would already be in the DB and this would fail); and in the future if someone
2769
+	 * creates a model object with this ID (or grabs it from the DB) then it will be added to the
2770
+	 * entity map at that time anyways. SO, no need for EEM_Base::insert ot add to the entity map
2771
+	 *
2772
+	 * @param array $field_n_values keys are field names, values are their values (in the client code's domain if
2773
+	 *                              $values_already_prepared_by_model_object is false, in the model object's domain if
2774
+	 *                              $values_already_prepared_by_model_object is true. See comment about this at the top
2775
+	 *                              of EEM_Base)
2776
+	 * @return int new primary key on main table that got inserted
2777
+	 * @throws EE_Error
2778
+	 */
2779
+	public function insert($field_n_values)
2780
+	{
2781
+		/**
2782
+		 * Filters the fields and their values before inserting an item using the models
2783
+		 *
2784
+		 * @param array    $fields_n_values keys are the fields and values are their new values
2785
+		 * @param EEM_Base $model           the model used
2786
+		 */
2787
+		$field_n_values = (array)apply_filters('FHEE__EEM_Base__insert__fields_n_values', $field_n_values, $this);
2788
+		if ($this->_satisfies_unique_indexes($field_n_values)) {
2789
+			$main_table = $this->_get_main_table();
2790
+			$new_id = $this->_insert_into_specific_table($main_table, $field_n_values, false);
2791
+			if ($new_id !== false) {
2792
+				foreach ($this->_get_other_tables() as $other_table) {
2793
+					$this->_insert_into_specific_table($other_table, $field_n_values, $new_id);
2794
+				}
2795
+			}
2796
+			/**
2797
+			 * Done just after attempting to insert a new model object
2798
+			 *
2799
+			 * @param EEM_Base   $model           used
2800
+			 * @param array      $fields_n_values fields and their values
2801
+			 * @param int|string the              ID of the newly-inserted model object
2802
+			 */
2803
+			do_action('AHEE__EEM_Base__insert__end', $this, $field_n_values, $new_id);
2804
+			return $new_id;
2805
+		}
2806
+		return false;
2807
+	}
2808
+
2809
+
2810
+
2811
+	/**
2812
+	 * Checks that the result would satisfy the unique indexes on this model
2813
+	 *
2814
+	 * @param array  $field_n_values
2815
+	 * @param string $action
2816
+	 * @return boolean
2817
+	 * @throws EE_Error
2818
+	 */
2819
+	protected function _satisfies_unique_indexes($field_n_values, $action = 'insert')
2820
+	{
2821
+		foreach ($this->unique_indexes() as $index_name => $index) {
2822
+			$uniqueness_where_params = array_intersect_key($field_n_values, $index->fields());
2823
+			if ($this->exists(array($uniqueness_where_params))) {
2824
+				EE_Error::add_error(
2825
+					sprintf(
2826
+						__(
2827
+							"Could not %s %s. %s uniqueness index failed. Fields %s must form a unique set, but an entry already exists with values %s.",
2828
+							"event_espresso"
2829
+						),
2830
+						$action,
2831
+						$this->_get_class_name(),
2832
+						$index_name,
2833
+						implode(",", $index->field_names()),
2834
+						http_build_query($uniqueness_where_params)
2835
+					),
2836
+					__FILE__,
2837
+					__FUNCTION__,
2838
+					__LINE__
2839
+				);
2840
+				return false;
2841
+			}
2842
+		}
2843
+		return true;
2844
+	}
2845
+
2846
+
2847
+
2848
+	/**
2849
+	 * Checks the database for an item that conflicts (ie, if this item were
2850
+	 * saved to the DB would break some uniqueness requirement, like a primary key
2851
+	 * or an index primary key set) with the item specified. $id_obj_or_fields_array
2852
+	 * can be either an EE_Base_Class or an array of fields n values
2853
+	 *
2854
+	 * @param EE_Base_Class|array $obj_or_fields_array
2855
+	 * @param boolean             $include_primary_key whether to use the model object's primary key
2856
+	 *                                                 when looking for conflicts
2857
+	 *                                                 (ie, if false, we ignore the model object's primary key
2858
+	 *                                                 when finding "conflicts". If true, it's also considered).
2859
+	 *                                                 Only works for INT primary key,
2860
+	 *                                                 STRING primary keys cannot be ignored
2861
+	 * @throws EE_Error
2862
+	 * @return EE_Base_Class|array
2863
+	 */
2864
+	public function get_one_conflicting($obj_or_fields_array, $include_primary_key = true)
2865
+	{
2866
+		if ($obj_or_fields_array instanceof EE_Base_Class) {
2867
+			$fields_n_values = $obj_or_fields_array->model_field_array();
2868
+		} elseif (is_array($obj_or_fields_array)) {
2869
+			$fields_n_values = $obj_or_fields_array;
2870
+		} else {
2871
+			throw new EE_Error(
2872
+				sprintf(
2873
+					__(
2874
+						"%s get_all_conflicting should be called with a model object or an array of field names and values, you provided %d",
2875
+						"event_espresso"
2876
+					),
2877
+					get_class($this),
2878
+					$obj_or_fields_array
2879
+				)
2880
+			);
2881
+		}
2882
+		$query_params = array();
2883
+		if ($this->has_primary_key_field()
2884
+			&& ($include_primary_key
2885
+				|| $this->get_primary_key_field()
2886
+				   instanceof
2887
+				   EE_Primary_Key_String_Field)
2888
+			&& isset($fields_n_values[$this->primary_key_name()])
2889
+		) {
2890
+			$query_params[0]['OR'][$this->primary_key_name()] = $fields_n_values[$this->primary_key_name()];
2891
+		}
2892
+		foreach ($this->unique_indexes() as $unique_index_name => $unique_index) {
2893
+			$uniqueness_where_params = array_intersect_key($fields_n_values, $unique_index->fields());
2894
+			$query_params[0]['OR']['AND*' . $unique_index_name] = $uniqueness_where_params;
2895
+		}
2896
+		//if there is nothing to base this search on, then we shouldn't find anything
2897
+		if (empty($query_params)) {
2898
+			return array();
2899
+		}
2900
+		return $this->get_one($query_params);
2901
+	}
2902
+
2903
+
2904
+
2905
+	/**
2906
+	 * Like count, but is optimized and returns a boolean instead of an int
2907
+	 *
2908
+	 * @param array $query_params
2909
+	 * @return boolean
2910
+	 * @throws EE_Error
2911
+	 */
2912
+	public function exists($query_params)
2913
+	{
2914
+		$query_params['limit'] = 1;
2915
+		return $this->count($query_params) > 0;
2916
+	}
2917
+
2918
+
2919
+
2920
+	/**
2921
+	 * Wrapper for exists, except ignores default query parameters so we're only considering ID
2922
+	 *
2923
+	 * @param int|string $id
2924
+	 * @return boolean
2925
+	 * @throws EE_Error
2926
+	 */
2927
+	public function exists_by_ID($id)
2928
+	{
2929
+		return $this->exists(
2930
+			array(
2931
+				'default_where_conditions' => EEM_Base::default_where_conditions_none,
2932
+				array(
2933
+					$this->primary_key_name() => $id,
2934
+				),
2935
+			)
2936
+		);
2937
+	}
2938
+
2939
+
2940
+
2941
+	/**
2942
+	 * Inserts a new row in $table, using the $cols_n_values which apply to that table.
2943
+	 * If a $new_id is supplied and if $table is an EE_Other_Table, we assume
2944
+	 * we need to add a foreign key column to point to $new_id (which should be the primary key's value
2945
+	 * on the main table)
2946
+	 * This is protected rather than private because private is not accessible to any child methods and there MAY be
2947
+	 * cases where we want to call it directly rather than via insert().
2948
+	 *
2949
+	 * @access   protected
2950
+	 * @param EE_Table_Base $table
2951
+	 * @param array         $fields_n_values each key should be in field's keys, and value should be an int, string or
2952
+	 *                                       float
2953
+	 * @param int           $new_id          for now we assume only int keys
2954
+	 * @throws EE_Error
2955
+	 * @global WPDB         $wpdb            only used to get the $wpdb->insert_id after performing an insert
2956
+	 * @return int ID of new row inserted, or FALSE on failure
2957
+	 */
2958
+	protected function _insert_into_specific_table(EE_Table_Base $table, $fields_n_values, $new_id = 0)
2959
+	{
2960
+		global $wpdb;
2961
+		$insertion_col_n_values = array();
2962
+		$format_for_insertion = array();
2963
+		$fields_on_table = $this->_get_fields_for_table($table->get_table_alias());
2964
+		foreach ($fields_on_table as $field_name => $field_obj) {
2965
+			//check if its an auto-incrementing column, in which case we should just leave it to do its autoincrement thing
2966
+			if ($field_obj->is_auto_increment()) {
2967
+				continue;
2968
+			}
2969
+			$prepared_value = $this->_prepare_value_or_use_default($field_obj, $fields_n_values);
2970
+			//if the value we want to assign it to is NULL, just don't mention it for the insertion
2971
+			if ($prepared_value !== null) {
2972
+				$insertion_col_n_values[$field_obj->get_table_column()] = $prepared_value;
2973
+				$format_for_insertion[] = $field_obj->get_wpdb_data_type();
2974
+			}
2975
+		}
2976
+		if ($table instanceof EE_Secondary_Table && $new_id) {
2977
+			//its not the main table, so we should have already saved the main table's PK which we just inserted
2978
+			//so add the fk to the main table as a column
2979
+			$insertion_col_n_values[$table->get_fk_on_table()] = $new_id;
2980
+			$format_for_insertion[] = '%d';//yes right now we're only allowing these foreign keys to be INTs
2981
+		}
2982
+		//insert the new entry
2983
+		$result = $this->_do_wpdb_query('insert',
2984
+			array($table->get_table_name(), $insertion_col_n_values, $format_for_insertion));
2985
+		if ($result === false) {
2986
+			return false;
2987
+		}
2988
+		//ok, now what do we return for the ID of the newly-inserted thing?
2989
+		if ($this->has_primary_key_field()) {
2990
+			if ($this->get_primary_key_field()->is_auto_increment()) {
2991
+				return $wpdb->insert_id;
2992
+			}
2993
+			//it's not an auto-increment primary key, so
2994
+			//it must have been supplied
2995
+			return $fields_n_values[$this->get_primary_key_field()->get_name()];
2996
+		}
2997
+		//we can't return a  primary key because there is none. instead return
2998
+		//a unique string indicating this model
2999
+		return $this->get_index_primary_key_string($fields_n_values);
3000
+	}
3001
+
3002
+
3003
+
3004
+	/**
3005
+	 * Prepare the $field_obj 's value in $fields_n_values for use in the database.
3006
+	 * If the field doesn't allow NULL, try to use its default. (If it doesn't allow NULL,
3007
+	 * and there is no default, we pass it along. WPDB will take care of it)
3008
+	 *
3009
+	 * @param EE_Model_Field_Base $field_obj
3010
+	 * @param array               $fields_n_values
3011
+	 * @return mixed string|int|float depending on what the table column will be expecting
3012
+	 * @throws EE_Error
3013
+	 */
3014
+	protected function _prepare_value_or_use_default($field_obj, $fields_n_values)
3015
+	{
3016
+		//if this field doesn't allow nullable, don't allow it
3017
+		if (
3018
+			! $field_obj->is_nullable()
3019
+			&& (
3020
+				! isset($fields_n_values[$field_obj->get_name()])
3021
+				|| $fields_n_values[$field_obj->get_name()] === null
3022
+			)
3023
+		) {
3024
+			$fields_n_values[$field_obj->get_name()] = $field_obj->get_default_value();
3025
+		}
3026
+		$unprepared_value = isset($fields_n_values[$field_obj->get_name()])
3027
+			? $fields_n_values[$field_obj->get_name()]
3028
+			: null;
3029
+		return $this->_prepare_value_for_use_in_db($unprepared_value, $field_obj);
3030
+	}
3031
+
3032
+
3033
+
3034
+	/**
3035
+	 * Consolidates code for preparing  a value supplied to the model for use int eh db. Calls the field's
3036
+	 * prepare_for_use_in_db method on the value, and depending on $value_already_prepare_by_model_obj, may also call
3037
+	 * the field's prepare_for_set() method.
3038
+	 *
3039
+	 * @param mixed               $value value in the client code domain if $value_already_prepared_by_model_object is
3040
+	 *                                   false, otherwise a value in the model object's domain (see lengthy comment at
3041
+	 *                                   top of file)
3042
+	 * @param EE_Model_Field_Base $field field which will be doing the preparing of the value. If null, we assume
3043
+	 *                                   $value is a custom selection
3044
+	 * @return mixed a value ready for use in the database for insertions, updating, or in a where clause
3045
+	 */
3046
+	private function _prepare_value_for_use_in_db($value, $field)
3047
+	{
3048
+		if ($field && $field instanceof EE_Model_Field_Base) {
3049
+			switch ($this->_values_already_prepared_by_model_object) {
3050
+				/** @noinspection PhpMissingBreakStatementInspection */
3051
+				case self::not_prepared_by_model_object:
3052
+					$value = $field->prepare_for_set($value);
3053
+				//purposefully left out "return"
3054
+				case self::prepared_by_model_object:
3055
+					/** @noinspection SuspiciousAssignmentsInspection */
3056
+					$value = $field->prepare_for_use_in_db($value);
3057
+				case self::prepared_for_use_in_db:
3058
+					//leave the value alone
3059
+			}
3060
+			return $value;
3061
+		}
3062
+		return $value;
3063
+	}
3064
+
3065
+
3066
+
3067
+	/**
3068
+	 * Returns the main table on this model
3069
+	 *
3070
+	 * @return EE_Primary_Table
3071
+	 * @throws EE_Error
3072
+	 */
3073
+	protected function _get_main_table()
3074
+	{
3075
+		foreach ($this->_tables as $table) {
3076
+			if ($table instanceof EE_Primary_Table) {
3077
+				return $table;
3078
+			}
3079
+		}
3080
+		throw new EE_Error(sprintf(__('There are no main tables on %s. They should be added to _tables array in the constructor',
3081
+			'event_espresso'), get_class($this)));
3082
+	}
3083
+
3084
+
3085
+
3086
+	/**
3087
+	 * table
3088
+	 * returns EE_Primary_Table table name
3089
+	 *
3090
+	 * @return string
3091
+	 * @throws EE_Error
3092
+	 */
3093
+	public function table()
3094
+	{
3095
+		return $this->_get_main_table()->get_table_name();
3096
+	}
3097
+
3098
+
3099
+
3100
+	/**
3101
+	 * table
3102
+	 * returns first EE_Secondary_Table table name
3103
+	 *
3104
+	 * @return string
3105
+	 */
3106
+	public function second_table()
3107
+	{
3108
+		// grab second table from tables array
3109
+		$second_table = end($this->_tables);
3110
+		return $second_table instanceof EE_Secondary_Table ? $second_table->get_table_name() : null;
3111
+	}
3112
+
3113
+
3114
+
3115
+	/**
3116
+	 * get_table_obj_by_alias
3117
+	 * returns table name given it's alias
3118
+	 *
3119
+	 * @param string $table_alias
3120
+	 * @return EE_Primary_Table | EE_Secondary_Table
3121
+	 */
3122
+	public function get_table_obj_by_alias($table_alias = '')
3123
+	{
3124
+		return isset($this->_tables[$table_alias]) ? $this->_tables[$table_alias] : null;
3125
+	}
3126
+
3127
+
3128
+
3129
+	/**
3130
+	 * Gets all the tables of type EE_Other_Table from EEM_CPT_Basel_Model::_tables
3131
+	 *
3132
+	 * @return EE_Secondary_Table[]
3133
+	 */
3134
+	protected function _get_other_tables()
3135
+	{
3136
+		$other_tables = array();
3137
+		foreach ($this->_tables as $table_alias => $table) {
3138
+			if ($table instanceof EE_Secondary_Table) {
3139
+				$other_tables[$table_alias] = $table;
3140
+			}
3141
+		}
3142
+		return $other_tables;
3143
+	}
3144
+
3145
+
3146
+
3147
+	/**
3148
+	 * Finds all the fields that correspond to the given table
3149
+	 *
3150
+	 * @param string $table_alias , array key in EEM_Base::_tables
3151
+	 * @return EE_Model_Field_Base[]
3152
+	 */
3153
+	public function _get_fields_for_table($table_alias)
3154
+	{
3155
+		return $this->_fields[$table_alias];
3156
+	}
3157
+
3158
+
3159
+
3160
+	/**
3161
+	 * Recurses through all the where parameters, and finds all the related models we'll need
3162
+	 * to complete this query. Eg, given where parameters like array('EVT_ID'=>3) from within Event model, we won't
3163
+	 * need any related models. But if the array were array('Registrations.REG_ID'=>3), we'd need the related
3164
+	 * Registration model. If it were array('Registrations.Transactions.Payments.PAY_ID'=>3), then we'd need the
3165
+	 * related Registration, Transaction, and Payment models.
3166
+	 *
3167
+	 * @param array $query_params like EEM_Base::get_all's $query_parameters['where']
3168
+	 * @return EE_Model_Query_Info_Carrier
3169
+	 * @throws EE_Error
3170
+	 */
3171
+	public function _extract_related_models_from_query($query_params)
3172
+	{
3173
+		$query_info_carrier = new EE_Model_Query_Info_Carrier();
3174
+		if (array_key_exists(0, $query_params)) {
3175
+			$this->_extract_related_models_from_sub_params_array_keys($query_params[0], $query_info_carrier, 0);
3176
+		}
3177
+		if (array_key_exists('group_by', $query_params)) {
3178
+			if (is_array($query_params['group_by'])) {
3179
+				$this->_extract_related_models_from_sub_params_array_values(
3180
+					$query_params['group_by'],
3181
+					$query_info_carrier,
3182
+					'group_by'
3183
+				);
3184
+			} elseif (! empty ($query_params['group_by'])) {
3185
+				$this->_extract_related_model_info_from_query_param(
3186
+					$query_params['group_by'],
3187
+					$query_info_carrier,
3188
+					'group_by'
3189
+				);
3190
+			}
3191
+		}
3192
+		if (array_key_exists('having', $query_params)) {
3193
+			$this->_extract_related_models_from_sub_params_array_keys(
3194
+				$query_params[0],
3195
+				$query_info_carrier,
3196
+				'having'
3197
+			);
3198
+		}
3199
+		if (array_key_exists('order_by', $query_params)) {
3200
+			if (is_array($query_params['order_by'])) {
3201
+				$this->_extract_related_models_from_sub_params_array_keys(
3202
+					$query_params['order_by'],
3203
+					$query_info_carrier,
3204
+					'order_by'
3205
+				);
3206
+			} elseif (! empty($query_params['order_by'])) {
3207
+				$this->_extract_related_model_info_from_query_param(
3208
+					$query_params['order_by'],
3209
+					$query_info_carrier,
3210
+					'order_by'
3211
+				);
3212
+			}
3213
+		}
3214
+		if (array_key_exists('force_join', $query_params)) {
3215
+			$this->_extract_related_models_from_sub_params_array_values(
3216
+				$query_params['force_join'],
3217
+				$query_info_carrier,
3218
+				'force_join'
3219
+			);
3220
+		}
3221
+		return $query_info_carrier;
3222
+	}
3223
+
3224
+
3225
+
3226
+	/**
3227
+	 * For extracting related models from WHERE (0), HAVING (having), ORDER BY (order_by) or forced joins (force_join)
3228
+	 *
3229
+	 * @param array                       $sub_query_params like EEM_Base::get_all's $query_params[0] or
3230
+	 *                                                      $query_params['having']
3231
+	 * @param EE_Model_Query_Info_Carrier $model_query_info_carrier
3232
+	 * @param string                      $query_param_type one of $this->_allowed_query_params
3233
+	 * @throws EE_Error
3234
+	 * @return \EE_Model_Query_Info_Carrier
3235
+	 */
3236
+	private function _extract_related_models_from_sub_params_array_keys(
3237
+		$sub_query_params,
3238
+		EE_Model_Query_Info_Carrier $model_query_info_carrier,
3239
+		$query_param_type
3240
+	) {
3241
+		if (! empty($sub_query_params)) {
3242
+			$sub_query_params = (array)$sub_query_params;
3243
+			foreach ($sub_query_params as $param => $possibly_array_of_params) {
3244
+				//$param could be simply 'EVT_ID', or it could be 'Registrations.REG_ID', or even 'Registrations.Transactions.Payments.PAY_amount'
3245
+				$this->_extract_related_model_info_from_query_param($param, $model_query_info_carrier,
3246
+					$query_param_type);
3247
+				//if $possibly_array_of_params is an array, try recursing into it, searching for keys which
3248
+				//indicate needed joins. Eg, array('NOT'=>array('Registration.TXN_ID'=>23)). In this case, we tried
3249
+				//extracting models out of the 'NOT', which obviously wasn't successful, and then we recurse into the value
3250
+				//of array('Registration.TXN_ID'=>23)
3251
+				$query_param_sans_stars = $this->_remove_stars_and_anything_after_from_condition_query_param_key($param);
3252
+				if (in_array($query_param_sans_stars, $this->_logic_query_param_keys, true)) {
3253
+					if (! is_array($possibly_array_of_params)) {
3254
+						throw new EE_Error(sprintf(__("You used a special where query param %s, but the value isn't an array of where query params, it's just %s'. It should be an array, eg array('EVT_ID'=>23,'OR'=>array('Venue.VNU_ID'=>32,'Venue.VNU_name'=>'monkey_land'))",
3255
+							"event_espresso"),
3256
+							$param, $possibly_array_of_params));
3257
+					}
3258
+					$this->_extract_related_models_from_sub_params_array_keys(
3259
+						$possibly_array_of_params,
3260
+						$model_query_info_carrier, $query_param_type
3261
+					);
3262
+				} elseif ($query_param_type === 0 //ie WHERE
3263
+						  && is_array($possibly_array_of_params)
3264
+						  && isset($possibly_array_of_params[2])
3265
+						  && $possibly_array_of_params[2] == true
3266
+				) {
3267
+					//then $possible_array_of_params looks something like array('<','DTT_sold',true)
3268
+					//indicating that $possible_array_of_params[1] is actually a field name,
3269
+					//from which we should extract query parameters!
3270
+					if (! isset($possibly_array_of_params[0], $possibly_array_of_params[1])) {
3271
+						throw new EE_Error(sprintf(__("Improperly formed query parameter %s. It should be numerically indexed like array('<','DTT_sold',true); but you provided %s",
3272
+							"event_espresso"), $query_param_type, implode(",", $possibly_array_of_params)));
3273
+					}
3274
+					$this->_extract_related_model_info_from_query_param($possibly_array_of_params[1],
3275
+						$model_query_info_carrier, $query_param_type);
3276
+				}
3277
+			}
3278
+		}
3279
+		return $model_query_info_carrier;
3280
+	}
3281
+
3282
+
3283
+
3284
+	/**
3285
+	 * For extracting related models from forced_joins, where the array values contain the info about what
3286
+	 * models to join with. Eg an array like array('Attendee','Price.Price_Type');
3287
+	 *
3288
+	 * @param array                       $sub_query_params like EEM_Base::get_all's $query_params[0] or
3289
+	 *                                                      $query_params['having']
3290
+	 * @param EE_Model_Query_Info_Carrier $model_query_info_carrier
3291
+	 * @param string                      $query_param_type one of $this->_allowed_query_params
3292
+	 * @throws EE_Error
3293
+	 * @return \EE_Model_Query_Info_Carrier
3294
+	 */
3295
+	private function _extract_related_models_from_sub_params_array_values(
3296
+		$sub_query_params,
3297
+		EE_Model_Query_Info_Carrier $model_query_info_carrier,
3298
+		$query_param_type
3299
+	) {
3300
+		if (! empty($sub_query_params)) {
3301
+			if (! is_array($sub_query_params)) {
3302
+				throw new EE_Error(sprintf(__("Query parameter %s should be an array, but it isn't.", "event_espresso"),
3303
+					$sub_query_params));
3304
+			}
3305
+			foreach ($sub_query_params as $param) {
3306
+				//$param could be simply 'EVT_ID', or it could be 'Registrations.REG_ID', or even 'Registrations.Transactions.Payments.PAY_amount'
3307
+				$this->_extract_related_model_info_from_query_param($param, $model_query_info_carrier,
3308
+					$query_param_type);
3309
+			}
3310
+		}
3311
+		return $model_query_info_carrier;
3312
+	}
3313
+
3314
+
3315
+
3316
+	/**
3317
+	 * Extract all the query parts from $query_params (an array like whats passed to EEM_Base::get_all)
3318
+	 * and put into a EEM_Related_Model_Info_Carrier for easy extraction into a query. We create this object
3319
+	 * instead of directly constructing the SQL because often we need to extract info from the $query_params
3320
+	 * but use them in a different order. Eg, we need to know what models we are querying
3321
+	 * before we know what joins to perform. However, we need to know what data types correspond to which fields on
3322
+	 * other models before we can finalize the where clause SQL.
3323
+	 *
3324
+	 * @param array $query_params
3325
+	 * @throws EE_Error
3326
+	 * @return EE_Model_Query_Info_Carrier
3327
+	 */
3328
+	public function _create_model_query_info_carrier($query_params)
3329
+	{
3330
+		if (! is_array($query_params)) {
3331
+			EE_Error::doing_it_wrong(
3332
+				'EEM_Base::_create_model_query_info_carrier',
3333
+				sprintf(
3334
+					__(
3335
+						'$query_params should be an array, you passed a variable of type %s',
3336
+						'event_espresso'
3337
+					),
3338
+					gettype($query_params)
3339
+				),
3340
+				'4.6.0'
3341
+			);
3342
+			$query_params = array();
3343
+		}
3344
+		$where_query_params = isset($query_params[0]) ? $query_params[0] : array();
3345
+		//first check if we should alter the query to account for caps or not
3346
+		//because the caps might require us to do extra joins
3347
+		if (isset($query_params['caps']) && $query_params['caps'] !== 'none') {
3348
+			$query_params[0] = $where_query_params = array_replace_recursive(
3349
+				$where_query_params,
3350
+				$this->caps_where_conditions(
3351
+					$query_params['caps']
3352
+				)
3353
+			);
3354
+		}
3355
+		$query_object = $this->_extract_related_models_from_query($query_params);
3356
+		//verify where_query_params has NO numeric indexes.... that's simply not how you use it!
3357
+		foreach ($where_query_params as $key => $value) {
3358
+			if (is_int($key)) {
3359
+				throw new EE_Error(
3360
+					sprintf(
3361
+						__(
3362
+							"WHERE query params must NOT be numerically-indexed. You provided the array key '%s' for value '%s' while querying model %s. All the query params provided were '%s' Please read documentation on EEM_Base::get_all.",
3363
+							"event_espresso"
3364
+						),
3365
+						$key,
3366
+						var_export($value, true),
3367
+						var_export($query_params, true),
3368
+						get_class($this)
3369
+					)
3370
+				);
3371
+			}
3372
+		}
3373
+		if (
3374
+			array_key_exists('default_where_conditions', $query_params)
3375
+			&& ! empty($query_params['default_where_conditions'])
3376
+		) {
3377
+			$use_default_where_conditions = $query_params['default_where_conditions'];
3378
+		} else {
3379
+			$use_default_where_conditions = EEM_Base::default_where_conditions_all;
3380
+		}
3381
+		$where_query_params = array_merge(
3382
+			$this->_get_default_where_conditions_for_models_in_query(
3383
+				$query_object,
3384
+				$use_default_where_conditions,
3385
+				$where_query_params
3386
+			),
3387
+			$where_query_params
3388
+		);
3389
+		$query_object->set_where_sql($this->_construct_where_clause($where_query_params));
3390
+		// if this is a "on_join_limit" then we are limiting on on a specific table in a multi_table join.
3391
+		// So we need to setup a subquery and use that for the main join.
3392
+		// Note for now this only works on the primary table for the model.
3393
+		// So for instance, you could set the limit array like this:
3394
+		// array( 'on_join_limit' => array('Primary_Table_Alias', array(1,10) ) )
3395
+		if (array_key_exists('on_join_limit', $query_params) && ! empty($query_params['on_join_limit'])) {
3396
+			$query_object->set_main_model_join_sql(
3397
+				$this->_construct_limit_join_select(
3398
+					$query_params['on_join_limit'][0],
3399
+					$query_params['on_join_limit'][1]
3400
+				)
3401
+			);
3402
+		}
3403
+		//set limit
3404
+		if (array_key_exists('limit', $query_params)) {
3405
+			if (is_array($query_params['limit'])) {
3406
+				if (! isset($query_params['limit'][0], $query_params['limit'][1])) {
3407
+					$e = sprintf(
3408
+						__(
3409
+							"Invalid DB query. You passed '%s' for the LIMIT, but only the following are valid: an integer, string representing an integer, a string like 'int,int', or an array like array(int,int)",
3410
+							"event_espresso"
3411
+						),
3412
+						http_build_query($query_params['limit'])
3413
+					);
3414
+					throw new EE_Error($e . "|" . $e);
3415
+				}
3416
+				//they passed us an array for the limit. Assume it's like array(50,25), meaning offset by 50, and get 25
3417
+				$query_object->set_limit_sql(" LIMIT " . $query_params['limit'][0] . "," . $query_params['limit'][1]);
3418
+			} elseif (! empty ($query_params['limit'])) {
3419
+				$query_object->set_limit_sql(" LIMIT " . $query_params['limit']);
3420
+			}
3421
+		}
3422
+		//set order by
3423
+		if (array_key_exists('order_by', $query_params)) {
3424
+			if (is_array($query_params['order_by'])) {
3425
+				//if they're using 'order_by' as an array, they can't use 'order' (because 'order_by' must
3426
+				//specify whether to ascend or descend on each field. Eg 'order_by'=>array('EVT_ID'=>'ASC'). So
3427
+				//including 'order' wouldn't make any sense if 'order_by' has already specified which way to order!
3428
+				if (array_key_exists('order', $query_params)) {
3429
+					throw new EE_Error(
3430
+						sprintf(
3431
+							__(
3432
+								"In querying %s, we are using query parameter 'order_by' as an array (keys:%s,values:%s), and so we can't use query parameter 'order' (value %s). You should just use the 'order_by' parameter ",
3433
+								"event_espresso"
3434
+							),
3435
+							get_class($this),
3436
+							implode(", ", array_keys($query_params['order_by'])),
3437
+							implode(", ", $query_params['order_by']),
3438
+							$query_params['order']
3439
+						)
3440
+					);
3441
+				}
3442
+				$this->_extract_related_models_from_sub_params_array_keys(
3443
+					$query_params['order_by'],
3444
+					$query_object,
3445
+					'order_by'
3446
+				);
3447
+				//assume it's an array of fields to order by
3448
+				$order_array = array();
3449
+				foreach ($query_params['order_by'] as $field_name_to_order_by => $order) {
3450
+					$order = $this->_extract_order($order);
3451
+					$order_array[] = $this->_deduce_column_name_from_query_param($field_name_to_order_by) . SP . $order;
3452
+				}
3453
+				$query_object->set_order_by_sql(" ORDER BY " . implode(",", $order_array));
3454
+			} elseif (! empty ($query_params['order_by'])) {
3455
+				$this->_extract_related_model_info_from_query_param(
3456
+					$query_params['order_by'],
3457
+					$query_object,
3458
+					'order',
3459
+					$query_params['order_by']
3460
+				);
3461
+				$order = isset($query_params['order'])
3462
+					? $this->_extract_order($query_params['order'])
3463
+					: 'DESC';
3464
+				$query_object->set_order_by_sql(
3465
+					" ORDER BY " . $this->_deduce_column_name_from_query_param($query_params['order_by']) . SP . $order
3466
+				);
3467
+			}
3468
+		}
3469
+		//if 'order_by' wasn't set, maybe they are just using 'order' on its own?
3470
+		if (! array_key_exists('order_by', $query_params)
3471
+			&& array_key_exists('order', $query_params)
3472
+			&& ! empty($query_params['order'])
3473
+		) {
3474
+			$pk_field = $this->get_primary_key_field();
3475
+			$order = $this->_extract_order($query_params['order']);
3476
+			$query_object->set_order_by_sql(" ORDER BY " . $pk_field->get_qualified_column() . SP . $order);
3477
+		}
3478
+		//set group by
3479
+		if (array_key_exists('group_by', $query_params)) {
3480
+			if (is_array($query_params['group_by'])) {
3481
+				//it's an array, so assume we'll be grouping by a bunch of stuff
3482
+				$group_by_array = array();
3483
+				foreach ($query_params['group_by'] as $field_name_to_group_by) {
3484
+					$group_by_array[] = $this->_deduce_column_name_from_query_param($field_name_to_group_by);
3485
+				}
3486
+				$query_object->set_group_by_sql(" GROUP BY " . implode(", ", $group_by_array));
3487
+			} elseif (! empty ($query_params['group_by'])) {
3488
+				$query_object->set_group_by_sql(
3489
+					" GROUP BY " . $this->_deduce_column_name_from_query_param($query_params['group_by'])
3490
+				);
3491
+			}
3492
+		}
3493
+		//set having
3494
+		if (array_key_exists('having', $query_params) && $query_params['having']) {
3495
+			$query_object->set_having_sql($this->_construct_having_clause($query_params['having']));
3496
+		}
3497
+		//now, just verify they didn't pass anything wack
3498
+		foreach ($query_params as $query_key => $query_value) {
3499
+			if (! in_array($query_key, $this->_allowed_query_params, true)) {
3500
+				throw new EE_Error(
3501
+					sprintf(
3502
+						__(
3503
+							"You passed %s as a query parameter to %s, which is illegal! The allowed query parameters are %s",
3504
+							'event_espresso'
3505
+						),
3506
+						$query_key,
3507
+						get_class($this),
3508
+						//						print_r( $this->_allowed_query_params, TRUE )
3509
+						implode(',', $this->_allowed_query_params)
3510
+					)
3511
+				);
3512
+			}
3513
+		}
3514
+		$main_model_join_sql = $query_object->get_main_model_join_sql();
3515
+		if (empty($main_model_join_sql)) {
3516
+			$query_object->set_main_model_join_sql($this->_construct_internal_join());
3517
+		}
3518
+		return $query_object;
3519
+	}
3520
+
3521
+
3522
+
3523
+	/**
3524
+	 * Gets the where conditions that should be imposed on the query based on the
3525
+	 * context (eg reading frontend, backend, edit or delete).
3526
+	 *
3527
+	 * @param string $context one of EEM_Base::valid_cap_contexts()
3528
+	 * @return array like EEM_Base::get_all() 's $query_params[0]
3529
+	 * @throws EE_Error
3530
+	 */
3531
+	public function caps_where_conditions($context = self::caps_read)
3532
+	{
3533
+		EEM_Base::verify_is_valid_cap_context($context);
3534
+		$cap_where_conditions = array();
3535
+		$cap_restrictions = $this->caps_missing($context);
3536
+		/**
3537
+		 * @var $cap_restrictions EE_Default_Where_Conditions[]
3538
+		 */
3539
+		foreach ($cap_restrictions as $cap => $restriction_if_no_cap) {
3540
+			$cap_where_conditions = array_replace_recursive($cap_where_conditions,
3541
+				$restriction_if_no_cap->get_default_where_conditions());
3542
+		}
3543
+		return apply_filters('FHEE__EEM_Base__caps_where_conditions__return', $cap_where_conditions, $this, $context,
3544
+			$cap_restrictions);
3545
+	}
3546
+
3547
+
3548
+
3549
+	/**
3550
+	 * Verifies that $should_be_order_string is in $this->_allowed_order_values,
3551
+	 * otherwise throws an exception
3552
+	 *
3553
+	 * @param string $should_be_order_string
3554
+	 * @return string either ASC, asc, DESC or desc
3555
+	 * @throws EE_Error
3556
+	 */
3557
+	private function _extract_order($should_be_order_string)
3558
+	{
3559
+		if (in_array($should_be_order_string, $this->_allowed_order_values)) {
3560
+			return $should_be_order_string;
3561
+		}
3562
+		throw new EE_Error(
3563
+			sprintf(
3564
+				__(
3565
+					"While performing a query on '%s', tried to use '%s' as an order parameter. ",
3566
+					"event_espresso"
3567
+				), get_class($this), $should_be_order_string
3568
+			)
3569
+		);
3570
+	}
3571
+
3572
+
3573
+
3574
+	/**
3575
+	 * Looks at all the models which are included in this query, and asks each
3576
+	 * for their universal_where_params, and returns them in the same format as $query_params[0] (where),
3577
+	 * so they can be merged
3578
+	 *
3579
+	 * @param EE_Model_Query_Info_Carrier $query_info_carrier
3580
+	 * @param string                      $use_default_where_conditions can be 'none','other_models_only', or 'all'.
3581
+	 *                                                                  'none' means NO default where conditions will
3582
+	 *                                                                  be used AT ALL during this query.
3583
+	 *                                                                  'other_models_only' means default where
3584
+	 *                                                                  conditions from other models will be used, but
3585
+	 *                                                                  not for this primary model. 'all', the default,
3586
+	 *                                                                  means default where conditions will apply as
3587
+	 *                                                                  normal
3588
+	 * @param array                       $where_query_params           like EEM_Base::get_all's $query_params[0]
3589
+	 * @throws EE_Error
3590
+	 * @return array like $query_params[0], see EEM_Base::get_all for documentation
3591
+	 */
3592
+	private function _get_default_where_conditions_for_models_in_query(
3593
+		EE_Model_Query_Info_Carrier $query_info_carrier,
3594
+		$use_default_where_conditions = EEM_Base::default_where_conditions_all,
3595
+		$where_query_params = array()
3596
+	) {
3597
+		$allowed_used_default_where_conditions_values = EEM_Base::valid_default_where_conditions();
3598
+		if (! in_array($use_default_where_conditions, $allowed_used_default_where_conditions_values)) {
3599
+			throw new EE_Error(sprintf(__("You passed an invalid value to the query parameter 'default_where_conditions' of '%s'. Allowed values are %s",
3600
+				"event_espresso"), $use_default_where_conditions,
3601
+				implode(", ", $allowed_used_default_where_conditions_values)));
3602
+		}
3603
+		$universal_query_params = array();
3604
+		if ($this->_should_use_default_where_conditions( $use_default_where_conditions, true)) {
3605
+			$universal_query_params = $this->_get_default_where_conditions();
3606
+		} else if ($this->_should_use_minimum_where_conditions( $use_default_where_conditions, true)) {
3607
+			$universal_query_params = $this->_get_minimum_where_conditions();
3608
+		}
3609
+		foreach ($query_info_carrier->get_model_names_included() as $model_relation_path => $model_name) {
3610
+			$related_model = $this->get_related_model_obj($model_name);
3611
+			if ( $this->_should_use_default_where_conditions( $use_default_where_conditions, false)) {
3612
+				$related_model_universal_where_params = $related_model->_get_default_where_conditions($model_relation_path);
3613
+			} elseif ($this->_should_use_minimum_where_conditions( $use_default_where_conditions, false)) {
3614
+				$related_model_universal_where_params = $related_model->_get_minimum_where_conditions($model_relation_path);
3615
+			} else {
3616
+				//we don't want to add full or even minimum default where conditions from this model, so just continue
3617
+				continue;
3618
+			}
3619
+			$overrides = $this->_override_defaults_or_make_null_friendly(
3620
+				$related_model_universal_where_params,
3621
+				$where_query_params,
3622
+				$related_model,
3623
+				$model_relation_path
3624
+			);
3625
+			$universal_query_params = EEH_Array::merge_arrays_and_overwrite_keys(
3626
+				$universal_query_params,
3627
+				$overrides
3628
+			);
3629
+		}
3630
+		return $universal_query_params;
3631
+	}
3632
+
3633
+
3634
+
3635
+	/**
3636
+	 * Determines whether or not we should use default where conditions for the model in question
3637
+	 * (this model, or other related models).
3638
+	 * Basically, we should use default where conditions on this model if they have requested to use them on all models,
3639
+	 * this model only, or to use minimum where conditions on all other models and normal where conditions on this one.
3640
+	 * We should use default where conditions on related models when they requested to use default where conditions
3641
+	 * on all models, or specifically just on other related models
3642
+	 * @param      $default_where_conditions_value
3643
+	 * @param bool $for_this_model false means this is for OTHER related models
3644
+	 * @return bool
3645
+	 */
3646
+	private function _should_use_default_where_conditions( $default_where_conditions_value, $for_this_model = true )
3647
+	{
3648
+		return (
3649
+				   $for_this_model
3650
+				   && in_array(
3651
+					   $default_where_conditions_value,
3652
+					   array(
3653
+						   EEM_Base::default_where_conditions_all,
3654
+						   EEM_Base::default_where_conditions_this_only,
3655
+						   EEM_Base::default_where_conditions_minimum_others,
3656
+					   ),
3657
+					   true
3658
+				   )
3659
+			   )
3660
+			   || (
3661
+				   ! $for_this_model
3662
+				   && in_array(
3663
+					   $default_where_conditions_value,
3664
+					   array(
3665
+						   EEM_Base::default_where_conditions_all,
3666
+						   EEM_Base::default_where_conditions_others_only,
3667
+					   ),
3668
+					   true
3669
+				   )
3670
+			   );
3671
+	}
3672
+
3673
+	/**
3674
+	 * Determines whether or not we should use default minimum conditions for the model in question
3675
+	 * (this model, or other related models).
3676
+	 * Basically, we should use minimum where conditions on this model only if they requested all models to use minimum
3677
+	 * where conditions.
3678
+	 * We should use minimum where conditions on related models if they requested to use minimum where conditions
3679
+	 * on this model or others
3680
+	 * @param      $default_where_conditions_value
3681
+	 * @param bool $for_this_model false means this is for OTHER related models
3682
+	 * @return bool
3683
+	 */
3684
+	private function _should_use_minimum_where_conditions($default_where_conditions_value, $for_this_model = true)
3685
+	{
3686
+		return (
3687
+				   $for_this_model
3688
+				   && $default_where_conditions_value === EEM_Base::default_where_conditions_minimum_all
3689
+			   )
3690
+			   || (
3691
+				   ! $for_this_model
3692
+				   && in_array(
3693
+					   $default_where_conditions_value,
3694
+					   array(
3695
+						   EEM_Base::default_where_conditions_minimum_others,
3696
+						   EEM_Base::default_where_conditions_minimum_all,
3697
+					   ),
3698
+					   true
3699
+				   )
3700
+			   );
3701
+	}
3702
+
3703
+
3704
+	/**
3705
+	 * Checks if any of the defaults have been overridden. If there are any that AREN'T overridden,
3706
+	 * then we also add a special where condition which allows for that model's primary key
3707
+	 * to be null (which is important for JOINs. Eg, if you want to see all Events ordered by Venue's name,
3708
+	 * then Event's with NO Venue won't appear unless you allow VNU_ID to be NULL)
3709
+	 *
3710
+	 * @param array    $default_where_conditions
3711
+	 * @param array    $provided_where_conditions
3712
+	 * @param EEM_Base $model
3713
+	 * @param string   $model_relation_path like 'Transaction.Payment.'
3714
+	 * @return array like EEM_Base::get_all's $query_params[0]
3715
+	 * @throws EE_Error
3716
+	 */
3717
+	private function _override_defaults_or_make_null_friendly(
3718
+		$default_where_conditions,
3719
+		$provided_where_conditions,
3720
+		$model,
3721
+		$model_relation_path
3722
+	) {
3723
+		$null_friendly_where_conditions = array();
3724
+		$none_overridden = true;
3725
+		$or_condition_key_for_defaults = 'OR*' . get_class($model);
3726
+		foreach ($default_where_conditions as $key => $val) {
3727
+			if (isset($provided_where_conditions[$key])) {
3728
+				$none_overridden = false;
3729
+			} else {
3730
+				$null_friendly_where_conditions[$or_condition_key_for_defaults]['AND'][$key] = $val;
3731
+			}
3732
+		}
3733
+		if ($none_overridden && $default_where_conditions) {
3734
+			if ($model->has_primary_key_field()) {
3735
+				$null_friendly_where_conditions[$or_condition_key_for_defaults][$model_relation_path
3736
+																				. "."
3737
+																				. $model->primary_key_name()] = array('IS NULL');
3738
+			}/*else{
3739 3739
 				//@todo NO PK, use other defaults
3740 3740
 			}*/
3741
-        }
3742
-        return $null_friendly_where_conditions;
3743
-    }
3744
-
3745
-
3746
-
3747
-    /**
3748
-     * Uses the _default_where_conditions_strategy set during __construct() to get
3749
-     * default where conditions on all get_all, update, and delete queries done by this model.
3750
-     * Use the same syntax as client code. Eg on the Event model, use array('Event.EVT_post_type'=>'esp_event'),
3751
-     * NOT array('Event_CPT.post_type'=>'esp_event').
3752
-     *
3753
-     * @param string $model_relation_path eg, path from Event to Payment is "Registration.Transaction.Payment."
3754
-     * @return array like EEM_Base::get_all's $query_params[0] (where conditions)
3755
-     */
3756
-    private function _get_default_where_conditions($model_relation_path = null)
3757
-    {
3758
-        if ($this->_ignore_where_strategy) {
3759
-            return array();
3760
-        }
3761
-        return $this->_default_where_conditions_strategy->get_default_where_conditions($model_relation_path);
3762
-    }
3763
-
3764
-
3765
-
3766
-    /**
3767
-     * Uses the _minimum_where_conditions_strategy set during __construct() to get
3768
-     * minimum where conditions on all get_all, update, and delete queries done by this model.
3769
-     * Use the same syntax as client code. Eg on the Event model, use array('Event.EVT_post_type'=>'esp_event'),
3770
-     * NOT array('Event_CPT.post_type'=>'esp_event').
3771
-     * Similar to _get_default_where_conditions
3772
-     *
3773
-     * @param string $model_relation_path eg, path from Event to Payment is "Registration.Transaction.Payment."
3774
-     * @return array like EEM_Base::get_all's $query_params[0] (where conditions)
3775
-     */
3776
-    protected function _get_minimum_where_conditions($model_relation_path = null)
3777
-    {
3778
-        if ($this->_ignore_where_strategy) {
3779
-            return array();
3780
-        }
3781
-        return $this->_minimum_where_conditions_strategy->get_default_where_conditions($model_relation_path);
3782
-    }
3783
-
3784
-
3785
-
3786
-    /**
3787
-     * Creates the string of SQL for the select part of a select query, everything behind SELECT and before FROM.
3788
-     * Eg, "Event.post_id, Event.post_name,Event_Detail.EVT_ID..."
3789
-     *
3790
-     * @param EE_Model_Query_Info_Carrier $model_query_info
3791
-     * @return string
3792
-     * @throws EE_Error
3793
-     */
3794
-    private function _construct_default_select_sql(EE_Model_Query_Info_Carrier $model_query_info)
3795
-    {
3796
-        $selects = $this->_get_columns_to_select_for_this_model();
3797
-        foreach (
3798
-            $model_query_info->get_model_names_included() as $model_relation_chain =>
3799
-            $name_of_other_model_included
3800
-        ) {
3801
-            $other_model_included = $this->get_related_model_obj($name_of_other_model_included);
3802
-            $other_model_selects = $other_model_included->_get_columns_to_select_for_this_model($model_relation_chain);
3803
-            foreach ($other_model_selects as $key => $value) {
3804
-                $selects[] = $value;
3805
-            }
3806
-        }
3807
-        return implode(", ", $selects);
3808
-    }
3809
-
3810
-
3811
-
3812
-    /**
3813
-     * Gets an array of columns to select for this model, which are necessary for it to create its objects.
3814
-     * So that's going to be the columns for all the fields on the model
3815
-     *
3816
-     * @param string $model_relation_chain like 'Question.Question_Group.Event'
3817
-     * @return array numerically indexed, values are columns to select and rename, eg "Event.ID AS 'Event.ID'"
3818
-     */
3819
-    public function _get_columns_to_select_for_this_model($model_relation_chain = '')
3820
-    {
3821
-        $fields = $this->field_settings();
3822
-        $selects = array();
3823
-        $table_alias_with_model_relation_chain_prefix = EE_Model_Parser::extract_table_alias_model_relation_chain_prefix($model_relation_chain,
3824
-            $this->get_this_model_name());
3825
-        foreach ($fields as $field_obj) {
3826
-            $selects[] = $table_alias_with_model_relation_chain_prefix
3827
-                         . $field_obj->get_table_alias()
3828
-                         . "."
3829
-                         . $field_obj->get_table_column()
3830
-                         . " AS '"
3831
-                         . $table_alias_with_model_relation_chain_prefix
3832
-                         . $field_obj->get_table_alias()
3833
-                         . "."
3834
-                         . $field_obj->get_table_column()
3835
-                         . "'";
3836
-        }
3837
-        //make sure we are also getting the PKs of each table
3838
-        $tables = $this->get_tables();
3839
-        if (count($tables) > 1) {
3840
-            foreach ($tables as $table_obj) {
3841
-                $qualified_pk_column = $table_alias_with_model_relation_chain_prefix
3842
-                                       . $table_obj->get_fully_qualified_pk_column();
3843
-                if (! in_array($qualified_pk_column, $selects)) {
3844
-                    $selects[] = "$qualified_pk_column AS '$qualified_pk_column'";
3845
-                }
3846
-            }
3847
-        }
3848
-        return $selects;
3849
-    }
3850
-
3851
-
3852
-
3853
-    /**
3854
-     * Given a $query_param like 'Registration.Transaction.TXN_ID', pops off 'Registration.',
3855
-     * gets the join statement for it; gets the data types for it; and passes the remaining 'Transaction.TXN_ID'
3856
-     * onto its related Transaction object to do the same. Returns an EE_Join_And_Data_Types object which contains the
3857
-     * SQL for joining, and the data types
3858
-     *
3859
-     * @param null|string                 $original_query_param
3860
-     * @param string                      $query_param          like Registration.Transaction.TXN_ID
3861
-     * @param EE_Model_Query_Info_Carrier $passed_in_query_info
3862
-     * @param    string                   $query_param_type     like Registration.Transaction.TXN_ID
3863
-     *                                                          or 'PAY_ID'. Otherwise, we don't expect there to be a
3864
-     *                                                          column name. We only want model names, eg 'Event.Venue'
3865
-     *                                                          or 'Registration's
3866
-     * @param string                      $original_query_param what it originally was (eg
3867
-     *                                                          Registration.Transaction.TXN_ID). If null, we assume it
3868
-     *                                                          matches $query_param
3869
-     * @throws EE_Error
3870
-     * @return void only modifies the EEM_Related_Model_Info_Carrier passed into it
3871
-     */
3872
-    private function _extract_related_model_info_from_query_param(
3873
-        $query_param,
3874
-        EE_Model_Query_Info_Carrier $passed_in_query_info,
3875
-        $query_param_type,
3876
-        $original_query_param = null
3877
-    ) {
3878
-        if ($original_query_param === null) {
3879
-            $original_query_param = $query_param;
3880
-        }
3881
-        $query_param = $this->_remove_stars_and_anything_after_from_condition_query_param_key($query_param);
3882
-        /** @var $allow_logic_query_params bool whether or not to allow logic_query_params like 'NOT','OR', or 'AND' */
3883
-        $allow_logic_query_params = in_array($query_param_type, array('where', 'having'));
3884
-        $allow_fields = in_array($query_param_type, array('where', 'having', 'order_by', 'group_by', 'order'));
3885
-        //check to see if we have a field on this model
3886
-        $this_model_fields = $this->field_settings(true);
3887
-        if (array_key_exists($query_param, $this_model_fields)) {
3888
-            if ($allow_fields) {
3889
-                return;
3890
-            }
3891
-            throw new EE_Error(
3892
-                sprintf(
3893
-                    __(
3894
-                        "Using a field name (%s) on model %s is not allowed on this query param type '%s'. Original query param was %s",
3895
-                        "event_espresso"
3896
-                    ),
3897
-                    $query_param, get_class($this), $query_param_type, $original_query_param
3898
-                )
3899
-            );
3900
-        }
3901
-        //check if this is a special logic query param
3902
-        if (in_array($query_param, $this->_logic_query_param_keys, true)) {
3903
-            if ($allow_logic_query_params) {
3904
-                return;
3905
-            }
3906
-            throw new EE_Error(
3907
-                sprintf(
3908
-                    __(
3909
-                        'Logic query params ("%1$s") are being used incorrectly with the following query param ("%2$s") on model %3$s. %4$sAdditional Info:%4$s%5$s',
3910
-                        'event_espresso'
3911
-                    ),
3912
-                    implode('", "', $this->_logic_query_param_keys),
3913
-                    $query_param,
3914
-                    get_class($this),
3915
-                    '<br />',
3916
-                    "\t"
3917
-                    . ' $passed_in_query_info = <pre>'
3918
-                    . print_r($passed_in_query_info, true)
3919
-                    . '</pre>'
3920
-                    . "\n\t"
3921
-                    . ' $query_param_type = '
3922
-                    . $query_param_type
3923
-                    . "\n\t"
3924
-                    . ' $original_query_param = '
3925
-                    . $original_query_param
3926
-                )
3927
-            );
3928
-        }
3929
-        //check if it's a custom selection
3930
-        if (array_key_exists($query_param, $this->_custom_selections)) {
3931
-            return;
3932
-        }
3933
-        //check if has a model name at the beginning
3934
-        //and
3935
-        //check if it's a field on a related model
3936
-        foreach ($this->_model_relations as $valid_related_model_name => $relation_obj) {
3937
-            if (strpos($query_param, $valid_related_model_name . ".") === 0) {
3938
-                $this->_add_join_to_model($valid_related_model_name, $passed_in_query_info, $original_query_param);
3939
-                $query_param = substr($query_param, strlen($valid_related_model_name . "."));
3940
-                if ($query_param === '') {
3941
-                    //nothing left to $query_param
3942
-                    //we should actually end in a field name, not a model like this!
3943
-                    throw new EE_Error(sprintf(__("Query param '%s' (of type %s on model %s) shouldn't end on a period (.) ",
3944
-                        "event_espresso"),
3945
-                        $query_param, $query_param_type, get_class($this), $valid_related_model_name));
3946
-                }
3947
-                $related_model_obj = $this->get_related_model_obj($valid_related_model_name);
3948
-                $related_model_obj->_extract_related_model_info_from_query_param(
3949
-                    $query_param,
3950
-                    $passed_in_query_info, $query_param_type, $original_query_param
3951
-                );
3952
-                return;
3953
-            }
3954
-            if ($query_param === $valid_related_model_name) {
3955
-                $this->_add_join_to_model($valid_related_model_name, $passed_in_query_info, $original_query_param);
3956
-                return;
3957
-            }
3958
-        }
3959
-        //ok so $query_param didn't start with a model name
3960
-        //and we previously confirmed it wasn't a logic query param or field on the current model
3961
-        //it's wack, that's what it is
3962
-        throw new EE_Error(sprintf(__("There is no model named '%s' related to %s. Query param type is %s and original query param is %s",
3963
-            "event_espresso"),
3964
-            $query_param, get_class($this), $query_param_type, $original_query_param));
3965
-    }
3966
-
3967
-
3968
-
3969
-    /**
3970
-     * Privately used by _extract_related_model_info_from_query_param to add a join to $model_name
3971
-     * and store it on $passed_in_query_info
3972
-     *
3973
-     * @param string                      $model_name
3974
-     * @param EE_Model_Query_Info_Carrier $passed_in_query_info
3975
-     * @param string                      $original_query_param used to extract the relation chain between the queried
3976
-     *                                                          model and $model_name. Eg, if we are querying Event,
3977
-     *                                                          and are adding a join to 'Payment' with the original
3978
-     *                                                          query param key
3979
-     *                                                          'Registration.Transaction.Payment.PAY_amount', we want
3980
-     *                                                          to extract 'Registration.Transaction.Payment', in case
3981
-     *                                                          Payment wants to add default query params so that it
3982
-     *                                                          will know what models to prepend onto its default query
3983
-     *                                                          params or in case it wants to rename tables (in case
3984
-     *                                                          there are multiple joins to the same table)
3985
-     * @return void
3986
-     * @throws EE_Error
3987
-     */
3988
-    private function _add_join_to_model(
3989
-        $model_name,
3990
-        EE_Model_Query_Info_Carrier $passed_in_query_info,
3991
-        $original_query_param
3992
-    ) {
3993
-        $relation_obj = $this->related_settings_for($model_name);
3994
-        $model_relation_chain = EE_Model_Parser::extract_model_relation_chain($model_name, $original_query_param);
3995
-        //check if the relation is HABTM, because then we're essentially doing two joins
3996
-        //If so, join first to the JOIN table, and add its data types, and then continue as normal
3997
-        if ($relation_obj instanceof EE_HABTM_Relation) {
3998
-            $join_model_obj = $relation_obj->get_join_model();
3999
-            //replace the model specified with the join model for this relation chain, whi
4000
-            $relation_chain_to_join_model = EE_Model_Parser::replace_model_name_with_join_model_name_in_model_relation_chain($model_name,
4001
-                $join_model_obj->get_this_model_name(), $model_relation_chain);
4002
-            $passed_in_query_info->merge(
4003
-                new EE_Model_Query_Info_Carrier(
4004
-                    array($relation_chain_to_join_model => $join_model_obj->get_this_model_name()),
4005
-                    $relation_obj->get_join_to_intermediate_model_statement($relation_chain_to_join_model)
4006
-                )
4007
-            );
4008
-        }
4009
-        //now just join to the other table pointed to by the relation object, and add its data types
4010
-        $passed_in_query_info->merge(
4011
-            new EE_Model_Query_Info_Carrier(
4012
-                array($model_relation_chain => $model_name),
4013
-                $relation_obj->get_join_statement($model_relation_chain)
4014
-            )
4015
-        );
4016
-    }
4017
-
4018
-
4019
-
4020
-    /**
4021
-     * Constructs SQL for where clause, like "WHERE Event.ID = 23 AND Transaction.amount > 100" etc.
4022
-     *
4023
-     * @param array $where_params like EEM_Base::get_all
4024
-     * @return string of SQL
4025
-     * @throws EE_Error
4026
-     */
4027
-    private function _construct_where_clause($where_params)
4028
-    {
4029
-        $SQL = $this->_construct_condition_clause_recursive($where_params, ' AND ');
4030
-        if ($SQL) {
4031
-            return " WHERE " . $SQL;
4032
-        }
4033
-        return '';
4034
-    }
4035
-
4036
-
4037
-
4038
-    /**
4039
-     * Just like the _construct_where_clause, except prepends 'HAVING' instead of 'WHERE',
4040
-     * and should be passed HAVING parameters, not WHERE parameters
4041
-     *
4042
-     * @param array $having_params
4043
-     * @return string
4044
-     * @throws EE_Error
4045
-     */
4046
-    private function _construct_having_clause($having_params)
4047
-    {
4048
-        $SQL = $this->_construct_condition_clause_recursive($having_params, ' AND ');
4049
-        if ($SQL) {
4050
-            return " HAVING " . $SQL;
4051
-        }
4052
-        return '';
4053
-    }
4054
-
4055
-
4056
-    /**
4057
-     * Used for creating nested WHERE conditions. Eg "WHERE ! (Event.ID = 3 OR ( Event_Meta.meta_key = 'bob' AND
4058
-     * Event_Meta.meta_value = 'foo'))"
4059
-     *
4060
-     * @param array  $where_params see EEM_Base::get_all for documentation
4061
-     * @param string $glue         joins each subclause together. Should really only be " AND " or " OR "...
4062
-     * @throws EE_Error
4063
-     * @return string of SQL
4064
-     */
4065
-    private function _construct_condition_clause_recursive($where_params, $glue = ' AND')
4066
-    {
4067
-        $where_clauses = array();
4068
-        foreach ($where_params as $query_param => $op_and_value_or_sub_condition) {
4069
-            $query_param = $this->_remove_stars_and_anything_after_from_condition_query_param_key($query_param);//str_replace("*",'',$query_param);
4070
-            if (in_array($query_param, $this->_logic_query_param_keys)) {
4071
-                switch ($query_param) {
4072
-                    case 'not':
4073
-                    case 'NOT':
4074
-                        $where_clauses[] = "! ("
4075
-                                           . $this->_construct_condition_clause_recursive($op_and_value_or_sub_condition,
4076
-                                $glue)
4077
-                                           . ")";
4078
-                        break;
4079
-                    case 'and':
4080
-                    case 'AND':
4081
-                        $where_clauses[] = " ("
4082
-                                           . $this->_construct_condition_clause_recursive($op_and_value_or_sub_condition,
4083
-                                ' AND ')
4084
-                                           . ")";
4085
-                        break;
4086
-                    case 'or':
4087
-                    case 'OR':
4088
-                        $where_clauses[] = " ("
4089
-                                           . $this->_construct_condition_clause_recursive($op_and_value_or_sub_condition,
4090
-                                ' OR ')
4091
-                                           . ")";
4092
-                        break;
4093
-                }
4094
-            } else {
4095
-                $field_obj = $this->_deduce_field_from_query_param($query_param);
4096
-                //if it's not a normal field, maybe it's a custom selection?
4097
-                if (! $field_obj) {
4098
-                    if (isset($this->_custom_selections[$query_param][1])) {
4099
-                        $field_obj = $this->_custom_selections[$query_param][1];
4100
-                    } else {
4101
-                        throw new EE_Error(sprintf(__("%s is neither a valid model field name, nor a custom selection",
4102
-                            "event_espresso"), $query_param));
4103
-                    }
4104
-                }
4105
-                $op_and_value_sql = $this->_construct_op_and_value($op_and_value_or_sub_condition, $field_obj);
4106
-                $where_clauses[] = $this->_deduce_column_name_from_query_param($query_param) . SP . $op_and_value_sql;
4107
-            }
4108
-        }
4109
-        return $where_clauses ? implode($glue, $where_clauses) : '';
4110
-    }
4111
-
4112
-
4113
-
4114
-    /**
4115
-     * Takes the input parameter and extract the table name (alias) and column name
4116
-     *
4117
-     * @param string $query_param like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
4118
-     * @throws EE_Error
4119
-     * @return string table alias and column name for SQL, eg "Transaction.TXN_ID"
4120
-     */
4121
-    private function _deduce_column_name_from_query_param($query_param)
4122
-    {
4123
-        $field = $this->_deduce_field_from_query_param($query_param);
4124
-        if ($field) {
4125
-            $table_alias_prefix = EE_Model_Parser::extract_table_alias_model_relation_chain_from_query_param($field->get_model_name(),
4126
-                $query_param);
4127
-            return $table_alias_prefix . $field->get_qualified_column();
4128
-        }
4129
-        if (array_key_exists($query_param, $this->_custom_selections)) {
4130
-            //maybe it's custom selection item?
4131
-            //if so, just use it as the "column name"
4132
-            return $query_param;
4133
-        }
4134
-        throw new EE_Error(
4135
-            sprintf(
4136
-                __(
4137
-                    "%s is not a valid field on this model, nor a custom selection (%s)",
4138
-                    "event_espresso"
4139
-                ), $query_param, implode(",", $this->_custom_selections)
4140
-            )
4141
-        );
4142
-    }
4143
-
4144
-
4145
-
4146
-    /**
4147
-     * Removes the * and anything after it from the condition query param key. It is useful to add the * to condition
4148
-     * query param keys (eg, 'OR*', 'EVT_ID') in order for the array keys to still be unique, so that they don't get
4149
-     * overwritten Takes a string like 'Event.EVT_ID*', 'TXN_total**', 'OR*1st', and 'DTT_reg_start*foobar' to
4150
-     * 'Event.EVT_ID', 'TXN_total', 'OR', and 'DTT_reg_start', respectively.
4151
-     *
4152
-     * @param string $condition_query_param_key
4153
-     * @return string
4154
-     */
4155
-    private function _remove_stars_and_anything_after_from_condition_query_param_key($condition_query_param_key)
4156
-    {
4157
-        $pos_of_star = strpos($condition_query_param_key, '*');
4158
-        if ($pos_of_star === false) {
4159
-            return $condition_query_param_key;
4160
-        }
4161
-        $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
4162
-        return $condition_query_param_sans_star;
4163
-    }
4164
-
4165
-
4166
-
4167
-    /**
4168
-     * creates the SQL for the operator and the value in a WHERE clause, eg "< 23" or "LIKE '%monkey%'"
4169
-     *
4170
-     * @param                            mixed      array | string    $op_and_value
4171
-     * @param EE_Model_Field_Base|string $field_obj . If string, should be one of EEM_Base::_valid_wpdb_data_types
4172
-     * @throws EE_Error
4173
-     * @return string
4174
-     */
4175
-    private function _construct_op_and_value($op_and_value, $field_obj)
4176
-    {
4177
-        if (is_array($op_and_value)) {
4178
-            $operator = isset($op_and_value[0]) ? $this->_prepare_operator_for_sql($op_and_value[0]) : null;
4179
-            if (! $operator) {
4180
-                $php_array_like_string = array();
4181
-                foreach ($op_and_value as $key => $value) {
4182
-                    $php_array_like_string[] = "$key=>$value";
4183
-                }
4184
-                throw new EE_Error(
4185
-                    sprintf(
4186
-                        __(
4187
-                            "You setup a query parameter like you were going to specify an operator, but didn't. You provided '(%s)', but the operator should be at array key index 0 (eg array('>',32))",
4188
-                            "event_espresso"
4189
-                        ),
4190
-                        implode(",", $php_array_like_string)
4191
-                    )
4192
-                );
4193
-            }
4194
-            $value = isset($op_and_value[1]) ? $op_and_value[1] : null;
4195
-        } else {
4196
-            $operator = '=';
4197
-            $value = $op_and_value;
4198
-        }
4199
-        //check to see if the value is actually another field
4200
-        if (is_array($op_and_value) && isset($op_and_value[2]) && $op_and_value[2] == true) {
4201
-            return $operator . SP . $this->_deduce_column_name_from_query_param($value);
4202
-        }
4203
-        if (in_array($operator, $this->valid_in_style_operators()) && is_array($value)) {
4204
-            //in this case, the value should be an array, or at least a comma-separated list
4205
-            //it will need to handle a little differently
4206
-            $cleaned_value = $this->_construct_in_value($value, $field_obj);
4207
-            //note: $cleaned_value has already been run through $wpdb->prepare()
4208
-            return $operator . SP . $cleaned_value;
4209
-        }
4210
-        if (in_array($operator, $this->valid_between_style_operators()) && is_array($value)) {
4211
-            //the value should be an array with count of two.
4212
-            if (count($value) !== 2) {
4213
-                throw new EE_Error(
4214
-                    sprintf(
4215
-                        __(
4216
-                            "The '%s' operator must be used with an array of values and there must be exactly TWO values in that array.",
4217
-                            'event_espresso'
4218
-                        ),
4219
-                        "BETWEEN"
4220
-                    )
4221
-                );
4222
-            }
4223
-            $cleaned_value = $this->_construct_between_value($value, $field_obj);
4224
-            return $operator . SP . $cleaned_value;
4225
-        }
4226
-        if (in_array($operator, $this->valid_null_style_operators())) {
4227
-            if ($value !== null) {
4228
-                throw new EE_Error(
4229
-                    sprintf(
4230
-                        __(
4231
-                            "You attempted to give a value  (%s) while using a NULL-style operator (%s). That isn't valid",
4232
-                            "event_espresso"
4233
-                        ),
4234
-                        $value,
4235
-                        $operator
4236
-                    )
4237
-                );
4238
-            }
4239
-            return $operator;
4240
-        }
4241
-        if (in_array($operator, $this->valid_like_style_operators()) && ! is_array($value)) {
4242
-            //if the operator is 'LIKE', we want to allow percent signs (%) and not
4243
-            //remove other junk. So just treat it as a string.
4244
-            return $operator . SP . $this->_wpdb_prepare_using_field($value, '%s');
4245
-        }
4246
-        if (! in_array($operator, $this->valid_in_style_operators()) && ! is_array($value)) {
4247
-            return $operator . SP . $this->_wpdb_prepare_using_field($value, $field_obj);
4248
-        }
4249
-        if (in_array($operator, $this->valid_in_style_operators()) && ! is_array($value)) {
4250
-            throw new EE_Error(
4251
-                sprintf(
4252
-                    __(
4253
-                        "Operator '%s' must be used with an array of values, eg 'Registration.REG_ID' => array('%s',array(1,2,3))",
4254
-                        'event_espresso'
4255
-                    ),
4256
-                    $operator,
4257
-                    $operator
4258
-                )
4259
-            );
4260
-        }
4261
-        if (! in_array($operator, $this->valid_in_style_operators()) && is_array($value)) {
4262
-            throw new EE_Error(
4263
-                sprintf(
4264
-                    __(
4265
-                        "Operator '%s' must be used with a single value, not an array. Eg 'Registration.REG_ID => array('%s',23))",
4266
-                        'event_espresso'
4267
-                    ),
4268
-                    $operator,
4269
-                    $operator
4270
-                )
4271
-            );
4272
-        }
4273
-        throw new EE_Error(
4274
-            sprintf(
4275
-                __(
4276
-                    "It appears you've provided some totally invalid query parameters. Operator and value were:'%s', which isn't right at all",
4277
-                    "event_espresso"
4278
-                ),
4279
-                http_build_query($op_and_value)
4280
-            )
4281
-        );
4282
-    }
4283
-
4284
-
4285
-
4286
-    /**
4287
-     * Creates the operands to be used in a BETWEEN query, eg "'2014-12-31 20:23:33' AND '2015-01-23 12:32:54'"
4288
-     *
4289
-     * @param array                      $values
4290
-     * @param EE_Model_Field_Base|string $field_obj if string, it should be the datatype to be used when querying, eg
4291
-     *                                              '%s'
4292
-     * @return string
4293
-     * @throws EE_Error
4294
-     */
4295
-    public function _construct_between_value($values, $field_obj)
4296
-    {
4297
-        $cleaned_values = array();
4298
-        foreach ($values as $value) {
4299
-            $cleaned_values[] = $this->_wpdb_prepare_using_field($value, $field_obj);
4300
-        }
4301
-        return $cleaned_values[0] . " AND " . $cleaned_values[1];
4302
-    }
4303
-
4304
-
4305
-
4306
-    /**
4307
-     * Takes an array or a comma-separated list of $values and cleans them
4308
-     * according to $data_type using $wpdb->prepare, and then makes the list a
4309
-     * string surrounded by ( and ). Eg, _construct_in_value(array(1,2,3),'%d') would
4310
-     * return '(1,2,3)'; _construct_in_value("1,2,hack",'%d') would return '(1,2,1)' (assuming
4311
-     * I'm right that a string, when interpreted as a digit, becomes a 1. It might become a 0)
4312
-     *
4313
-     * @param mixed                      $values    array or comma-separated string
4314
-     * @param EE_Model_Field_Base|string $field_obj if string, it should be a wpdb data type like '%s', or '%d'
4315
-     * @return string of SQL to follow an 'IN' or 'NOT IN' operator
4316
-     * @throws EE_Error
4317
-     */
4318
-    public function _construct_in_value($values, $field_obj)
4319
-    {
4320
-        //check if the value is a CSV list
4321
-        if (is_string($values)) {
4322
-            //in which case, turn it into an array
4323
-            $values = explode(",", $values);
4324
-        }
4325
-        $cleaned_values = array();
4326
-        foreach ($values as $value) {
4327
-            $cleaned_values[] = $this->_wpdb_prepare_using_field($value, $field_obj);
4328
-        }
4329
-        //we would just LOVE to leave $cleaned_values as an empty array, and return the value as "()",
4330
-        //but unfortunately that's invalid SQL. So instead we return a string which we KNOW will evaluate to be the empty set
4331
-        //which is effectively equivalent to returning "()". We don't return "(0)" because that only works for auto-incrementing columns
4332
-        if (empty($cleaned_values)) {
4333
-            $all_fields = $this->field_settings();
4334
-            $a_field = array_shift($all_fields);
4335
-            $main_table = $this->_get_main_table();
4336
-            $cleaned_values[] = "SELECT "
4337
-                                . $a_field->get_table_column()
4338
-                                . " FROM "
4339
-                                . $main_table->get_table_name()
4340
-                                . " WHERE FALSE";
4341
-        }
4342
-        return "(" . implode(",", $cleaned_values) . ")";
4343
-    }
4344
-
4345
-
4346
-
4347
-    /**
4348
-     * @param mixed                      $value
4349
-     * @param EE_Model_Field_Base|string $field_obj if string it should be a wpdb data type like '%d'
4350
-     * @throws EE_Error
4351
-     * @return false|null|string
4352
-     */
4353
-    private function _wpdb_prepare_using_field($value, $field_obj)
4354
-    {
4355
-        /** @type WPDB $wpdb */
4356
-        global $wpdb;
4357
-        if ($field_obj instanceof EE_Model_Field_Base) {
4358
-            return $wpdb->prepare($field_obj->get_wpdb_data_type(),
4359
-                $this->_prepare_value_for_use_in_db($value, $field_obj));
4360
-        } //$field_obj should really just be a data type
4361
-        if (! in_array($field_obj, $this->_valid_wpdb_data_types)) {
4362
-            throw new EE_Error(
4363
-                sprintf(
4364
-                    __("%s is not a valid wpdb datatype. Valid ones are %s", "event_espresso"),
4365
-                    $field_obj, implode(",", $this->_valid_wpdb_data_types)
4366
-                )
4367
-            );
4368
-        }
4369
-        return $wpdb->prepare($field_obj, $value);
4370
-    }
4371
-
4372
-
4373
-
4374
-    /**
4375
-     * Takes the input parameter and finds the model field that it indicates.
4376
-     *
4377
-     * @param string $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
4378
-     * @throws EE_Error
4379
-     * @return EE_Model_Field_Base
4380
-     */
4381
-    protected function _deduce_field_from_query_param($query_param_name)
4382
-    {
4383
-        //ok, now proceed with deducing which part is the model's name, and which is the field's name
4384
-        //which will help us find the database table and column
4385
-        $query_param_parts = explode(".", $query_param_name);
4386
-        if (empty($query_param_parts)) {
4387
-            throw new EE_Error(sprintf(__("_extract_column_name is empty when trying to extract column and table name from %s",
4388
-                'event_espresso'), $query_param_name));
4389
-        }
4390
-        $number_of_parts = count($query_param_parts);
4391
-        $last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
4392
-        if ($number_of_parts === 1) {
4393
-            $field_name = $last_query_param_part;
4394
-            $model_obj = $this;
4395
-        } else {// $number_of_parts >= 2
4396
-            //the last part is the column name, and there are only 2parts. therefore...
4397
-            $field_name = $last_query_param_part;
4398
-            $model_obj = $this->get_related_model_obj($query_param_parts[$number_of_parts - 2]);
4399
-        }
4400
-        try {
4401
-            return $model_obj->field_settings_for($field_name);
4402
-        } catch (EE_Error $e) {
4403
-            return null;
4404
-        }
4405
-    }
4406
-
4407
-
4408
-
4409
-    /**
4410
-     * Given a field's name (ie, a key in $this->field_settings()), uses the EE_Model_Field object to get the table's
4411
-     * alias and column which corresponds to it
4412
-     *
4413
-     * @param string $field_name
4414
-     * @throws EE_Error
4415
-     * @return string
4416
-     */
4417
-    public function _get_qualified_column_for_field($field_name)
4418
-    {
4419
-        $all_fields = $this->field_settings();
4420
-        $field = isset($all_fields[$field_name]) ? $all_fields[$field_name] : false;
4421
-        if ($field) {
4422
-            return $field->get_qualified_column();
4423
-        }
4424
-        throw new EE_Error(
4425
-            sprintf(
4426
-                __(
4427
-                    "There is no field titled %s on model %s. Either the query trying to use it is bad, or you need to add it to the list of fields on the model.",
4428
-                    'event_espresso'
4429
-                ), $field_name, get_class($this)
4430
-            )
4431
-        );
4432
-    }
4433
-
4434
-
4435
-
4436
-    /**
4437
-     * similar to \EEM_Base::_get_qualified_column_for_field() but returns an array with data for ALL fields.
4438
-     * Example usage:
4439
-     * EEM_Ticket::instance()->get_all_wpdb_results(
4440
-     *      array(),
4441
-     *      ARRAY_A,
4442
-     *      EEM_Ticket::instance()->get_qualified_columns_for_all_fields()
4443
-     *  );
4444
-     * is equivalent to
4445
-     *  EEM_Ticket::instance()->get_all_wpdb_results( array(), ARRAY_A, '*' );
4446
-     * and
4447
-     *  EEM_Event::instance()->get_all_wpdb_results(
4448
-     *      array(
4449
-     *          array(
4450
-     *              'Datetime.Ticket.TKT_ID' => array( '<', 100 ),
4451
-     *          ),
4452
-     *          ARRAY_A,
4453
-     *          implode(
4454
-     *              ', ',
4455
-     *              array_merge(
4456
-     *                  EEM_Event::instance()->get_qualified_columns_for_all_fields( '', false ),
4457
-     *                  EEM_Ticket::instance()->get_qualified_columns_for_all_fields( 'Datetime', false )
4458
-     *              )
4459
-     *          )
4460
-     *      )
4461
-     *  );
4462
-     * selects rows from the database, selecting all the event and ticket columns, where the ticket ID is below 100
4463
-     *
4464
-     * @param string $model_relation_chain        the chain of models used to join between the model you want to query
4465
-     *                                            and the one whose fields you are selecting for example: when querying
4466
-     *                                            tickets model and selecting fields from the tickets model you would
4467
-     *                                            leave this parameter empty, because no models are needed to join
4468
-     *                                            between the queried model and the selected one. Likewise when
4469
-     *                                            querying the datetime model and selecting fields from the tickets
4470
-     *                                            model, it would also be left empty, because there is a direct
4471
-     *                                            relation from datetimes to tickets, so no model is needed to join
4472
-     *                                            them together. However, when querying from the event model and
4473
-     *                                            selecting fields from the ticket model, you should provide the string
4474
-     *                                            'Datetime', indicating that the event model must first join to the
4475
-     *                                            datetime model in order to find its relation to ticket model.
4476
-     *                                            Also, when querying from the venue model and selecting fields from
4477
-     *                                            the ticket model, you should provide the string 'Event.Datetime',
4478
-     *                                            indicating you need to join the venue model to the event model,
4479
-     *                                            to the datetime model, in order to find its relation to the ticket model.
4480
-     *                                            This string is used to deduce the prefix that gets added onto the
4481
-     *                                            models' tables qualified columns
4482
-     * @param bool   $return_string               if true, will return a string with qualified column names separated
4483
-     *                                            by ', ' if false, will simply return a numerically indexed array of
4484
-     *                                            qualified column names
4485
-     * @return array|string
4486
-     */
4487
-    public function get_qualified_columns_for_all_fields($model_relation_chain = '', $return_string = true)
4488
-    {
4489
-        $table_prefix = str_replace('.', '__', $model_relation_chain) . (empty($model_relation_chain) ? '' : '__');
4490
-        $qualified_columns = array();
4491
-        foreach ($this->field_settings() as $field_name => $field) {
4492
-            $qualified_columns[] = $table_prefix . $field->get_qualified_column();
4493
-        }
4494
-        return $return_string ? implode(', ', $qualified_columns) : $qualified_columns;
4495
-    }
4496
-
4497
-
4498
-
4499
-    /**
4500
-     * constructs the select use on special limit joins
4501
-     * NOTE: for now this has only been tested and will work when the  table alias is for the PRIMARY table. Although
4502
-     * its setup so the select query will be setup on and just doing the special select join off of the primary table
4503
-     * (as that is typically where the limits would be set).
4504
-     *
4505
-     * @param  string       $table_alias The table the select is being built for
4506
-     * @param  mixed|string $limit       The limit for this select
4507
-     * @return string                The final select join element for the query.
4508
-     */
4509
-    public function _construct_limit_join_select($table_alias, $limit)
4510
-    {
4511
-        $SQL = '';
4512
-        foreach ($this->_tables as $table_obj) {
4513
-            if ($table_obj instanceof EE_Primary_Table) {
4514
-                $SQL .= $table_alias === $table_obj->get_table_alias()
4515
-                    ? $table_obj->get_select_join_limit($limit)
4516
-                    : SP . $table_obj->get_table_name() . " AS " . $table_obj->get_table_alias() . SP;
4517
-            } elseif ($table_obj instanceof EE_Secondary_Table) {
4518
-                $SQL .= $table_alias === $table_obj->get_table_alias()
4519
-                    ? $table_obj->get_select_join_limit_join($limit)
4520
-                    : SP . $table_obj->get_join_sql($table_alias) . SP;
4521
-            }
4522
-        }
4523
-        return $SQL;
4524
-    }
4525
-
4526
-
4527
-
4528
-    /**
4529
-     * Constructs the internal join if there are multiple tables, or simply the table's name and alias
4530
-     * Eg "wp_post AS Event" or "wp_post AS Event INNER JOIN wp_postmeta Event_Meta ON Event.ID = Event_Meta.post_id"
4531
-     *
4532
-     * @return string SQL
4533
-     * @throws EE_Error
4534
-     */
4535
-    public function _construct_internal_join()
4536
-    {
4537
-        $SQL = $this->_get_main_table()->get_table_sql();
4538
-        $SQL .= $this->_construct_internal_join_to_table_with_alias($this->_get_main_table()->get_table_alias());
4539
-        return $SQL;
4540
-    }
4541
-
4542
-
4543
-
4544
-    /**
4545
-     * Constructs the SQL for joining all the tables on this model.
4546
-     * Normally $alias should be the primary table's alias, but in cases where
4547
-     * we have already joined to a secondary table (eg, the secondary table has a foreign key and is joined before the
4548
-     * primary table) then we should provide that secondary table's alias. Eg, with $alias being the primary table's
4549
-     * alias, this will construct SQL like:
4550
-     * " INNER JOIN wp_esp_secondary_table AS Secondary_Table ON Primary_Table.pk = Secondary_Table.fk".
4551
-     * With $alias being a secondary table's alias, this will construct SQL like:
4552
-     * " INNER JOIN wp_esp_primary_table AS Primary_Table ON Primary_Table.pk = Secondary_Table.fk".
4553
-     *
4554
-     * @param string $alias_prefixed table alias to join to (this table should already be in the FROM SQL clause)
4555
-     * @return string
4556
-     */
4557
-    public function _construct_internal_join_to_table_with_alias($alias_prefixed)
4558
-    {
4559
-        $SQL = '';
4560
-        $alias_sans_prefix = EE_Model_Parser::remove_table_alias_model_relation_chain_prefix($alias_prefixed);
4561
-        foreach ($this->_tables as $table_obj) {
4562
-            if ($table_obj instanceof EE_Secondary_Table) {//table is secondary table
4563
-                if ($alias_sans_prefix === $table_obj->get_table_alias()) {
4564
-                    //so we're joining to this table, meaning the table is already in
4565
-                    //the FROM statement, BUT the primary table isn't. So we want
4566
-                    //to add the inverse join sql
4567
-                    $SQL .= $table_obj->get_inverse_join_sql($alias_prefixed);
4568
-                } else {
4569
-                    //just add a regular JOIN to this table from the primary table
4570
-                    $SQL .= $table_obj->get_join_sql($alias_prefixed);
4571
-                }
4572
-            }//if it's a primary table, dont add any SQL. it should already be in the FROM statement
4573
-        }
4574
-        return $SQL;
4575
-    }
4576
-
4577
-
4578
-
4579
-    /**
4580
-     * Gets an array for storing all the data types on the next-to-be-executed-query.
4581
-     * This should be a growing array of keys being table-columns (eg 'EVT_ID' and 'Event.EVT_ID'), and values being
4582
-     * their data type (eg, '%s', '%d', etc)
4583
-     *
4584
-     * @return array
4585
-     */
4586
-    public function _get_data_types()
4587
-    {
4588
-        $data_types = array();
4589
-        foreach ($this->field_settings() as $field_obj) {
4590
-            //$data_types[$field_obj->get_table_column()] = $field_obj->get_wpdb_data_type();
4591
-            /** @var $field_obj EE_Model_Field_Base */
4592
-            $data_types[$field_obj->get_qualified_column()] = $field_obj->get_wpdb_data_type();
4593
-        }
4594
-        return $data_types;
4595
-    }
4596
-
4597
-
4598
-
4599
-    /**
4600
-     * Gets the model object given the relation's name / model's name (eg, 'Event', 'Registration',etc. Always singular)
4601
-     *
4602
-     * @param string $model_name
4603
-     * @throws EE_Error
4604
-     * @return EEM_Base
4605
-     */
4606
-    public function get_related_model_obj($model_name)
4607
-    {
4608
-        $model_classname = "EEM_" . $model_name;
4609
-        if (! class_exists($model_classname)) {
4610
-            throw new EE_Error(sprintf(__("You specified a related model named %s in your query. No such model exists, if it did, it would have the classname %s",
4611
-                'event_espresso'), $model_name, $model_classname));
4612
-        }
4613
-        return call_user_func($model_classname . "::instance");
4614
-    }
4615
-
4616
-
4617
-
4618
-    /**
4619
-     * Returns the array of EE_ModelRelations for this model.
4620
-     *
4621
-     * @return EE_Model_Relation_Base[]
4622
-     */
4623
-    public function relation_settings()
4624
-    {
4625
-        return $this->_model_relations;
4626
-    }
4627
-
4628
-
4629
-
4630
-    /**
4631
-     * Gets all related models that this model BELONGS TO. Handy to know sometimes
4632
-     * because without THOSE models, this model probably doesn't have much purpose.
4633
-     * (Eg, without an event, datetimes have little purpose.)
4634
-     *
4635
-     * @return EE_Belongs_To_Relation[]
4636
-     */
4637
-    public function belongs_to_relations()
4638
-    {
4639
-        $belongs_to_relations = array();
4640
-        foreach ($this->relation_settings() as $model_name => $relation_obj) {
4641
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
4642
-                $belongs_to_relations[$model_name] = $relation_obj;
4643
-            }
4644
-        }
4645
-        return $belongs_to_relations;
4646
-    }
4647
-
4648
-
4649
-
4650
-    /**
4651
-     * Returns the specified EE_Model_Relation, or throws an exception
4652
-     *
4653
-     * @param string $relation_name name of relation, key in $this->_relatedModels
4654
-     * @throws EE_Error
4655
-     * @return EE_Model_Relation_Base
4656
-     */
4657
-    public function related_settings_for($relation_name)
4658
-    {
4659
-        $relatedModels = $this->relation_settings();
4660
-        if (! array_key_exists($relation_name, $relatedModels)) {
4661
-            throw new EE_Error(
4662
-                sprintf(
4663
-                    __('Cannot get %s related to %s. There is no model relation of that type. There is, however, %s...',
4664
-                        'event_espresso'),
4665
-                    $relation_name,
4666
-                    $this->_get_class_name(),
4667
-                    implode(', ', array_keys($relatedModels))
4668
-                )
4669
-            );
4670
-        }
4671
-        return $relatedModels[$relation_name];
4672
-    }
4673
-
4674
-
4675
-
4676
-    /**
4677
-     * A convenience method for getting a specific field's settings, instead of getting all field settings for all
4678
-     * fields
4679
-     *
4680
-     * @param string $fieldName
4681
-     * @param boolean $include_db_only_fields
4682
-     * @throws EE_Error
4683
-     * @return EE_Model_Field_Base
4684
-     */
4685
-    public function field_settings_for($fieldName, $include_db_only_fields = true)
4686
-    {
4687
-        $fieldSettings = $this->field_settings($include_db_only_fields);
4688
-        if (! array_key_exists($fieldName, $fieldSettings)) {
4689
-            throw new EE_Error(sprintf(__("There is no field/column '%s' on '%s'", 'event_espresso'), $fieldName,
4690
-                get_class($this)));
4691
-        }
4692
-        return $fieldSettings[$fieldName];
4693
-    }
4694
-
4695
-
4696
-
4697
-    /**
4698
-     * Checks if this field exists on this model
4699
-     *
4700
-     * @param string $fieldName a key in the model's _field_settings array
4701
-     * @return boolean
4702
-     */
4703
-    public function has_field($fieldName)
4704
-    {
4705
-        $fieldSettings = $this->field_settings(true);
4706
-        if (isset($fieldSettings[$fieldName])) {
4707
-            return true;
4708
-        }
4709
-        return false;
4710
-    }
4711
-
4712
-
4713
-
4714
-    /**
4715
-     * Returns whether or not this model has a relation to the specified model
4716
-     *
4717
-     * @param string $relation_name possibly one of the keys in the relation_settings array
4718
-     * @return boolean
4719
-     */
4720
-    public function has_relation($relation_name)
4721
-    {
4722
-        $relations = $this->relation_settings();
4723
-        if (isset($relations[$relation_name])) {
4724
-            return true;
4725
-        }
4726
-        return false;
4727
-    }
4728
-
4729
-
4730
-
4731
-    /**
4732
-     * gets the field object of type 'primary_key' from the fieldsSettings attribute.
4733
-     * Eg, on EE_Answer that would be ANS_ID field object
4734
-     *
4735
-     * @param $field_obj
4736
-     * @return boolean
4737
-     */
4738
-    public function is_primary_key_field($field_obj)
4739
-    {
4740
-        return $field_obj instanceof EE_Primary_Key_Field_Base ? true : false;
4741
-    }
4742
-
4743
-
4744
-
4745
-    /**
4746
-     * gets the field object of type 'primary_key' from the fieldsSettings attribute.
4747
-     * Eg, on EE_Answer that would be ANS_ID field object
4748
-     *
4749
-     * @return EE_Model_Field_Base
4750
-     * @throws EE_Error
4751
-     */
4752
-    public function get_primary_key_field()
4753
-    {
4754
-        if ($this->_primary_key_field === null) {
4755
-            foreach ($this->field_settings(true) as $field_obj) {
4756
-                if ($this->is_primary_key_field($field_obj)) {
4757
-                    $this->_primary_key_field = $field_obj;
4758
-                    break;
4759
-                }
4760
-            }
4761
-            if (! $this->_primary_key_field instanceof EE_Primary_Key_Field_Base) {
4762
-                throw new EE_Error(sprintf(__("There is no Primary Key defined on model %s", 'event_espresso'),
4763
-                    get_class($this)));
4764
-            }
4765
-        }
4766
-        return $this->_primary_key_field;
4767
-    }
4768
-
4769
-
4770
-
4771
-    /**
4772
-     * Returns whether or not not there is a primary key on this model.
4773
-     * Internally does some caching.
4774
-     *
4775
-     * @return boolean
4776
-     */
4777
-    public function has_primary_key_field()
4778
-    {
4779
-        if ($this->_has_primary_key_field === null) {
4780
-            try {
4781
-                $this->get_primary_key_field();
4782
-                $this->_has_primary_key_field = true;
4783
-            } catch (EE_Error $e) {
4784
-                $this->_has_primary_key_field = false;
4785
-            }
4786
-        }
4787
-        return $this->_has_primary_key_field;
4788
-    }
4789
-
4790
-
4791
-
4792
-    /**
4793
-     * Finds the first field of type $field_class_name.
4794
-     *
4795
-     * @param string $field_class_name class name of field that you want to find. Eg, EE_Datetime_Field,
4796
-     *                                 EE_Foreign_Key_Field, etc
4797
-     * @return EE_Model_Field_Base or null if none is found
4798
-     */
4799
-    public function get_a_field_of_type($field_class_name)
4800
-    {
4801
-        foreach ($this->field_settings() as $field) {
4802
-            if ($field instanceof $field_class_name) {
4803
-                return $field;
4804
-            }
4805
-        }
4806
-        return null;
4807
-    }
4808
-
4809
-
4810
-
4811
-    /**
4812
-     * Gets a foreign key field pointing to model.
4813
-     *
4814
-     * @param string $model_name eg Event, Registration, not EEM_Event
4815
-     * @return EE_Foreign_Key_Field_Base
4816
-     * @throws EE_Error
4817
-     */
4818
-    public function get_foreign_key_to($model_name)
4819
-    {
4820
-        if (! isset($this->_cache_foreign_key_to_fields[$model_name])) {
4821
-            foreach ($this->field_settings() as $field) {
4822
-                if (
4823
-                    $field instanceof EE_Foreign_Key_Field_Base
4824
-                    && in_array($model_name, $field->get_model_names_pointed_to())
4825
-                ) {
4826
-                    $this->_cache_foreign_key_to_fields[$model_name] = $field;
4827
-                    break;
4828
-                }
4829
-            }
4830
-            if (! isset($this->_cache_foreign_key_to_fields[$model_name])) {
4831
-                throw new EE_Error(sprintf(__("There is no foreign key field pointing to model %s on model %s",
4832
-                    'event_espresso'), $model_name, get_class($this)));
4833
-            }
4834
-        }
4835
-        return $this->_cache_foreign_key_to_fields[$model_name];
4836
-    }
4837
-
4838
-
4839
-
4840
-    /**
4841
-     * Gets the table name (including $wpdb->prefix) for the table alias
4842
-     *
4843
-     * @param string $table_alias eg Event, Event_Meta, Registration, Transaction, but maybe
4844
-     *                            a table alias with a model chain prefix, like 'Venue__Event_Venue___Event_Meta'.
4845
-     *                            Either one works
4846
-     * @return string
4847
-     */
4848
-    public function get_table_for_alias($table_alias)
4849
-    {
4850
-        $table_alias_sans_model_relation_chain_prefix = EE_Model_Parser::remove_table_alias_model_relation_chain_prefix($table_alias);
4851
-        return $this->_tables[$table_alias_sans_model_relation_chain_prefix]->get_table_name();
4852
-    }
4853
-
4854
-
4855
-
4856
-    /**
4857
-     * Returns a flat array of all field son this model, instead of organizing them
4858
-     * by table_alias as they are in the constructor.
4859
-     *
4860
-     * @param bool $include_db_only_fields flag indicating whether or not to include the db-only fields
4861
-     * @return EE_Model_Field_Base[] where the keys are the field's name
4862
-     */
4863
-    public function field_settings($include_db_only_fields = false)
4864
-    {
4865
-        if ($include_db_only_fields) {
4866
-            if ($this->_cached_fields === null) {
4867
-                $this->_cached_fields = array();
4868
-                foreach ($this->_fields as $fields_corresponding_to_table) {
4869
-                    foreach ($fields_corresponding_to_table as $field_name => $field_obj) {
4870
-                        $this->_cached_fields[$field_name] = $field_obj;
4871
-                    }
4872
-                }
4873
-            }
4874
-            return $this->_cached_fields;
4875
-        }
4876
-        if ($this->_cached_fields_non_db_only === null) {
4877
-            $this->_cached_fields_non_db_only = array();
4878
-            foreach ($this->_fields as $fields_corresponding_to_table) {
4879
-                foreach ($fields_corresponding_to_table as $field_name => $field_obj) {
4880
-                    /** @var $field_obj EE_Model_Field_Base */
4881
-                    if (! $field_obj->is_db_only_field()) {
4882
-                        $this->_cached_fields_non_db_only[$field_name] = $field_obj;
4883
-                    }
4884
-                }
4885
-            }
4886
-        }
4887
-        return $this->_cached_fields_non_db_only;
4888
-    }
4889
-
4890
-
4891
-
4892
-    /**
4893
-     *        cycle though array of attendees and create objects out of each item
4894
-     *
4895
-     * @access        private
4896
-     * @param        array $rows of results of $wpdb->get_results($query,ARRAY_A)
4897
-     * @return \EE_Base_Class[] array keys are primary keys (if there is a primary key on the model. if not,
4898
-     *                           numerically indexed)
4899
-     * @throws EE_Error
4900
-     */
4901
-    protected function _create_objects($rows = array())
4902
-    {
4903
-        $array_of_objects = array();
4904
-        if (empty($rows)) {
4905
-            return array();
4906
-        }
4907
-        $count_if_model_has_no_primary_key = 0;
4908
-        $has_primary_key = $this->has_primary_key_field();
4909
-        $primary_key_field = $has_primary_key ? $this->get_primary_key_field() : null;
4910
-        foreach ((array)$rows as $row) {
4911
-            if (empty($row)) {
4912
-                //wp did its weird thing where it returns an array like array(0=>null), which is totally not helpful...
4913
-                return array();
4914
-            }
4915
-            //check if we've already set this object in the results array,
4916
-            //in which case there's no need to process it further (again)
4917
-            if ($has_primary_key) {
4918
-                $table_pk_value = $this->_get_column_value_with_table_alias_or_not(
4919
-                    $row,
4920
-                    $primary_key_field->get_qualified_column(),
4921
-                    $primary_key_field->get_table_column()
4922
-                );
4923
-                if ($table_pk_value && isset($array_of_objects[$table_pk_value])) {
4924
-                    continue;
4925
-                }
4926
-            }
4927
-            $classInstance = $this->instantiate_class_from_array_or_object($row);
4928
-            if (! $classInstance) {
4929
-                throw new EE_Error(
4930
-                    sprintf(
4931
-                        __('Could not create instance of class %s from row %s', 'event_espresso'),
4932
-                        $this->get_this_model_name(),
4933
-                        http_build_query($row)
4934
-                    )
4935
-                );
4936
-            }
4937
-            //set the timezone on the instantiated objects
4938
-            $classInstance->set_timezone($this->_timezone);
4939
-            //make sure if there is any timezone setting present that we set the timezone for the object
4940
-            $key = $has_primary_key ? $classInstance->ID() : $count_if_model_has_no_primary_key++;
4941
-            $array_of_objects[$key] = $classInstance;
4942
-            //also, for all the relations of type BelongsTo, see if we can cache
4943
-            //those related models
4944
-            //(we could do this for other relations too, but if there are conditions
4945
-            //that filtered out some fo the results, then we'd be caching an incomplete set
4946
-            //so it requires a little more thought than just caching them immediately...)
4947
-            foreach ($this->_model_relations as $modelName => $relation_obj) {
4948
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
4949
-                    //check if this model's INFO is present. If so, cache it on the model
4950
-                    $other_model = $relation_obj->get_other_model();
4951
-                    $other_model_obj_maybe = $other_model->instantiate_class_from_array_or_object($row);
4952
-                    //if we managed to make a model object from the results, cache it on the main model object
4953
-                    if ($other_model_obj_maybe) {
4954
-                        //set timezone on these other model objects if they are present
4955
-                        $other_model_obj_maybe->set_timezone($this->_timezone);
4956
-                        $classInstance->cache($modelName, $other_model_obj_maybe);
4957
-                    }
4958
-                }
4959
-            }
4960
-        }
4961
-        return $array_of_objects;
4962
-    }
4963
-
4964
-
4965
-
4966
-    /**
4967
-     * The purpose of this method is to allow us to create a model object that is not in the db that holds default
4968
-     * values. A typical example of where this is used is when creating a new item and the initial load of a form.  We
4969
-     * dont' necessarily want to test for if the object is present but just assume it is BUT load the defaults from the
4970
-     * object (as set in the model_field!).
4971
-     *
4972
-     * @return EE_Base_Class single EE_Base_Class object with default values for the properties.
4973
-     */
4974
-    public function create_default_object()
4975
-    {
4976
-        $this_model_fields_and_values = array();
4977
-        //setup the row using default values;
4978
-        foreach ($this->field_settings() as $field_name => $field_obj) {
4979
-            $this_model_fields_and_values[$field_name] = $field_obj->get_default_value();
4980
-        }
4981
-        $className = $this->_get_class_name();
4982
-        $classInstance = EE_Registry::instance()
4983
-                                    ->load_class($className, array($this_model_fields_and_values), false, false);
4984
-        return $classInstance;
4985
-    }
4986
-
4987
-
4988
-
4989
-    /**
4990
-     * @param mixed $cols_n_values either an array of where each key is the name of a field, and the value is its value
4991
-     *                             or an stdClass where each property is the name of a column,
4992
-     * @return EE_Base_Class
4993
-     * @throws EE_Error
4994
-     */
4995
-    public function instantiate_class_from_array_or_object($cols_n_values)
4996
-    {
4997
-        if (! is_array($cols_n_values) && is_object($cols_n_values)) {
4998
-            $cols_n_values = get_object_vars($cols_n_values);
4999
-        }
5000
-        $primary_key = null;
5001
-        //make sure the array only has keys that are fields/columns on this model
5002
-        $this_model_fields_n_values = $this->_deduce_fields_n_values_from_cols_n_values($cols_n_values);
5003
-        if ($this->has_primary_key_field() && isset($this_model_fields_n_values[$this->primary_key_name()])) {
5004
-            $primary_key = $this_model_fields_n_values[$this->primary_key_name()];
5005
-        }
5006
-        $className = $this->_get_class_name();
5007
-        //check we actually found results that we can use to build our model object
5008
-        //if not, return null
5009
-        if ($this->has_primary_key_field()) {
5010
-            if (empty($this_model_fields_n_values[$this->primary_key_name()])) {
5011
-                return null;
5012
-            }
5013
-        } else if ($this->unique_indexes()) {
5014
-            $first_column = reset($this_model_fields_n_values);
5015
-            if (empty($first_column)) {
5016
-                return null;
5017
-            }
5018
-        }
5019
-        // if there is no primary key or the object doesn't already exist in the entity map, then create a new instance
5020
-        if ($primary_key) {
5021
-            $classInstance = $this->get_from_entity_map($primary_key);
5022
-            if (! $classInstance) {
5023
-                $classInstance = EE_Registry::instance()
5024
-                                            ->load_class($className,
5025
-                                                array($this_model_fields_n_values, $this->_timezone), true, false);
5026
-                // add this new object to the entity map
5027
-                $classInstance = $this->add_to_entity_map($classInstance);
5028
-            }
5029
-        } else {
5030
-            $classInstance = EE_Registry::instance()
5031
-                                        ->load_class($className, array($this_model_fields_n_values, $this->_timezone),
5032
-                                            true, false);
5033
-        }
5034
-        return $classInstance;
5035
-    }
5036
-
5037
-
5038
-
5039
-    /**
5040
-     * Gets the model object from the  entity map if it exists
5041
-     *
5042
-     * @param int|string $id the ID of the model object
5043
-     * @return EE_Base_Class
5044
-     */
5045
-    public function get_from_entity_map($id)
5046
-    {
5047
-        return isset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id])
5048
-            ? $this->_entity_map[EEM_Base::$_model_query_blog_id][$id] : null;
5049
-    }
5050
-
5051
-
5052
-
5053
-    /**
5054
-     * add_to_entity_map
5055
-     * Adds the object to the model's entity mappings
5056
-     *        Effectively tells the models "Hey, this model object is the most up-to-date representation of the data,
5057
-     *        and for the remainder of the request, it's even more up-to-date than what's in the database.
5058
-     *        So, if the database doesn't agree with what's in the entity mapper, ignore the database"
5059
-     *        If the database gets updated directly and you want the entity mapper to reflect that change,
5060
-     *        then this method should be called immediately after the update query
5061
-     * Note: The map is indexed by whatever the current blog id is set (via EEM_Base::$_model_query_blog_id).  This is
5062
-     * so on multisite, the entity map is specific to the query being done for a specific site.
5063
-     *
5064
-     * @param    EE_Base_Class $object
5065
-     * @throws EE_Error
5066
-     * @return \EE_Base_Class
5067
-     */
5068
-    public function add_to_entity_map(EE_Base_Class $object)
5069
-    {
5070
-        $className = $this->_get_class_name();
5071
-        if (! $object instanceof $className) {
5072
-            throw new EE_Error(sprintf(__("You tried adding a %s to a mapping of %ss", "event_espresso"),
5073
-                is_object($object) ? get_class($object) : $object, $className));
5074
-        }
5075
-        /** @var $object EE_Base_Class */
5076
-        if (! $object->ID()) {
5077
-            throw new EE_Error(sprintf(__("You tried storing a model object with NO ID in the %s entity mapper.",
5078
-                "event_espresso"), get_class($this)));
5079
-        }
5080
-        // double check it's not already there
5081
-        $classInstance = $this->get_from_entity_map($object->ID());
5082
-        if ($classInstance) {
5083
-            return $classInstance;
5084
-        }
5085
-        $this->_entity_map[EEM_Base::$_model_query_blog_id][$object->ID()] = $object;
5086
-        return $object;
5087
-    }
5088
-
5089
-
5090
-
5091
-    /**
5092
-     * if a valid identifier is provided, then that entity is unset from the entity map,
5093
-     * if no identifier is provided, then the entire entity map is emptied
5094
-     *
5095
-     * @param int|string $id the ID of the model object
5096
-     * @return boolean
5097
-     */
5098
-    public function clear_entity_map($id = null)
5099
-    {
5100
-        if (empty($id)) {
5101
-            $this->_entity_map[EEM_Base::$_model_query_blog_id] = array();
5102
-            return true;
5103
-        }
5104
-        if (isset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id])) {
5105
-            unset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id]);
5106
-            return true;
5107
-        }
5108
-        return false;
5109
-    }
5110
-
5111
-
5112
-
5113
-    /**
5114
-     * Public wrapper for _deduce_fields_n_values_from_cols_n_values.
5115
-     * Given an array where keys are column (or column alias) names and values,
5116
-     * returns an array of their corresponding field names and database values
5117
-     *
5118
-     * @param array $cols_n_values
5119
-     * @return array
5120
-     */
5121
-    public function deduce_fields_n_values_from_cols_n_values($cols_n_values)
5122
-    {
5123
-        return $this->_deduce_fields_n_values_from_cols_n_values($cols_n_values);
5124
-    }
5125
-
5126
-
5127
-
5128
-    /**
5129
-     * _deduce_fields_n_values_from_cols_n_values
5130
-     * Given an array where keys are column (or column alias) names and values,
5131
-     * returns an array of their corresponding field names and database values
5132
-     *
5133
-     * @param string $cols_n_values
5134
-     * @return array
5135
-     */
5136
-    protected function _deduce_fields_n_values_from_cols_n_values($cols_n_values)
5137
-    {
5138
-        $this_model_fields_n_values = array();
5139
-        foreach ($this->get_tables() as $table_alias => $table_obj) {
5140
-            $table_pk_value = $this->_get_column_value_with_table_alias_or_not($cols_n_values,
5141
-                $table_obj->get_fully_qualified_pk_column(), $table_obj->get_pk_column());
5142
-            //there is a primary key on this table and its not set. Use defaults for all its columns
5143
-            if ($table_pk_value === null && $table_obj->get_pk_column()) {
5144
-                foreach ($this->_get_fields_for_table($table_alias) as $field_name => $field_obj) {
5145
-                    if (! $field_obj->is_db_only_field()) {
5146
-                        //prepare field as if its coming from db
5147
-                        $prepared_value = $field_obj->prepare_for_set($field_obj->get_default_value());
5148
-                        $this_model_fields_n_values[$field_name] = $field_obj->prepare_for_use_in_db($prepared_value);
5149
-                    }
5150
-                }
5151
-            } else {
5152
-                //the table's rows existed. Use their values
5153
-                foreach ($this->_get_fields_for_table($table_alias) as $field_name => $field_obj) {
5154
-                    if (! $field_obj->is_db_only_field()) {
5155
-                        $this_model_fields_n_values[$field_name] = $this->_get_column_value_with_table_alias_or_not(
5156
-                            $cols_n_values, $field_obj->get_qualified_column(),
5157
-                            $field_obj->get_table_column()
5158
-                        );
5159
-                    }
5160
-                }
5161
-            }
5162
-        }
5163
-        return $this_model_fields_n_values;
5164
-    }
5165
-
5166
-
5167
-
5168
-    /**
5169
-     * @param $cols_n_values
5170
-     * @param $qualified_column
5171
-     * @param $regular_column
5172
-     * @return null
5173
-     */
5174
-    protected function _get_column_value_with_table_alias_or_not($cols_n_values, $qualified_column, $regular_column)
5175
-    {
5176
-        $value = null;
5177
-        //ask the field what it think it's table_name.column_name should be, and call it the "qualified column"
5178
-        //does the field on the model relate to this column retrieved from the db?
5179
-        //or is it a db-only field? (not relating to the model)
5180
-        if (isset($cols_n_values[$qualified_column])) {
5181
-            $value = $cols_n_values[$qualified_column];
5182
-        } elseif (isset($cols_n_values[$regular_column])) {
5183
-            $value = $cols_n_values[$regular_column];
5184
-        }
5185
-        return $value;
5186
-    }
5187
-
5188
-
5189
-
5190
-    /**
5191
-     * refresh_entity_map_from_db
5192
-     * Makes sure the model object in the entity map at $id assumes the values
5193
-     * of the database (opposite of EE_base_Class::save())
5194
-     *
5195
-     * @param int|string $id
5196
-     * @return EE_Base_Class
5197
-     * @throws EE_Error
5198
-     */
5199
-    public function refresh_entity_map_from_db($id)
5200
-    {
5201
-        $obj_in_map = $this->get_from_entity_map($id);
5202
-        if ($obj_in_map) {
5203
-            $wpdb_results = $this->_get_all_wpdb_results(
5204
-                array(array($this->get_primary_key_field()->get_name() => $id), 'limit' => 1)
5205
-            );
5206
-            if ($wpdb_results && is_array($wpdb_results)) {
5207
-                $one_row = reset($wpdb_results);
5208
-                foreach ($this->_deduce_fields_n_values_from_cols_n_values($one_row) as $field_name => $db_value) {
5209
-                    $obj_in_map->set_from_db($field_name, $db_value);
5210
-                }
5211
-                //clear the cache of related model objects
5212
-                foreach ($this->relation_settings() as $relation_name => $relation_obj) {
5213
-                    $obj_in_map->clear_cache($relation_name, null, true);
5214
-                }
5215
-            }
5216
-            $this->_entity_map[EEM_Base::$_model_query_blog_id][$id] = $obj_in_map;
5217
-            return $obj_in_map;
5218
-        }
5219
-        return $this->get_one_by_ID($id);
5220
-    }
5221
-
5222
-
5223
-
5224
-    /**
5225
-     * refresh_entity_map_with
5226
-     * Leaves the entry in the entity map alone, but updates it to match the provided
5227
-     * $replacing_model_obj (which we assume to be its equivalent but somehow NOT in the entity map).
5228
-     * This is useful if you have a model object you want to make authoritative over what's in the entity map currently.
5229
-     * Note: The old $replacing_model_obj should now be destroyed as it's now un-authoritative
5230
-     *
5231
-     * @param int|string    $id
5232
-     * @param EE_Base_Class $replacing_model_obj
5233
-     * @return \EE_Base_Class
5234
-     * @throws EE_Error
5235
-     */
5236
-    public function refresh_entity_map_with($id, $replacing_model_obj)
5237
-    {
5238
-        $obj_in_map = $this->get_from_entity_map($id);
5239
-        if ($obj_in_map) {
5240
-            if ($replacing_model_obj instanceof EE_Base_Class) {
5241
-                foreach ($replacing_model_obj->model_field_array() as $field_name => $value) {
5242
-                    $obj_in_map->set($field_name, $value);
5243
-                }
5244
-                //make the model object in the entity map's cache match the $replacing_model_obj
5245
-                foreach ($this->relation_settings() as $relation_name => $relation_obj) {
5246
-                    $obj_in_map->clear_cache($relation_name, null, true);
5247
-                    foreach ($replacing_model_obj->get_all_from_cache($relation_name) as $cache_id => $cached_obj) {
5248
-                        $obj_in_map->cache($relation_name, $cached_obj, $cache_id);
5249
-                    }
5250
-                }
5251
-            }
5252
-            return $obj_in_map;
5253
-        }
5254
-        $this->add_to_entity_map($replacing_model_obj);
5255
-        return $replacing_model_obj;
5256
-    }
5257
-
5258
-
5259
-
5260
-    /**
5261
-     * Gets the EE class that corresponds to this model. Eg, for EEM_Answer that
5262
-     * would be EE_Answer.To import that class, you'd just add ".class.php" to the name, like so
5263
-     * require_once($this->_getClassName().".class.php");
5264
-     *
5265
-     * @return string
5266
-     */
5267
-    private function _get_class_name()
5268
-    {
5269
-        return "EE_" . $this->get_this_model_name();
5270
-    }
5271
-
5272
-
5273
-
5274
-    /**
5275
-     * Get the name of the items this model represents, for the quantity specified. Eg,
5276
-     * if $quantity==1, on EEM_Event, it would 'Event' (internationalized), otherwise
5277
-     * it would be 'Events'.
5278
-     *
5279
-     * @param int $quantity
5280
-     * @return string
5281
-     */
5282
-    public function item_name($quantity = 1)
5283
-    {
5284
-        return (int)$quantity === 1 ? $this->singular_item : $this->plural_item;
5285
-    }
5286
-
5287
-
5288
-
5289
-    /**
5290
-     * Very handy general function to allow for plugins to extend any child of EE_TempBase.
5291
-     * If a method is called on a child of EE_TempBase that doesn't exist, this function is called
5292
-     * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
5293
-     * requiring a plugin to extend the EE_TempBase (which works fine is there's only 1 plugin, but when will that
5294
-     * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
5295
-     * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
5296
-     * was called, and an array of the original arguments passed to the function. Whatever their callback function
5297
-     * returns will be returned by this function. Example: in functions.php (or in a plugin):
5298
-     * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
5299
-     * my_callback($previousReturnValue,EE_TempBase $object,$argsArray){
5300
-     * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
5301
-     *        return $previousReturnValue.$returnString;
5302
-     * }
5303
-     * require('EEM_Answer.model.php');
5304
-     * $answer=EEM_Answer::instance();
5305
-     * echo $answer->my_callback('monkeys',100);
5306
-     * //will output "you called my_callback! and passed args:monkeys,100"
5307
-     *
5308
-     * @param string $methodName name of method which was called on a child of EE_TempBase, but which
5309
-     * @param array  $args       array of original arguments passed to the function
5310
-     * @throws EE_Error
5311
-     * @return mixed whatever the plugin which calls add_filter decides
5312
-     */
5313
-    public function __call($methodName, $args)
5314
-    {
5315
-        $className = get_class($this);
5316
-        $tagName = "FHEE__{$className}__{$methodName}";
5317
-        if (! has_filter($tagName)) {
5318
-            throw new EE_Error(
5319
-                sprintf(
5320
-                    __('Method %1$s on model %2$s does not exist! You can create one with the following code in functions.php or in a plugin: %4$s function my_callback(%4$s \$previousReturnValue, EEM_Base \$object\ $argsArray=NULL ){%4$s     /*function body*/%4$s      return \$whatever;%4$s }%4$s add_filter( \'%3$s\', \'my_callback\', 10, 3 );',
5321
-                        'event_espresso'),
5322
-                    $methodName,
5323
-                    $className,
5324
-                    $tagName,
5325
-                    '<br />'
5326
-                )
5327
-            );
5328
-        }
5329
-        return apply_filters($tagName, null, $this, $args);
5330
-    }
5331
-
5332
-
5333
-
5334
-    /**
5335
-     * Ensures $base_class_obj_or_id is of the EE_Base_Class child that corresponds ot this model.
5336
-     * If not, assumes its an ID, and uses $this->get_one_by_ID() to get the EE_Base_Class.
5337
-     *
5338
-     * @param EE_Base_Class|string|int $base_class_obj_or_id either:
5339
-     *                                                       the EE_Base_Class object that corresponds to this Model,
5340
-     *                                                       the object's class name
5341
-     *                                                       or object's ID
5342
-     * @param boolean                  $ensure_is_in_db      if set, we will also verify this model object
5343
-     *                                                       exists in the database. If it does not, we add it
5344
-     * @throws EE_Error
5345
-     * @return EE_Base_Class
5346
-     */
5347
-    public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false)
5348
-    {
5349
-        $className = $this->_get_class_name();
5350
-        if ($base_class_obj_or_id instanceof $className) {
5351
-            $model_object = $base_class_obj_or_id;
5352
-        } else {
5353
-            $primary_key_field = $this->get_primary_key_field();
5354
-            if (
5355
-                $primary_key_field instanceof EE_Primary_Key_Int_Field
5356
-                && (
5357
-                    is_int($base_class_obj_or_id)
5358
-                    || is_string($base_class_obj_or_id)
5359
-                )
5360
-            ) {
5361
-                // assume it's an ID.
5362
-                // either a proper integer or a string representing an integer (eg "101" instead of 101)
5363
-                $model_object = $this->get_one_by_ID($base_class_obj_or_id);
5364
-            } else if (
5365
-                $primary_key_field instanceof EE_Primary_Key_String_Field
5366
-                && is_string($base_class_obj_or_id)
5367
-            ) {
5368
-                // assume its a string representation of the object
5369
-                $model_object = $this->get_one_by_ID($base_class_obj_or_id);
5370
-            } else {
5371
-                throw new EE_Error(
5372
-                    sprintf(
5373
-                        __(
5374
-                            "'%s' is neither an object of type %s, nor an ID! Its full value is '%s'",
5375
-                            'event_espresso'
5376
-                        ),
5377
-                        $base_class_obj_or_id,
5378
-                        $this->_get_class_name(),
5379
-                        print_r($base_class_obj_or_id, true)
5380
-                    )
5381
-                );
5382
-            }
5383
-        }
5384
-        if ($ensure_is_in_db && $model_object->ID() !== null) {
5385
-            $model_object->save();
5386
-        }
5387
-        return $model_object;
5388
-    }
5389
-
5390
-
5391
-
5392
-    /**
5393
-     * Similar to ensure_is_obj(), this method makes sure $base_class_obj_or_id
5394
-     * is a value of the this model's primary key. If it's an EE_Base_Class child,
5395
-     * returns it ID.
5396
-     *
5397
-     * @param EE_Base_Class|int|string $base_class_obj_or_id
5398
-     * @return int|string depending on the type of this model object's ID
5399
-     * @throws EE_Error
5400
-     */
5401
-    public function ensure_is_ID($base_class_obj_or_id)
5402
-    {
5403
-        $className = $this->_get_class_name();
5404
-        if ($base_class_obj_or_id instanceof $className) {
5405
-            /** @var $base_class_obj_or_id EE_Base_Class */
5406
-            $id = $base_class_obj_or_id->ID();
5407
-        } elseif (is_int($base_class_obj_or_id)) {
5408
-            //assume it's an ID
5409
-            $id = $base_class_obj_or_id;
5410
-        } elseif (is_string($base_class_obj_or_id)) {
5411
-            //assume its a string representation of the object
5412
-            $id = $base_class_obj_or_id;
5413
-        } else {
5414
-            throw new EE_Error(sprintf(__("'%s' is neither an object of type %s, nor an ID! Its full value is '%s'",
5415
-                'event_espresso'), $base_class_obj_or_id, $this->_get_class_name(),
5416
-                print_r($base_class_obj_or_id, true)));
5417
-        }
5418
-        return $id;
5419
-    }
5420
-
5421
-
5422
-
5423
-    /**
5424
-     * Sets whether the values passed to the model (eg, values in WHERE, values in INSERT, UPDATE, etc)
5425
-     * have already been ran through the appropriate model field's prepare_for_use_in_db method. IE, they have
5426
-     * been sanitized and converted into the appropriate domain.
5427
-     * Usually the only place you'll want to change the default (which is to assume values have NOT been sanitized by
5428
-     * the model object/model field) is when making a method call from WITHIN a model object, which has direct access
5429
-     * to its sanitized values. Note: after changing this setting, you should set it back to its previous value (using
5430
-     * get_assumption_concerning_values_already_prepared_by_model_object()) eg.
5431
-     * $EVT = EEM_Event::instance(); $old_setting =
5432
-     * $EVT->get_assumption_concerning_values_already_prepared_by_model_object();
5433
-     * $EVT->assume_values_already_prepared_by_model_object(true);
5434
-     * $EVT->update(array('foo'=>'bar'),array(array('foo'=>'monkey')));
5435
-     * $EVT->assume_values_already_prepared_by_model_object($old_setting);
5436
-     *
5437
-     * @param int $values_already_prepared like one of the constants on EEM_Base
5438
-     * @return void
5439
-     */
5440
-    public function assume_values_already_prepared_by_model_object(
5441
-        $values_already_prepared = self::not_prepared_by_model_object
5442
-    ) {
5443
-        $this->_values_already_prepared_by_model_object = $values_already_prepared;
5444
-    }
5445
-
5446
-
5447
-
5448
-    /**
5449
-     * Read comments for assume_values_already_prepared_by_model_object()
5450
-     *
5451
-     * @return int
5452
-     */
5453
-    public function get_assumption_concerning_values_already_prepared_by_model_object()
5454
-    {
5455
-        return $this->_values_already_prepared_by_model_object;
5456
-    }
5457
-
5458
-
5459
-
5460
-    /**
5461
-     * Gets all the indexes on this model
5462
-     *
5463
-     * @return EE_Index[]
5464
-     */
5465
-    public function indexes()
5466
-    {
5467
-        return $this->_indexes;
5468
-    }
5469
-
5470
-
5471
-
5472
-    /**
5473
-     * Gets all the Unique Indexes on this model
5474
-     *
5475
-     * @return EE_Unique_Index[]
5476
-     */
5477
-    public function unique_indexes()
5478
-    {
5479
-        $unique_indexes = array();
5480
-        foreach ($this->_indexes as $name => $index) {
5481
-            if ($index instanceof EE_Unique_Index) {
5482
-                $unique_indexes [$name] = $index;
5483
-            }
5484
-        }
5485
-        return $unique_indexes;
5486
-    }
5487
-
5488
-
5489
-
5490
-    /**
5491
-     * Gets all the fields which, when combined, make the primary key.
5492
-     * This is usually just an array with 1 element (the primary key), but in cases
5493
-     * where there is no primary key, it's a combination of fields as defined
5494
-     * on a primary index
5495
-     *
5496
-     * @return EE_Model_Field_Base[] indexed by the field's name
5497
-     * @throws EE_Error
5498
-     */
5499
-    public function get_combined_primary_key_fields()
5500
-    {
5501
-        foreach ($this->indexes() as $index) {
5502
-            if ($index instanceof EE_Primary_Key_Index) {
5503
-                return $index->fields();
5504
-            }
5505
-        }
5506
-        return array($this->primary_key_name() => $this->get_primary_key_field());
5507
-    }
5508
-
5509
-
5510
-
5511
-    /**
5512
-     * Used to build a primary key string (when the model has no primary key),
5513
-     * which can be used a unique string to identify this model object.
5514
-     *
5515
-     * @param array $cols_n_values keys are field names, values are their values
5516
-     * @return string
5517
-     * @throws EE_Error
5518
-     */
5519
-    public function get_index_primary_key_string($cols_n_values)
5520
-    {
5521
-        $cols_n_values_for_primary_key_index = array_intersect_key($cols_n_values,
5522
-            $this->get_combined_primary_key_fields());
5523
-        return http_build_query($cols_n_values_for_primary_key_index);
5524
-    }
5525
-
5526
-
5527
-
5528
-    /**
5529
-     * Gets the field values from the primary key string
5530
-     *
5531
-     * @see EEM_Base::get_combined_primary_key_fields() and EEM_Base::get_index_primary_key_string()
5532
-     * @param string $index_primary_key_string
5533
-     * @return null|array
5534
-     * @throws EE_Error
5535
-     */
5536
-    public function parse_index_primary_key_string($index_primary_key_string)
5537
-    {
5538
-        $key_fields = $this->get_combined_primary_key_fields();
5539
-        //check all of them are in the $id
5540
-        $key_vals_in_combined_pk = array();
5541
-        parse_str($index_primary_key_string, $key_vals_in_combined_pk);
5542
-        foreach ($key_fields as $key_field_name => $field_obj) {
5543
-            if (! isset($key_vals_in_combined_pk[$key_field_name])) {
5544
-                return null;
5545
-            }
5546
-        }
5547
-        return $key_vals_in_combined_pk;
5548
-    }
5549
-
5550
-
5551
-
5552
-    /**
5553
-     * verifies that an array of key-value pairs for model fields has a key
5554
-     * for each field comprising the primary key index
5555
-     *
5556
-     * @param array $key_vals
5557
-     * @return boolean
5558
-     * @throws EE_Error
5559
-     */
5560
-    public function has_all_combined_primary_key_fields($key_vals)
5561
-    {
5562
-        $keys_it_should_have = array_keys($this->get_combined_primary_key_fields());
5563
-        foreach ($keys_it_should_have as $key) {
5564
-            if (! isset($key_vals[$key])) {
5565
-                return false;
5566
-            }
5567
-        }
5568
-        return true;
5569
-    }
5570
-
5571
-
5572
-
5573
-    /**
5574
-     * Finds all model objects in the DB that appear to be a copy of $model_object_or_attributes_array.
5575
-     * We consider something to be a copy if all the attributes match (except the ID, of course).
5576
-     *
5577
-     * @param array|EE_Base_Class $model_object_or_attributes_array If its an array, it's field-value pairs
5578
-     * @param array               $query_params                     like EEM_Base::get_all's query_params.
5579
-     * @throws EE_Error
5580
-     * @return \EE_Base_Class[] Array keys are object IDs (if there is a primary key on the model. if not, numerically
5581
-     *                                                              indexed)
5582
-     */
5583
-    public function get_all_copies($model_object_or_attributes_array, $query_params = array())
5584
-    {
5585
-        if ($model_object_or_attributes_array instanceof EE_Base_Class) {
5586
-            $attributes_array = $model_object_or_attributes_array->model_field_array();
5587
-        } elseif (is_array($model_object_or_attributes_array)) {
5588
-            $attributes_array = $model_object_or_attributes_array;
5589
-        } else {
5590
-            throw new EE_Error(sprintf(__("get_all_copies should be provided with either a model object or an array of field-value-pairs, but was given %s",
5591
-                "event_espresso"), $model_object_or_attributes_array));
5592
-        }
5593
-        //even copies obviously won't have the same ID, so remove the primary key
5594
-        //from the WHERE conditions for finding copies (if there is a primary key, of course)
5595
-        if ($this->has_primary_key_field() && isset($attributes_array[$this->primary_key_name()])) {
5596
-            unset($attributes_array[$this->primary_key_name()]);
5597
-        }
5598
-        if (isset($query_params[0])) {
5599
-            $query_params[0] = array_merge($attributes_array, $query_params);
5600
-        } else {
5601
-            $query_params[0] = $attributes_array;
5602
-        }
5603
-        return $this->get_all($query_params);
5604
-    }
5605
-
5606
-
5607
-
5608
-    /**
5609
-     * Gets the first copy we find. See get_all_copies for more details
5610
-     *
5611
-     * @param       mixed EE_Base_Class | array        $model_object_or_attributes_array
5612
-     * @param array $query_params
5613
-     * @return EE_Base_Class
5614
-     * @throws EE_Error
5615
-     */
5616
-    public function get_one_copy($model_object_or_attributes_array, $query_params = array())
5617
-    {
5618
-        if (! is_array($query_params)) {
5619
-            EE_Error::doing_it_wrong('EEM_Base::get_one_copy',
5620
-                sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
5621
-                    gettype($query_params)), '4.6.0');
5622
-            $query_params = array();
5623
-        }
5624
-        $query_params['limit'] = 1;
5625
-        $copies = $this->get_all_copies($model_object_or_attributes_array, $query_params);
5626
-        if (is_array($copies)) {
5627
-            return array_shift($copies);
5628
-        }
5629
-        return null;
5630
-    }
5631
-
5632
-
5633
-
5634
-    /**
5635
-     * Updates the item with the specified id. Ignores default query parameters because
5636
-     * we have specified the ID, and its assumed we KNOW what we're doing
5637
-     *
5638
-     * @param array      $fields_n_values keys are field names, values are their new values
5639
-     * @param int|string $id              the value of the primary key to update
5640
-     * @return int number of rows updated
5641
-     * @throws EE_Error
5642
-     */
5643
-    public function update_by_ID($fields_n_values, $id)
5644
-    {
5645
-        $query_params = array(
5646
-            0                          => array($this->get_primary_key_field()->get_name() => $id),
5647
-            'default_where_conditions' => EEM_Base::default_where_conditions_others_only,
5648
-        );
5649
-        return $this->update($fields_n_values, $query_params);
5650
-    }
5651
-
5652
-
5653
-
5654
-    /**
5655
-     * Changes an operator which was supplied to the models into one usable in SQL
5656
-     *
5657
-     * @param string $operator_supplied
5658
-     * @return string an operator which can be used in SQL
5659
-     * @throws EE_Error
5660
-     */
5661
-    private function _prepare_operator_for_sql($operator_supplied)
5662
-    {
5663
-        $sql_operator = isset($this->_valid_operators[$operator_supplied]) ? $this->_valid_operators[$operator_supplied]
5664
-            : null;
5665
-        if ($sql_operator) {
5666
-            return $sql_operator;
5667
-        }
5668
-        throw new EE_Error(
5669
-            sprintf(
5670
-                __(
5671
-                    "The operator '%s' is not in the list of valid operators: %s",
5672
-                    "event_espresso"
5673
-                ), $operator_supplied, implode(",", array_keys($this->_valid_operators))
5674
-            )
5675
-        );
5676
-    }
5677
-
5678
-
5679
-
5680
-    /**
5681
-     * Gets the valid operators
5682
-     * @return array keys are accepted strings, values are the SQL they are converted to
5683
-     */
5684
-    public function valid_operators(){
5685
-        return $this->_valid_operators;
5686
-    }
5687
-
5688
-
5689
-
5690
-    /**
5691
-     * Gets the between-style operators (take 2 arguments).
5692
-     * @return array keys are accepted strings, values are the SQL they are converted to
5693
-     */
5694
-    public function valid_between_style_operators()
5695
-    {
5696
-        return array_intersect(
5697
-            $this->valid_operators(),
5698
-            $this->_between_style_operators
5699
-        );
5700
-    }
5701
-
5702
-    /**
5703
-     * Gets the "like"-style operators (take a single argument, but it may contain wildcards)
5704
-     * @return array keys are accepted strings, values are the SQL they are converted to
5705
-     */
5706
-    public function valid_like_style_operators()
5707
-    {
5708
-        return array_intersect(
5709
-            $this->valid_operators(),
5710
-            $this->_like_style_operators
5711
-        );
5712
-    }
5713
-
5714
-    /**
5715
-     * Gets the "in"-style operators
5716
-     * @return array keys are accepted strings, values are the SQL they are converted to
5717
-     */
5718
-    public function valid_in_style_operators()
5719
-    {
5720
-        return array_intersect(
5721
-            $this->valid_operators(),
5722
-            $this->_in_style_operators
5723
-        );
5724
-    }
5725
-
5726
-    /**
5727
-     * Gets the "null"-style operators (accept no arguments)
5728
-     * @return array keys are accepted strings, values are the SQL they are converted to
5729
-     */
5730
-    public function valid_null_style_operators()
5731
-    {
5732
-        return array_intersect(
5733
-            $this->valid_operators(),
5734
-            $this->_null_style_operators
5735
-        );
5736
-    }
5737
-
5738
-    /**
5739
-     * Gets an array where keys are the primary keys and values are their 'names'
5740
-     * (as determined by the model object's name() function, which is often overridden)
5741
-     *
5742
-     * @param array $query_params like get_all's
5743
-     * @return string[]
5744
-     * @throws EE_Error
5745
-     */
5746
-    public function get_all_names($query_params = array())
5747
-    {
5748
-        $objs = $this->get_all($query_params);
5749
-        $names = array();
5750
-        foreach ($objs as $obj) {
5751
-            $names[$obj->ID()] = $obj->name();
5752
-        }
5753
-        return $names;
5754
-    }
5755
-
5756
-
5757
-
5758
-    /**
5759
-     * Gets an array of primary keys from the model objects. If you acquired the model objects
5760
-     * using EEM_Base::get_all() you don't need to call this (and probably shouldn't because
5761
-     * this is duplicated effort and reduces efficiency) you would be better to use
5762
-     * array_keys() on $model_objects.
5763
-     *
5764
-     * @param \EE_Base_Class[] $model_objects
5765
-     * @param boolean          $filter_out_empty_ids if a model object has an ID of '' or 0, don't bother including it
5766
-     *                                               in the returned array
5767
-     * @return array
5768
-     * @throws EE_Error
5769
-     */
5770
-    public function get_IDs($model_objects, $filter_out_empty_ids = false)
5771
-    {
5772
-        if (! $this->has_primary_key_field()) {
5773
-            if (WP_DEBUG) {
5774
-                EE_Error::add_error(
5775
-                    __('Trying to get IDs from a model than has no primary key', 'event_espresso'),
5776
-                    __FILE__,
5777
-                    __FUNCTION__,
5778
-                    __LINE__
5779
-                );
5780
-            }
5781
-        }
5782
-        $IDs = array();
5783
-        foreach ($model_objects as $model_object) {
5784
-            $id = $model_object->ID();
5785
-            if (! $id) {
5786
-                if ($filter_out_empty_ids) {
5787
-                    continue;
5788
-                }
5789
-                if (WP_DEBUG) {
5790
-                    EE_Error::add_error(
5791
-                        __(
5792
-                            'Called %1$s on a model object that has no ID and so probably hasn\'t been saved to the database',
5793
-                            'event_espresso'
5794
-                        ),
5795
-                        __FILE__,
5796
-                        __FUNCTION__,
5797
-                        __LINE__
5798
-                    );
5799
-                }
5800
-            }
5801
-            $IDs[] = $id;
5802
-        }
5803
-        return $IDs;
5804
-    }
5805
-
5806
-
5807
-
5808
-    /**
5809
-     * Returns the string used in capabilities relating to this model. If there
5810
-     * are no capabilities that relate to this model returns false
5811
-     *
5812
-     * @return string|false
5813
-     */
5814
-    public function cap_slug()
5815
-    {
5816
-        return apply_filters('FHEE__EEM_Base__cap_slug', $this->_caps_slug, $this);
5817
-    }
5818
-
5819
-
5820
-
5821
-    /**
5822
-     * Returns the capability-restrictions array (@see EEM_Base::_cap_restrictions).
5823
-     * If $context is provided (which should be set to one of EEM_Base::valid_cap_contexts())
5824
-     * only returns the cap restrictions array in that context (ie, the array
5825
-     * at that key)
5826
-     *
5827
-     * @param string $context
5828
-     * @return EE_Default_Where_Conditions[] indexed by associated capability
5829
-     * @throws EE_Error
5830
-     */
5831
-    public function cap_restrictions($context = EEM_Base::caps_read)
5832
-    {
5833
-        EEM_Base::verify_is_valid_cap_context($context);
5834
-        //check if we ought to run the restriction generator first
5835
-        if (
5836
-            isset($this->_cap_restriction_generators[$context])
5837
-            && $this->_cap_restriction_generators[$context] instanceof EE_Restriction_Generator_Base
5838
-            && ! $this->_cap_restriction_generators[$context]->has_generated_cap_restrictions()
5839
-        ) {
5840
-            $this->_cap_restrictions[$context] = array_merge(
5841
-                $this->_cap_restrictions[$context],
5842
-                $this->_cap_restriction_generators[$context]->generate_restrictions()
5843
-            );
5844
-        }
5845
-        //and make sure we've finalized the construction of each restriction
5846
-        foreach ($this->_cap_restrictions[$context] as $where_conditions_obj) {
5847
-            if ($where_conditions_obj instanceof EE_Default_Where_Conditions) {
5848
-                $where_conditions_obj->_finalize_construct($this);
5849
-            }
5850
-        }
5851
-        return $this->_cap_restrictions[$context];
5852
-    }
5853
-
5854
-
5855
-
5856
-    /**
5857
-     * Indicating whether or not this model thinks its a wp core model
5858
-     *
5859
-     * @return boolean
5860
-     */
5861
-    public function is_wp_core_model()
5862
-    {
5863
-        return $this->_wp_core_model;
5864
-    }
5865
-
5866
-
5867
-
5868
-    /**
5869
-     * Gets all the caps that are missing which impose a restriction on
5870
-     * queries made in this context
5871
-     *
5872
-     * @param string $context one of EEM_Base::caps_ constants
5873
-     * @return EE_Default_Where_Conditions[] indexed by capability name
5874
-     * @throws EE_Error
5875
-     */
5876
-    public function caps_missing($context = EEM_Base::caps_read)
5877
-    {
5878
-        $missing_caps = array();
5879
-        $cap_restrictions = $this->cap_restrictions($context);
5880
-        foreach ($cap_restrictions as $cap => $restriction_if_no_cap) {
5881
-            if (! EE_Capabilities::instance()
5882
-                                 ->current_user_can($cap, $this->get_this_model_name() . '_model_applying_caps')
5883
-            ) {
5884
-                $missing_caps[$cap] = $restriction_if_no_cap;
5885
-            }
5886
-        }
5887
-        return $missing_caps;
5888
-    }
5889
-
5890
-
5891
-
5892
-    /**
5893
-     * Gets the mapping from capability contexts to action strings used in capability names
5894
-     *
5895
-     * @return array keys are one of EEM_Base::valid_cap_contexts(), and values are usually
5896
-     * one of 'read', 'edit', or 'delete'
5897
-     */
5898
-    public function cap_contexts_to_cap_action_map()
5899
-    {
5900
-        return apply_filters('FHEE__EEM_Base__cap_contexts_to_cap_action_map', $this->_cap_contexts_to_cap_action_map,
5901
-            $this);
5902
-    }
5903
-
5904
-
5905
-
5906
-    /**
5907
-     * Gets the action string for the specified capability context
5908
-     *
5909
-     * @param string $context
5910
-     * @return string one of EEM_Base::cap_contexts_to_cap_action_map() values
5911
-     * @throws EE_Error
5912
-     */
5913
-    public function cap_action_for_context($context)
5914
-    {
5915
-        $mapping = $this->cap_contexts_to_cap_action_map();
5916
-        if (isset($mapping[$context])) {
5917
-            return $mapping[$context];
5918
-        }
5919
-        if ($action = apply_filters('FHEE__EEM_Base__cap_action_for_context', null, $this, $mapping, $context)) {
5920
-            return $action;
5921
-        }
5922
-        throw new EE_Error(
5923
-            sprintf(
5924
-                __('Cannot find capability restrictions for context "%1$s", allowed values are:%2$s', 'event_espresso'),
5925
-                $context,
5926
-                implode(',', array_keys($this->cap_contexts_to_cap_action_map()))
5927
-            )
5928
-        );
5929
-    }
5930
-
5931
-
5932
-
5933
-    /**
5934
-     * Returns all the capability contexts which are valid when querying models
5935
-     *
5936
-     * @return array
5937
-     */
5938
-    public static function valid_cap_contexts()
5939
-    {
5940
-        return apply_filters('FHEE__EEM_Base__valid_cap_contexts', array(
5941
-            self::caps_read,
5942
-            self::caps_read_admin,
5943
-            self::caps_edit,
5944
-            self::caps_delete,
5945
-        ));
5946
-    }
5947
-
5948
-
5949
-
5950
-    /**
5951
-     * Returns all valid options for 'default_where_conditions'
5952
-     *
5953
-     * @return array
5954
-     */
5955
-    public static function valid_default_where_conditions()
5956
-    {
5957
-        return array(
5958
-            EEM_Base::default_where_conditions_all,
5959
-            EEM_Base::default_where_conditions_this_only,
5960
-            EEM_Base::default_where_conditions_others_only,
5961
-            EEM_Base::default_where_conditions_minimum_all,
5962
-            EEM_Base::default_where_conditions_minimum_others,
5963
-            EEM_Base::default_where_conditions_none
5964
-        );
5965
-    }
5966
-
5967
-    // public static function default_where_conditions_full
5968
-    /**
5969
-     * Verifies $context is one of EEM_Base::valid_cap_contexts(), if not it throws an exception
5970
-     *
5971
-     * @param string $context
5972
-     * @return bool
5973
-     * @throws EE_Error
5974
-     */
5975
-    static public function verify_is_valid_cap_context($context)
5976
-    {
5977
-        $valid_cap_contexts = EEM_Base::valid_cap_contexts();
5978
-        if (in_array($context, $valid_cap_contexts)) {
5979
-            return true;
5980
-        }
5981
-        throw new EE_Error(
5982
-            sprintf(
5983
-                __(
5984
-                    'Context "%1$s" passed into model "%2$s" is not a valid context. They are: %3$s',
5985
-                    'event_espresso'
5986
-                ),
5987
-                $context,
5988
-                'EEM_Base',
5989
-                implode(',', $valid_cap_contexts)
5990
-            )
5991
-        );
5992
-    }
5993
-
5994
-
5995
-
5996
-    /**
5997
-     * Clears all the models field caches. This is only useful when a sub-class
5998
-     * might have added a field or something and these caches might be invalidated
5999
-     */
6000
-    protected function _invalidate_field_caches()
6001
-    {
6002
-        $this->_cache_foreign_key_to_fields = array();
6003
-        $this->_cached_fields = null;
6004
-        $this->_cached_fields_non_db_only = null;
6005
-    }
6006
-
6007
-
6008
-
6009
-    /**
6010
-     * Gets the list of all the where query param keys that relate to logic instead of field names
6011
-     * (eg "and", "or", "not").
6012
-     *
6013
-     * @return array
6014
-     */
6015
-    public function logic_query_param_keys()
6016
-    {
6017
-        return $this->_logic_query_param_keys;
6018
-    }
6019
-
6020
-
6021
-
6022
-    /**
6023
-     * Determines whether or not the where query param array key is for a logic query param.
6024
-     * Eg 'OR', 'not*', and 'and*because-i-say-so' should all return true, whereas
6025
-     * 'ATT_fname', 'EVT_name*not-you-or-me', and 'ORG_name' should return false
6026
-     *
6027
-     * @param $query_param_key
6028
-     * @return bool
6029
-     */
6030
-    public function is_logic_query_param_key($query_param_key)
6031
-    {
6032
-        foreach ($this->logic_query_param_keys() as $logic_query_param_key) {
6033
-            if ($query_param_key === $logic_query_param_key
6034
-                || strpos($query_param_key, $logic_query_param_key . '*') === 0
6035
-            ) {
6036
-                return true;
6037
-            }
6038
-        }
6039
-        return false;
6040
-    }
3741
+		}
3742
+		return $null_friendly_where_conditions;
3743
+	}
3744
+
3745
+
3746
+
3747
+	/**
3748
+	 * Uses the _default_where_conditions_strategy set during __construct() to get
3749
+	 * default where conditions on all get_all, update, and delete queries done by this model.
3750
+	 * Use the same syntax as client code. Eg on the Event model, use array('Event.EVT_post_type'=>'esp_event'),
3751
+	 * NOT array('Event_CPT.post_type'=>'esp_event').
3752
+	 *
3753
+	 * @param string $model_relation_path eg, path from Event to Payment is "Registration.Transaction.Payment."
3754
+	 * @return array like EEM_Base::get_all's $query_params[0] (where conditions)
3755
+	 */
3756
+	private function _get_default_where_conditions($model_relation_path = null)
3757
+	{
3758
+		if ($this->_ignore_where_strategy) {
3759
+			return array();
3760
+		}
3761
+		return $this->_default_where_conditions_strategy->get_default_where_conditions($model_relation_path);
3762
+	}
3763
+
3764
+
3765
+
3766
+	/**
3767
+	 * Uses the _minimum_where_conditions_strategy set during __construct() to get
3768
+	 * minimum where conditions on all get_all, update, and delete queries done by this model.
3769
+	 * Use the same syntax as client code. Eg on the Event model, use array('Event.EVT_post_type'=>'esp_event'),
3770
+	 * NOT array('Event_CPT.post_type'=>'esp_event').
3771
+	 * Similar to _get_default_where_conditions
3772
+	 *
3773
+	 * @param string $model_relation_path eg, path from Event to Payment is "Registration.Transaction.Payment."
3774
+	 * @return array like EEM_Base::get_all's $query_params[0] (where conditions)
3775
+	 */
3776
+	protected function _get_minimum_where_conditions($model_relation_path = null)
3777
+	{
3778
+		if ($this->_ignore_where_strategy) {
3779
+			return array();
3780
+		}
3781
+		return $this->_minimum_where_conditions_strategy->get_default_where_conditions($model_relation_path);
3782
+	}
3783
+
3784
+
3785
+
3786
+	/**
3787
+	 * Creates the string of SQL for the select part of a select query, everything behind SELECT and before FROM.
3788
+	 * Eg, "Event.post_id, Event.post_name,Event_Detail.EVT_ID..."
3789
+	 *
3790
+	 * @param EE_Model_Query_Info_Carrier $model_query_info
3791
+	 * @return string
3792
+	 * @throws EE_Error
3793
+	 */
3794
+	private function _construct_default_select_sql(EE_Model_Query_Info_Carrier $model_query_info)
3795
+	{
3796
+		$selects = $this->_get_columns_to_select_for_this_model();
3797
+		foreach (
3798
+			$model_query_info->get_model_names_included() as $model_relation_chain =>
3799
+			$name_of_other_model_included
3800
+		) {
3801
+			$other_model_included = $this->get_related_model_obj($name_of_other_model_included);
3802
+			$other_model_selects = $other_model_included->_get_columns_to_select_for_this_model($model_relation_chain);
3803
+			foreach ($other_model_selects as $key => $value) {
3804
+				$selects[] = $value;
3805
+			}
3806
+		}
3807
+		return implode(", ", $selects);
3808
+	}
3809
+
3810
+
3811
+
3812
+	/**
3813
+	 * Gets an array of columns to select for this model, which are necessary for it to create its objects.
3814
+	 * So that's going to be the columns for all the fields on the model
3815
+	 *
3816
+	 * @param string $model_relation_chain like 'Question.Question_Group.Event'
3817
+	 * @return array numerically indexed, values are columns to select and rename, eg "Event.ID AS 'Event.ID'"
3818
+	 */
3819
+	public function _get_columns_to_select_for_this_model($model_relation_chain = '')
3820
+	{
3821
+		$fields = $this->field_settings();
3822
+		$selects = array();
3823
+		$table_alias_with_model_relation_chain_prefix = EE_Model_Parser::extract_table_alias_model_relation_chain_prefix($model_relation_chain,
3824
+			$this->get_this_model_name());
3825
+		foreach ($fields as $field_obj) {
3826
+			$selects[] = $table_alias_with_model_relation_chain_prefix
3827
+						 . $field_obj->get_table_alias()
3828
+						 . "."
3829
+						 . $field_obj->get_table_column()
3830
+						 . " AS '"
3831
+						 . $table_alias_with_model_relation_chain_prefix
3832
+						 . $field_obj->get_table_alias()
3833
+						 . "."
3834
+						 . $field_obj->get_table_column()
3835
+						 . "'";
3836
+		}
3837
+		//make sure we are also getting the PKs of each table
3838
+		$tables = $this->get_tables();
3839
+		if (count($tables) > 1) {
3840
+			foreach ($tables as $table_obj) {
3841
+				$qualified_pk_column = $table_alias_with_model_relation_chain_prefix
3842
+									   . $table_obj->get_fully_qualified_pk_column();
3843
+				if (! in_array($qualified_pk_column, $selects)) {
3844
+					$selects[] = "$qualified_pk_column AS '$qualified_pk_column'";
3845
+				}
3846
+			}
3847
+		}
3848
+		return $selects;
3849
+	}
3850
+
3851
+
3852
+
3853
+	/**
3854
+	 * Given a $query_param like 'Registration.Transaction.TXN_ID', pops off 'Registration.',
3855
+	 * gets the join statement for it; gets the data types for it; and passes the remaining 'Transaction.TXN_ID'
3856
+	 * onto its related Transaction object to do the same. Returns an EE_Join_And_Data_Types object which contains the
3857
+	 * SQL for joining, and the data types
3858
+	 *
3859
+	 * @param null|string                 $original_query_param
3860
+	 * @param string                      $query_param          like Registration.Transaction.TXN_ID
3861
+	 * @param EE_Model_Query_Info_Carrier $passed_in_query_info
3862
+	 * @param    string                   $query_param_type     like Registration.Transaction.TXN_ID
3863
+	 *                                                          or 'PAY_ID'. Otherwise, we don't expect there to be a
3864
+	 *                                                          column name. We only want model names, eg 'Event.Venue'
3865
+	 *                                                          or 'Registration's
3866
+	 * @param string                      $original_query_param what it originally was (eg
3867
+	 *                                                          Registration.Transaction.TXN_ID). If null, we assume it
3868
+	 *                                                          matches $query_param
3869
+	 * @throws EE_Error
3870
+	 * @return void only modifies the EEM_Related_Model_Info_Carrier passed into it
3871
+	 */
3872
+	private function _extract_related_model_info_from_query_param(
3873
+		$query_param,
3874
+		EE_Model_Query_Info_Carrier $passed_in_query_info,
3875
+		$query_param_type,
3876
+		$original_query_param = null
3877
+	) {
3878
+		if ($original_query_param === null) {
3879
+			$original_query_param = $query_param;
3880
+		}
3881
+		$query_param = $this->_remove_stars_and_anything_after_from_condition_query_param_key($query_param);
3882
+		/** @var $allow_logic_query_params bool whether or not to allow logic_query_params like 'NOT','OR', or 'AND' */
3883
+		$allow_logic_query_params = in_array($query_param_type, array('where', 'having'));
3884
+		$allow_fields = in_array($query_param_type, array('where', 'having', 'order_by', 'group_by', 'order'));
3885
+		//check to see if we have a field on this model
3886
+		$this_model_fields = $this->field_settings(true);
3887
+		if (array_key_exists($query_param, $this_model_fields)) {
3888
+			if ($allow_fields) {
3889
+				return;
3890
+			}
3891
+			throw new EE_Error(
3892
+				sprintf(
3893
+					__(
3894
+						"Using a field name (%s) on model %s is not allowed on this query param type '%s'. Original query param was %s",
3895
+						"event_espresso"
3896
+					),
3897
+					$query_param, get_class($this), $query_param_type, $original_query_param
3898
+				)
3899
+			);
3900
+		}
3901
+		//check if this is a special logic query param
3902
+		if (in_array($query_param, $this->_logic_query_param_keys, true)) {
3903
+			if ($allow_logic_query_params) {
3904
+				return;
3905
+			}
3906
+			throw new EE_Error(
3907
+				sprintf(
3908
+					__(
3909
+						'Logic query params ("%1$s") are being used incorrectly with the following query param ("%2$s") on model %3$s. %4$sAdditional Info:%4$s%5$s',
3910
+						'event_espresso'
3911
+					),
3912
+					implode('", "', $this->_logic_query_param_keys),
3913
+					$query_param,
3914
+					get_class($this),
3915
+					'<br />',
3916
+					"\t"
3917
+					. ' $passed_in_query_info = <pre>'
3918
+					. print_r($passed_in_query_info, true)
3919
+					. '</pre>'
3920
+					. "\n\t"
3921
+					. ' $query_param_type = '
3922
+					. $query_param_type
3923
+					. "\n\t"
3924
+					. ' $original_query_param = '
3925
+					. $original_query_param
3926
+				)
3927
+			);
3928
+		}
3929
+		//check if it's a custom selection
3930
+		if (array_key_exists($query_param, $this->_custom_selections)) {
3931
+			return;
3932
+		}
3933
+		//check if has a model name at the beginning
3934
+		//and
3935
+		//check if it's a field on a related model
3936
+		foreach ($this->_model_relations as $valid_related_model_name => $relation_obj) {
3937
+			if (strpos($query_param, $valid_related_model_name . ".") === 0) {
3938
+				$this->_add_join_to_model($valid_related_model_name, $passed_in_query_info, $original_query_param);
3939
+				$query_param = substr($query_param, strlen($valid_related_model_name . "."));
3940
+				if ($query_param === '') {
3941
+					//nothing left to $query_param
3942
+					//we should actually end in a field name, not a model like this!
3943
+					throw new EE_Error(sprintf(__("Query param '%s' (of type %s on model %s) shouldn't end on a period (.) ",
3944
+						"event_espresso"),
3945
+						$query_param, $query_param_type, get_class($this), $valid_related_model_name));
3946
+				}
3947
+				$related_model_obj = $this->get_related_model_obj($valid_related_model_name);
3948
+				$related_model_obj->_extract_related_model_info_from_query_param(
3949
+					$query_param,
3950
+					$passed_in_query_info, $query_param_type, $original_query_param
3951
+				);
3952
+				return;
3953
+			}
3954
+			if ($query_param === $valid_related_model_name) {
3955
+				$this->_add_join_to_model($valid_related_model_name, $passed_in_query_info, $original_query_param);
3956
+				return;
3957
+			}
3958
+		}
3959
+		//ok so $query_param didn't start with a model name
3960
+		//and we previously confirmed it wasn't a logic query param or field on the current model
3961
+		//it's wack, that's what it is
3962
+		throw new EE_Error(sprintf(__("There is no model named '%s' related to %s. Query param type is %s and original query param is %s",
3963
+			"event_espresso"),
3964
+			$query_param, get_class($this), $query_param_type, $original_query_param));
3965
+	}
3966
+
3967
+
3968
+
3969
+	/**
3970
+	 * Privately used by _extract_related_model_info_from_query_param to add a join to $model_name
3971
+	 * and store it on $passed_in_query_info
3972
+	 *
3973
+	 * @param string                      $model_name
3974
+	 * @param EE_Model_Query_Info_Carrier $passed_in_query_info
3975
+	 * @param string                      $original_query_param used to extract the relation chain between the queried
3976
+	 *                                                          model and $model_name. Eg, if we are querying Event,
3977
+	 *                                                          and are adding a join to 'Payment' with the original
3978
+	 *                                                          query param key
3979
+	 *                                                          'Registration.Transaction.Payment.PAY_amount', we want
3980
+	 *                                                          to extract 'Registration.Transaction.Payment', in case
3981
+	 *                                                          Payment wants to add default query params so that it
3982
+	 *                                                          will know what models to prepend onto its default query
3983
+	 *                                                          params or in case it wants to rename tables (in case
3984
+	 *                                                          there are multiple joins to the same table)
3985
+	 * @return void
3986
+	 * @throws EE_Error
3987
+	 */
3988
+	private function _add_join_to_model(
3989
+		$model_name,
3990
+		EE_Model_Query_Info_Carrier $passed_in_query_info,
3991
+		$original_query_param
3992
+	) {
3993
+		$relation_obj = $this->related_settings_for($model_name);
3994
+		$model_relation_chain = EE_Model_Parser::extract_model_relation_chain($model_name, $original_query_param);
3995
+		//check if the relation is HABTM, because then we're essentially doing two joins
3996
+		//If so, join first to the JOIN table, and add its data types, and then continue as normal
3997
+		if ($relation_obj instanceof EE_HABTM_Relation) {
3998
+			$join_model_obj = $relation_obj->get_join_model();
3999
+			//replace the model specified with the join model for this relation chain, whi
4000
+			$relation_chain_to_join_model = EE_Model_Parser::replace_model_name_with_join_model_name_in_model_relation_chain($model_name,
4001
+				$join_model_obj->get_this_model_name(), $model_relation_chain);
4002
+			$passed_in_query_info->merge(
4003
+				new EE_Model_Query_Info_Carrier(
4004
+					array($relation_chain_to_join_model => $join_model_obj->get_this_model_name()),
4005
+					$relation_obj->get_join_to_intermediate_model_statement($relation_chain_to_join_model)
4006
+				)
4007
+			);
4008
+		}
4009
+		//now just join to the other table pointed to by the relation object, and add its data types
4010
+		$passed_in_query_info->merge(
4011
+			new EE_Model_Query_Info_Carrier(
4012
+				array($model_relation_chain => $model_name),
4013
+				$relation_obj->get_join_statement($model_relation_chain)
4014
+			)
4015
+		);
4016
+	}
4017
+
4018
+
4019
+
4020
+	/**
4021
+	 * Constructs SQL for where clause, like "WHERE Event.ID = 23 AND Transaction.amount > 100" etc.
4022
+	 *
4023
+	 * @param array $where_params like EEM_Base::get_all
4024
+	 * @return string of SQL
4025
+	 * @throws EE_Error
4026
+	 */
4027
+	private function _construct_where_clause($where_params)
4028
+	{
4029
+		$SQL = $this->_construct_condition_clause_recursive($where_params, ' AND ');
4030
+		if ($SQL) {
4031
+			return " WHERE " . $SQL;
4032
+		}
4033
+		return '';
4034
+	}
4035
+
4036
+
4037
+
4038
+	/**
4039
+	 * Just like the _construct_where_clause, except prepends 'HAVING' instead of 'WHERE',
4040
+	 * and should be passed HAVING parameters, not WHERE parameters
4041
+	 *
4042
+	 * @param array $having_params
4043
+	 * @return string
4044
+	 * @throws EE_Error
4045
+	 */
4046
+	private function _construct_having_clause($having_params)
4047
+	{
4048
+		$SQL = $this->_construct_condition_clause_recursive($having_params, ' AND ');
4049
+		if ($SQL) {
4050
+			return " HAVING " . $SQL;
4051
+		}
4052
+		return '';
4053
+	}
4054
+
4055
+
4056
+	/**
4057
+	 * Used for creating nested WHERE conditions. Eg "WHERE ! (Event.ID = 3 OR ( Event_Meta.meta_key = 'bob' AND
4058
+	 * Event_Meta.meta_value = 'foo'))"
4059
+	 *
4060
+	 * @param array  $where_params see EEM_Base::get_all for documentation
4061
+	 * @param string $glue         joins each subclause together. Should really only be " AND " or " OR "...
4062
+	 * @throws EE_Error
4063
+	 * @return string of SQL
4064
+	 */
4065
+	private function _construct_condition_clause_recursive($where_params, $glue = ' AND')
4066
+	{
4067
+		$where_clauses = array();
4068
+		foreach ($where_params as $query_param => $op_and_value_or_sub_condition) {
4069
+			$query_param = $this->_remove_stars_and_anything_after_from_condition_query_param_key($query_param);//str_replace("*",'',$query_param);
4070
+			if (in_array($query_param, $this->_logic_query_param_keys)) {
4071
+				switch ($query_param) {
4072
+					case 'not':
4073
+					case 'NOT':
4074
+						$where_clauses[] = "! ("
4075
+										   . $this->_construct_condition_clause_recursive($op_and_value_or_sub_condition,
4076
+								$glue)
4077
+										   . ")";
4078
+						break;
4079
+					case 'and':
4080
+					case 'AND':
4081
+						$where_clauses[] = " ("
4082
+										   . $this->_construct_condition_clause_recursive($op_and_value_or_sub_condition,
4083
+								' AND ')
4084
+										   . ")";
4085
+						break;
4086
+					case 'or':
4087
+					case 'OR':
4088
+						$where_clauses[] = " ("
4089
+										   . $this->_construct_condition_clause_recursive($op_and_value_or_sub_condition,
4090
+								' OR ')
4091
+										   . ")";
4092
+						break;
4093
+				}
4094
+			} else {
4095
+				$field_obj = $this->_deduce_field_from_query_param($query_param);
4096
+				//if it's not a normal field, maybe it's a custom selection?
4097
+				if (! $field_obj) {
4098
+					if (isset($this->_custom_selections[$query_param][1])) {
4099
+						$field_obj = $this->_custom_selections[$query_param][1];
4100
+					} else {
4101
+						throw new EE_Error(sprintf(__("%s is neither a valid model field name, nor a custom selection",
4102
+							"event_espresso"), $query_param));
4103
+					}
4104
+				}
4105
+				$op_and_value_sql = $this->_construct_op_and_value($op_and_value_or_sub_condition, $field_obj);
4106
+				$where_clauses[] = $this->_deduce_column_name_from_query_param($query_param) . SP . $op_and_value_sql;
4107
+			}
4108
+		}
4109
+		return $where_clauses ? implode($glue, $where_clauses) : '';
4110
+	}
4111
+
4112
+
4113
+
4114
+	/**
4115
+	 * Takes the input parameter and extract the table name (alias) and column name
4116
+	 *
4117
+	 * @param string $query_param like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
4118
+	 * @throws EE_Error
4119
+	 * @return string table alias and column name for SQL, eg "Transaction.TXN_ID"
4120
+	 */
4121
+	private function _deduce_column_name_from_query_param($query_param)
4122
+	{
4123
+		$field = $this->_deduce_field_from_query_param($query_param);
4124
+		if ($field) {
4125
+			$table_alias_prefix = EE_Model_Parser::extract_table_alias_model_relation_chain_from_query_param($field->get_model_name(),
4126
+				$query_param);
4127
+			return $table_alias_prefix . $field->get_qualified_column();
4128
+		}
4129
+		if (array_key_exists($query_param, $this->_custom_selections)) {
4130
+			//maybe it's custom selection item?
4131
+			//if so, just use it as the "column name"
4132
+			return $query_param;
4133
+		}
4134
+		throw new EE_Error(
4135
+			sprintf(
4136
+				__(
4137
+					"%s is not a valid field on this model, nor a custom selection (%s)",
4138
+					"event_espresso"
4139
+				), $query_param, implode(",", $this->_custom_selections)
4140
+			)
4141
+		);
4142
+	}
4143
+
4144
+
4145
+
4146
+	/**
4147
+	 * Removes the * and anything after it from the condition query param key. It is useful to add the * to condition
4148
+	 * query param keys (eg, 'OR*', 'EVT_ID') in order for the array keys to still be unique, so that they don't get
4149
+	 * overwritten Takes a string like 'Event.EVT_ID*', 'TXN_total**', 'OR*1st', and 'DTT_reg_start*foobar' to
4150
+	 * 'Event.EVT_ID', 'TXN_total', 'OR', and 'DTT_reg_start', respectively.
4151
+	 *
4152
+	 * @param string $condition_query_param_key
4153
+	 * @return string
4154
+	 */
4155
+	private function _remove_stars_and_anything_after_from_condition_query_param_key($condition_query_param_key)
4156
+	{
4157
+		$pos_of_star = strpos($condition_query_param_key, '*');
4158
+		if ($pos_of_star === false) {
4159
+			return $condition_query_param_key;
4160
+		}
4161
+		$condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
4162
+		return $condition_query_param_sans_star;
4163
+	}
4164
+
4165
+
4166
+
4167
+	/**
4168
+	 * creates the SQL for the operator and the value in a WHERE clause, eg "< 23" or "LIKE '%monkey%'"
4169
+	 *
4170
+	 * @param                            mixed      array | string    $op_and_value
4171
+	 * @param EE_Model_Field_Base|string $field_obj . If string, should be one of EEM_Base::_valid_wpdb_data_types
4172
+	 * @throws EE_Error
4173
+	 * @return string
4174
+	 */
4175
+	private function _construct_op_and_value($op_and_value, $field_obj)
4176
+	{
4177
+		if (is_array($op_and_value)) {
4178
+			$operator = isset($op_and_value[0]) ? $this->_prepare_operator_for_sql($op_and_value[0]) : null;
4179
+			if (! $operator) {
4180
+				$php_array_like_string = array();
4181
+				foreach ($op_and_value as $key => $value) {
4182
+					$php_array_like_string[] = "$key=>$value";
4183
+				}
4184
+				throw new EE_Error(
4185
+					sprintf(
4186
+						__(
4187
+							"You setup a query parameter like you were going to specify an operator, but didn't. You provided '(%s)', but the operator should be at array key index 0 (eg array('>',32))",
4188
+							"event_espresso"
4189
+						),
4190
+						implode(",", $php_array_like_string)
4191
+					)
4192
+				);
4193
+			}
4194
+			$value = isset($op_and_value[1]) ? $op_and_value[1] : null;
4195
+		} else {
4196
+			$operator = '=';
4197
+			$value = $op_and_value;
4198
+		}
4199
+		//check to see if the value is actually another field
4200
+		if (is_array($op_and_value) && isset($op_and_value[2]) && $op_and_value[2] == true) {
4201
+			return $operator . SP . $this->_deduce_column_name_from_query_param($value);
4202
+		}
4203
+		if (in_array($operator, $this->valid_in_style_operators()) && is_array($value)) {
4204
+			//in this case, the value should be an array, or at least a comma-separated list
4205
+			//it will need to handle a little differently
4206
+			$cleaned_value = $this->_construct_in_value($value, $field_obj);
4207
+			//note: $cleaned_value has already been run through $wpdb->prepare()
4208
+			return $operator . SP . $cleaned_value;
4209
+		}
4210
+		if (in_array($operator, $this->valid_between_style_operators()) && is_array($value)) {
4211
+			//the value should be an array with count of two.
4212
+			if (count($value) !== 2) {
4213
+				throw new EE_Error(
4214
+					sprintf(
4215
+						__(
4216
+							"The '%s' operator must be used with an array of values and there must be exactly TWO values in that array.",
4217
+							'event_espresso'
4218
+						),
4219
+						"BETWEEN"
4220
+					)
4221
+				);
4222
+			}
4223
+			$cleaned_value = $this->_construct_between_value($value, $field_obj);
4224
+			return $operator . SP . $cleaned_value;
4225
+		}
4226
+		if (in_array($operator, $this->valid_null_style_operators())) {
4227
+			if ($value !== null) {
4228
+				throw new EE_Error(
4229
+					sprintf(
4230
+						__(
4231
+							"You attempted to give a value  (%s) while using a NULL-style operator (%s). That isn't valid",
4232
+							"event_espresso"
4233
+						),
4234
+						$value,
4235
+						$operator
4236
+					)
4237
+				);
4238
+			}
4239
+			return $operator;
4240
+		}
4241
+		if (in_array($operator, $this->valid_like_style_operators()) && ! is_array($value)) {
4242
+			//if the operator is 'LIKE', we want to allow percent signs (%) and not
4243
+			//remove other junk. So just treat it as a string.
4244
+			return $operator . SP . $this->_wpdb_prepare_using_field($value, '%s');
4245
+		}
4246
+		if (! in_array($operator, $this->valid_in_style_operators()) && ! is_array($value)) {
4247
+			return $operator . SP . $this->_wpdb_prepare_using_field($value, $field_obj);
4248
+		}
4249
+		if (in_array($operator, $this->valid_in_style_operators()) && ! is_array($value)) {
4250
+			throw new EE_Error(
4251
+				sprintf(
4252
+					__(
4253
+						"Operator '%s' must be used with an array of values, eg 'Registration.REG_ID' => array('%s',array(1,2,3))",
4254
+						'event_espresso'
4255
+					),
4256
+					$operator,
4257
+					$operator
4258
+				)
4259
+			);
4260
+		}
4261
+		if (! in_array($operator, $this->valid_in_style_operators()) && is_array($value)) {
4262
+			throw new EE_Error(
4263
+				sprintf(
4264
+					__(
4265
+						"Operator '%s' must be used with a single value, not an array. Eg 'Registration.REG_ID => array('%s',23))",
4266
+						'event_espresso'
4267
+					),
4268
+					$operator,
4269
+					$operator
4270
+				)
4271
+			);
4272
+		}
4273
+		throw new EE_Error(
4274
+			sprintf(
4275
+				__(
4276
+					"It appears you've provided some totally invalid query parameters. Operator and value were:'%s', which isn't right at all",
4277
+					"event_espresso"
4278
+				),
4279
+				http_build_query($op_and_value)
4280
+			)
4281
+		);
4282
+	}
4283
+
4284
+
4285
+
4286
+	/**
4287
+	 * Creates the operands to be used in a BETWEEN query, eg "'2014-12-31 20:23:33' AND '2015-01-23 12:32:54'"
4288
+	 *
4289
+	 * @param array                      $values
4290
+	 * @param EE_Model_Field_Base|string $field_obj if string, it should be the datatype to be used when querying, eg
4291
+	 *                                              '%s'
4292
+	 * @return string
4293
+	 * @throws EE_Error
4294
+	 */
4295
+	public function _construct_between_value($values, $field_obj)
4296
+	{
4297
+		$cleaned_values = array();
4298
+		foreach ($values as $value) {
4299
+			$cleaned_values[] = $this->_wpdb_prepare_using_field($value, $field_obj);
4300
+		}
4301
+		return $cleaned_values[0] . " AND " . $cleaned_values[1];
4302
+	}
4303
+
4304
+
4305
+
4306
+	/**
4307
+	 * Takes an array or a comma-separated list of $values and cleans them
4308
+	 * according to $data_type using $wpdb->prepare, and then makes the list a
4309
+	 * string surrounded by ( and ). Eg, _construct_in_value(array(1,2,3),'%d') would
4310
+	 * return '(1,2,3)'; _construct_in_value("1,2,hack",'%d') would return '(1,2,1)' (assuming
4311
+	 * I'm right that a string, when interpreted as a digit, becomes a 1. It might become a 0)
4312
+	 *
4313
+	 * @param mixed                      $values    array or comma-separated string
4314
+	 * @param EE_Model_Field_Base|string $field_obj if string, it should be a wpdb data type like '%s', or '%d'
4315
+	 * @return string of SQL to follow an 'IN' or 'NOT IN' operator
4316
+	 * @throws EE_Error
4317
+	 */
4318
+	public function _construct_in_value($values, $field_obj)
4319
+	{
4320
+		//check if the value is a CSV list
4321
+		if (is_string($values)) {
4322
+			//in which case, turn it into an array
4323
+			$values = explode(",", $values);
4324
+		}
4325
+		$cleaned_values = array();
4326
+		foreach ($values as $value) {
4327
+			$cleaned_values[] = $this->_wpdb_prepare_using_field($value, $field_obj);
4328
+		}
4329
+		//we would just LOVE to leave $cleaned_values as an empty array, and return the value as "()",
4330
+		//but unfortunately that's invalid SQL. So instead we return a string which we KNOW will evaluate to be the empty set
4331
+		//which is effectively equivalent to returning "()". We don't return "(0)" because that only works for auto-incrementing columns
4332
+		if (empty($cleaned_values)) {
4333
+			$all_fields = $this->field_settings();
4334
+			$a_field = array_shift($all_fields);
4335
+			$main_table = $this->_get_main_table();
4336
+			$cleaned_values[] = "SELECT "
4337
+								. $a_field->get_table_column()
4338
+								. " FROM "
4339
+								. $main_table->get_table_name()
4340
+								. " WHERE FALSE";
4341
+		}
4342
+		return "(" . implode(",", $cleaned_values) . ")";
4343
+	}
4344
+
4345
+
4346
+
4347
+	/**
4348
+	 * @param mixed                      $value
4349
+	 * @param EE_Model_Field_Base|string $field_obj if string it should be a wpdb data type like '%d'
4350
+	 * @throws EE_Error
4351
+	 * @return false|null|string
4352
+	 */
4353
+	private function _wpdb_prepare_using_field($value, $field_obj)
4354
+	{
4355
+		/** @type WPDB $wpdb */
4356
+		global $wpdb;
4357
+		if ($field_obj instanceof EE_Model_Field_Base) {
4358
+			return $wpdb->prepare($field_obj->get_wpdb_data_type(),
4359
+				$this->_prepare_value_for_use_in_db($value, $field_obj));
4360
+		} //$field_obj should really just be a data type
4361
+		if (! in_array($field_obj, $this->_valid_wpdb_data_types)) {
4362
+			throw new EE_Error(
4363
+				sprintf(
4364
+					__("%s is not a valid wpdb datatype. Valid ones are %s", "event_espresso"),
4365
+					$field_obj, implode(",", $this->_valid_wpdb_data_types)
4366
+				)
4367
+			);
4368
+		}
4369
+		return $wpdb->prepare($field_obj, $value);
4370
+	}
4371
+
4372
+
4373
+
4374
+	/**
4375
+	 * Takes the input parameter and finds the model field that it indicates.
4376
+	 *
4377
+	 * @param string $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
4378
+	 * @throws EE_Error
4379
+	 * @return EE_Model_Field_Base
4380
+	 */
4381
+	protected function _deduce_field_from_query_param($query_param_name)
4382
+	{
4383
+		//ok, now proceed with deducing which part is the model's name, and which is the field's name
4384
+		//which will help us find the database table and column
4385
+		$query_param_parts = explode(".", $query_param_name);
4386
+		if (empty($query_param_parts)) {
4387
+			throw new EE_Error(sprintf(__("_extract_column_name is empty when trying to extract column and table name from %s",
4388
+				'event_espresso'), $query_param_name));
4389
+		}
4390
+		$number_of_parts = count($query_param_parts);
4391
+		$last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
4392
+		if ($number_of_parts === 1) {
4393
+			$field_name = $last_query_param_part;
4394
+			$model_obj = $this;
4395
+		} else {// $number_of_parts >= 2
4396
+			//the last part is the column name, and there are only 2parts. therefore...
4397
+			$field_name = $last_query_param_part;
4398
+			$model_obj = $this->get_related_model_obj($query_param_parts[$number_of_parts - 2]);
4399
+		}
4400
+		try {
4401
+			return $model_obj->field_settings_for($field_name);
4402
+		} catch (EE_Error $e) {
4403
+			return null;
4404
+		}
4405
+	}
4406
+
4407
+
4408
+
4409
+	/**
4410
+	 * Given a field's name (ie, a key in $this->field_settings()), uses the EE_Model_Field object to get the table's
4411
+	 * alias and column which corresponds to it
4412
+	 *
4413
+	 * @param string $field_name
4414
+	 * @throws EE_Error
4415
+	 * @return string
4416
+	 */
4417
+	public function _get_qualified_column_for_field($field_name)
4418
+	{
4419
+		$all_fields = $this->field_settings();
4420
+		$field = isset($all_fields[$field_name]) ? $all_fields[$field_name] : false;
4421
+		if ($field) {
4422
+			return $field->get_qualified_column();
4423
+		}
4424
+		throw new EE_Error(
4425
+			sprintf(
4426
+				__(
4427
+					"There is no field titled %s on model %s. Either the query trying to use it is bad, or you need to add it to the list of fields on the model.",
4428
+					'event_espresso'
4429
+				), $field_name, get_class($this)
4430
+			)
4431
+		);
4432
+	}
4433
+
4434
+
4435
+
4436
+	/**
4437
+	 * similar to \EEM_Base::_get_qualified_column_for_field() but returns an array with data for ALL fields.
4438
+	 * Example usage:
4439
+	 * EEM_Ticket::instance()->get_all_wpdb_results(
4440
+	 *      array(),
4441
+	 *      ARRAY_A,
4442
+	 *      EEM_Ticket::instance()->get_qualified_columns_for_all_fields()
4443
+	 *  );
4444
+	 * is equivalent to
4445
+	 *  EEM_Ticket::instance()->get_all_wpdb_results( array(), ARRAY_A, '*' );
4446
+	 * and
4447
+	 *  EEM_Event::instance()->get_all_wpdb_results(
4448
+	 *      array(
4449
+	 *          array(
4450
+	 *              'Datetime.Ticket.TKT_ID' => array( '<', 100 ),
4451
+	 *          ),
4452
+	 *          ARRAY_A,
4453
+	 *          implode(
4454
+	 *              ', ',
4455
+	 *              array_merge(
4456
+	 *                  EEM_Event::instance()->get_qualified_columns_for_all_fields( '', false ),
4457
+	 *                  EEM_Ticket::instance()->get_qualified_columns_for_all_fields( 'Datetime', false )
4458
+	 *              )
4459
+	 *          )
4460
+	 *      )
4461
+	 *  );
4462
+	 * selects rows from the database, selecting all the event and ticket columns, where the ticket ID is below 100
4463
+	 *
4464
+	 * @param string $model_relation_chain        the chain of models used to join between the model you want to query
4465
+	 *                                            and the one whose fields you are selecting for example: when querying
4466
+	 *                                            tickets model and selecting fields from the tickets model you would
4467
+	 *                                            leave this parameter empty, because no models are needed to join
4468
+	 *                                            between the queried model and the selected one. Likewise when
4469
+	 *                                            querying the datetime model and selecting fields from the tickets
4470
+	 *                                            model, it would also be left empty, because there is a direct
4471
+	 *                                            relation from datetimes to tickets, so no model is needed to join
4472
+	 *                                            them together. However, when querying from the event model and
4473
+	 *                                            selecting fields from the ticket model, you should provide the string
4474
+	 *                                            'Datetime', indicating that the event model must first join to the
4475
+	 *                                            datetime model in order to find its relation to ticket model.
4476
+	 *                                            Also, when querying from the venue model and selecting fields from
4477
+	 *                                            the ticket model, you should provide the string 'Event.Datetime',
4478
+	 *                                            indicating you need to join the venue model to the event model,
4479
+	 *                                            to the datetime model, in order to find its relation to the ticket model.
4480
+	 *                                            This string is used to deduce the prefix that gets added onto the
4481
+	 *                                            models' tables qualified columns
4482
+	 * @param bool   $return_string               if true, will return a string with qualified column names separated
4483
+	 *                                            by ', ' if false, will simply return a numerically indexed array of
4484
+	 *                                            qualified column names
4485
+	 * @return array|string
4486
+	 */
4487
+	public function get_qualified_columns_for_all_fields($model_relation_chain = '', $return_string = true)
4488
+	{
4489
+		$table_prefix = str_replace('.', '__', $model_relation_chain) . (empty($model_relation_chain) ? '' : '__');
4490
+		$qualified_columns = array();
4491
+		foreach ($this->field_settings() as $field_name => $field) {
4492
+			$qualified_columns[] = $table_prefix . $field->get_qualified_column();
4493
+		}
4494
+		return $return_string ? implode(', ', $qualified_columns) : $qualified_columns;
4495
+	}
4496
+
4497
+
4498
+
4499
+	/**
4500
+	 * constructs the select use on special limit joins
4501
+	 * NOTE: for now this has only been tested and will work when the  table alias is for the PRIMARY table. Although
4502
+	 * its setup so the select query will be setup on and just doing the special select join off of the primary table
4503
+	 * (as that is typically where the limits would be set).
4504
+	 *
4505
+	 * @param  string       $table_alias The table the select is being built for
4506
+	 * @param  mixed|string $limit       The limit for this select
4507
+	 * @return string                The final select join element for the query.
4508
+	 */
4509
+	public function _construct_limit_join_select($table_alias, $limit)
4510
+	{
4511
+		$SQL = '';
4512
+		foreach ($this->_tables as $table_obj) {
4513
+			if ($table_obj instanceof EE_Primary_Table) {
4514
+				$SQL .= $table_alias === $table_obj->get_table_alias()
4515
+					? $table_obj->get_select_join_limit($limit)
4516
+					: SP . $table_obj->get_table_name() . " AS " . $table_obj->get_table_alias() . SP;
4517
+			} elseif ($table_obj instanceof EE_Secondary_Table) {
4518
+				$SQL .= $table_alias === $table_obj->get_table_alias()
4519
+					? $table_obj->get_select_join_limit_join($limit)
4520
+					: SP . $table_obj->get_join_sql($table_alias) . SP;
4521
+			}
4522
+		}
4523
+		return $SQL;
4524
+	}
4525
+
4526
+
4527
+
4528
+	/**
4529
+	 * Constructs the internal join if there are multiple tables, or simply the table's name and alias
4530
+	 * Eg "wp_post AS Event" or "wp_post AS Event INNER JOIN wp_postmeta Event_Meta ON Event.ID = Event_Meta.post_id"
4531
+	 *
4532
+	 * @return string SQL
4533
+	 * @throws EE_Error
4534
+	 */
4535
+	public function _construct_internal_join()
4536
+	{
4537
+		$SQL = $this->_get_main_table()->get_table_sql();
4538
+		$SQL .= $this->_construct_internal_join_to_table_with_alias($this->_get_main_table()->get_table_alias());
4539
+		return $SQL;
4540
+	}
4541
+
4542
+
4543
+
4544
+	/**
4545
+	 * Constructs the SQL for joining all the tables on this model.
4546
+	 * Normally $alias should be the primary table's alias, but in cases where
4547
+	 * we have already joined to a secondary table (eg, the secondary table has a foreign key and is joined before the
4548
+	 * primary table) then we should provide that secondary table's alias. Eg, with $alias being the primary table's
4549
+	 * alias, this will construct SQL like:
4550
+	 * " INNER JOIN wp_esp_secondary_table AS Secondary_Table ON Primary_Table.pk = Secondary_Table.fk".
4551
+	 * With $alias being a secondary table's alias, this will construct SQL like:
4552
+	 * " INNER JOIN wp_esp_primary_table AS Primary_Table ON Primary_Table.pk = Secondary_Table.fk".
4553
+	 *
4554
+	 * @param string $alias_prefixed table alias to join to (this table should already be in the FROM SQL clause)
4555
+	 * @return string
4556
+	 */
4557
+	public function _construct_internal_join_to_table_with_alias($alias_prefixed)
4558
+	{
4559
+		$SQL = '';
4560
+		$alias_sans_prefix = EE_Model_Parser::remove_table_alias_model_relation_chain_prefix($alias_prefixed);
4561
+		foreach ($this->_tables as $table_obj) {
4562
+			if ($table_obj instanceof EE_Secondary_Table) {//table is secondary table
4563
+				if ($alias_sans_prefix === $table_obj->get_table_alias()) {
4564
+					//so we're joining to this table, meaning the table is already in
4565
+					//the FROM statement, BUT the primary table isn't. So we want
4566
+					//to add the inverse join sql
4567
+					$SQL .= $table_obj->get_inverse_join_sql($alias_prefixed);
4568
+				} else {
4569
+					//just add a regular JOIN to this table from the primary table
4570
+					$SQL .= $table_obj->get_join_sql($alias_prefixed);
4571
+				}
4572
+			}//if it's a primary table, dont add any SQL. it should already be in the FROM statement
4573
+		}
4574
+		return $SQL;
4575
+	}
4576
+
4577
+
4578
+
4579
+	/**
4580
+	 * Gets an array for storing all the data types on the next-to-be-executed-query.
4581
+	 * This should be a growing array of keys being table-columns (eg 'EVT_ID' and 'Event.EVT_ID'), and values being
4582
+	 * their data type (eg, '%s', '%d', etc)
4583
+	 *
4584
+	 * @return array
4585
+	 */
4586
+	public function _get_data_types()
4587
+	{
4588
+		$data_types = array();
4589
+		foreach ($this->field_settings() as $field_obj) {
4590
+			//$data_types[$field_obj->get_table_column()] = $field_obj->get_wpdb_data_type();
4591
+			/** @var $field_obj EE_Model_Field_Base */
4592
+			$data_types[$field_obj->get_qualified_column()] = $field_obj->get_wpdb_data_type();
4593
+		}
4594
+		return $data_types;
4595
+	}
4596
+
4597
+
4598
+
4599
+	/**
4600
+	 * Gets the model object given the relation's name / model's name (eg, 'Event', 'Registration',etc. Always singular)
4601
+	 *
4602
+	 * @param string $model_name
4603
+	 * @throws EE_Error
4604
+	 * @return EEM_Base
4605
+	 */
4606
+	public function get_related_model_obj($model_name)
4607
+	{
4608
+		$model_classname = "EEM_" . $model_name;
4609
+		if (! class_exists($model_classname)) {
4610
+			throw new EE_Error(sprintf(__("You specified a related model named %s in your query. No such model exists, if it did, it would have the classname %s",
4611
+				'event_espresso'), $model_name, $model_classname));
4612
+		}
4613
+		return call_user_func($model_classname . "::instance");
4614
+	}
4615
+
4616
+
4617
+
4618
+	/**
4619
+	 * Returns the array of EE_ModelRelations for this model.
4620
+	 *
4621
+	 * @return EE_Model_Relation_Base[]
4622
+	 */
4623
+	public function relation_settings()
4624
+	{
4625
+		return $this->_model_relations;
4626
+	}
4627
+
4628
+
4629
+
4630
+	/**
4631
+	 * Gets all related models that this model BELONGS TO. Handy to know sometimes
4632
+	 * because without THOSE models, this model probably doesn't have much purpose.
4633
+	 * (Eg, without an event, datetimes have little purpose.)
4634
+	 *
4635
+	 * @return EE_Belongs_To_Relation[]
4636
+	 */
4637
+	public function belongs_to_relations()
4638
+	{
4639
+		$belongs_to_relations = array();
4640
+		foreach ($this->relation_settings() as $model_name => $relation_obj) {
4641
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
4642
+				$belongs_to_relations[$model_name] = $relation_obj;
4643
+			}
4644
+		}
4645
+		return $belongs_to_relations;
4646
+	}
4647
+
4648
+
4649
+
4650
+	/**
4651
+	 * Returns the specified EE_Model_Relation, or throws an exception
4652
+	 *
4653
+	 * @param string $relation_name name of relation, key in $this->_relatedModels
4654
+	 * @throws EE_Error
4655
+	 * @return EE_Model_Relation_Base
4656
+	 */
4657
+	public function related_settings_for($relation_name)
4658
+	{
4659
+		$relatedModels = $this->relation_settings();
4660
+		if (! array_key_exists($relation_name, $relatedModels)) {
4661
+			throw new EE_Error(
4662
+				sprintf(
4663
+					__('Cannot get %s related to %s. There is no model relation of that type. There is, however, %s...',
4664
+						'event_espresso'),
4665
+					$relation_name,
4666
+					$this->_get_class_name(),
4667
+					implode(', ', array_keys($relatedModels))
4668
+				)
4669
+			);
4670
+		}
4671
+		return $relatedModels[$relation_name];
4672
+	}
4673
+
4674
+
4675
+
4676
+	/**
4677
+	 * A convenience method for getting a specific field's settings, instead of getting all field settings for all
4678
+	 * fields
4679
+	 *
4680
+	 * @param string $fieldName
4681
+	 * @param boolean $include_db_only_fields
4682
+	 * @throws EE_Error
4683
+	 * @return EE_Model_Field_Base
4684
+	 */
4685
+	public function field_settings_for($fieldName, $include_db_only_fields = true)
4686
+	{
4687
+		$fieldSettings = $this->field_settings($include_db_only_fields);
4688
+		if (! array_key_exists($fieldName, $fieldSettings)) {
4689
+			throw new EE_Error(sprintf(__("There is no field/column '%s' on '%s'", 'event_espresso'), $fieldName,
4690
+				get_class($this)));
4691
+		}
4692
+		return $fieldSettings[$fieldName];
4693
+	}
4694
+
4695
+
4696
+
4697
+	/**
4698
+	 * Checks if this field exists on this model
4699
+	 *
4700
+	 * @param string $fieldName a key in the model's _field_settings array
4701
+	 * @return boolean
4702
+	 */
4703
+	public function has_field($fieldName)
4704
+	{
4705
+		$fieldSettings = $this->field_settings(true);
4706
+		if (isset($fieldSettings[$fieldName])) {
4707
+			return true;
4708
+		}
4709
+		return false;
4710
+	}
4711
+
4712
+
4713
+
4714
+	/**
4715
+	 * Returns whether or not this model has a relation to the specified model
4716
+	 *
4717
+	 * @param string $relation_name possibly one of the keys in the relation_settings array
4718
+	 * @return boolean
4719
+	 */
4720
+	public function has_relation($relation_name)
4721
+	{
4722
+		$relations = $this->relation_settings();
4723
+		if (isset($relations[$relation_name])) {
4724
+			return true;
4725
+		}
4726
+		return false;
4727
+	}
4728
+
4729
+
4730
+
4731
+	/**
4732
+	 * gets the field object of type 'primary_key' from the fieldsSettings attribute.
4733
+	 * Eg, on EE_Answer that would be ANS_ID field object
4734
+	 *
4735
+	 * @param $field_obj
4736
+	 * @return boolean
4737
+	 */
4738
+	public function is_primary_key_field($field_obj)
4739
+	{
4740
+		return $field_obj instanceof EE_Primary_Key_Field_Base ? true : false;
4741
+	}
4742
+
4743
+
4744
+
4745
+	/**
4746
+	 * gets the field object of type 'primary_key' from the fieldsSettings attribute.
4747
+	 * Eg, on EE_Answer that would be ANS_ID field object
4748
+	 *
4749
+	 * @return EE_Model_Field_Base
4750
+	 * @throws EE_Error
4751
+	 */
4752
+	public function get_primary_key_field()
4753
+	{
4754
+		if ($this->_primary_key_field === null) {
4755
+			foreach ($this->field_settings(true) as $field_obj) {
4756
+				if ($this->is_primary_key_field($field_obj)) {
4757
+					$this->_primary_key_field = $field_obj;
4758
+					break;
4759
+				}
4760
+			}
4761
+			if (! $this->_primary_key_field instanceof EE_Primary_Key_Field_Base) {
4762
+				throw new EE_Error(sprintf(__("There is no Primary Key defined on model %s", 'event_espresso'),
4763
+					get_class($this)));
4764
+			}
4765
+		}
4766
+		return $this->_primary_key_field;
4767
+	}
4768
+
4769
+
4770
+
4771
+	/**
4772
+	 * Returns whether or not not there is a primary key on this model.
4773
+	 * Internally does some caching.
4774
+	 *
4775
+	 * @return boolean
4776
+	 */
4777
+	public function has_primary_key_field()
4778
+	{
4779
+		if ($this->_has_primary_key_field === null) {
4780
+			try {
4781
+				$this->get_primary_key_field();
4782
+				$this->_has_primary_key_field = true;
4783
+			} catch (EE_Error $e) {
4784
+				$this->_has_primary_key_field = false;
4785
+			}
4786
+		}
4787
+		return $this->_has_primary_key_field;
4788
+	}
4789
+
4790
+
4791
+
4792
+	/**
4793
+	 * Finds the first field of type $field_class_name.
4794
+	 *
4795
+	 * @param string $field_class_name class name of field that you want to find. Eg, EE_Datetime_Field,
4796
+	 *                                 EE_Foreign_Key_Field, etc
4797
+	 * @return EE_Model_Field_Base or null if none is found
4798
+	 */
4799
+	public function get_a_field_of_type($field_class_name)
4800
+	{
4801
+		foreach ($this->field_settings() as $field) {
4802
+			if ($field instanceof $field_class_name) {
4803
+				return $field;
4804
+			}
4805
+		}
4806
+		return null;
4807
+	}
4808
+
4809
+
4810
+
4811
+	/**
4812
+	 * Gets a foreign key field pointing to model.
4813
+	 *
4814
+	 * @param string $model_name eg Event, Registration, not EEM_Event
4815
+	 * @return EE_Foreign_Key_Field_Base
4816
+	 * @throws EE_Error
4817
+	 */
4818
+	public function get_foreign_key_to($model_name)
4819
+	{
4820
+		if (! isset($this->_cache_foreign_key_to_fields[$model_name])) {
4821
+			foreach ($this->field_settings() as $field) {
4822
+				if (
4823
+					$field instanceof EE_Foreign_Key_Field_Base
4824
+					&& in_array($model_name, $field->get_model_names_pointed_to())
4825
+				) {
4826
+					$this->_cache_foreign_key_to_fields[$model_name] = $field;
4827
+					break;
4828
+				}
4829
+			}
4830
+			if (! isset($this->_cache_foreign_key_to_fields[$model_name])) {
4831
+				throw new EE_Error(sprintf(__("There is no foreign key field pointing to model %s on model %s",
4832
+					'event_espresso'), $model_name, get_class($this)));
4833
+			}
4834
+		}
4835
+		return $this->_cache_foreign_key_to_fields[$model_name];
4836
+	}
4837
+
4838
+
4839
+
4840
+	/**
4841
+	 * Gets the table name (including $wpdb->prefix) for the table alias
4842
+	 *
4843
+	 * @param string $table_alias eg Event, Event_Meta, Registration, Transaction, but maybe
4844
+	 *                            a table alias with a model chain prefix, like 'Venue__Event_Venue___Event_Meta'.
4845
+	 *                            Either one works
4846
+	 * @return string
4847
+	 */
4848
+	public function get_table_for_alias($table_alias)
4849
+	{
4850
+		$table_alias_sans_model_relation_chain_prefix = EE_Model_Parser::remove_table_alias_model_relation_chain_prefix($table_alias);
4851
+		return $this->_tables[$table_alias_sans_model_relation_chain_prefix]->get_table_name();
4852
+	}
4853
+
4854
+
4855
+
4856
+	/**
4857
+	 * Returns a flat array of all field son this model, instead of organizing them
4858
+	 * by table_alias as they are in the constructor.
4859
+	 *
4860
+	 * @param bool $include_db_only_fields flag indicating whether or not to include the db-only fields
4861
+	 * @return EE_Model_Field_Base[] where the keys are the field's name
4862
+	 */
4863
+	public function field_settings($include_db_only_fields = false)
4864
+	{
4865
+		if ($include_db_only_fields) {
4866
+			if ($this->_cached_fields === null) {
4867
+				$this->_cached_fields = array();
4868
+				foreach ($this->_fields as $fields_corresponding_to_table) {
4869
+					foreach ($fields_corresponding_to_table as $field_name => $field_obj) {
4870
+						$this->_cached_fields[$field_name] = $field_obj;
4871
+					}
4872
+				}
4873
+			}
4874
+			return $this->_cached_fields;
4875
+		}
4876
+		if ($this->_cached_fields_non_db_only === null) {
4877
+			$this->_cached_fields_non_db_only = array();
4878
+			foreach ($this->_fields as $fields_corresponding_to_table) {
4879
+				foreach ($fields_corresponding_to_table as $field_name => $field_obj) {
4880
+					/** @var $field_obj EE_Model_Field_Base */
4881
+					if (! $field_obj->is_db_only_field()) {
4882
+						$this->_cached_fields_non_db_only[$field_name] = $field_obj;
4883
+					}
4884
+				}
4885
+			}
4886
+		}
4887
+		return $this->_cached_fields_non_db_only;
4888
+	}
4889
+
4890
+
4891
+
4892
+	/**
4893
+	 *        cycle though array of attendees and create objects out of each item
4894
+	 *
4895
+	 * @access        private
4896
+	 * @param        array $rows of results of $wpdb->get_results($query,ARRAY_A)
4897
+	 * @return \EE_Base_Class[] array keys are primary keys (if there is a primary key on the model. if not,
4898
+	 *                           numerically indexed)
4899
+	 * @throws EE_Error
4900
+	 */
4901
+	protected function _create_objects($rows = array())
4902
+	{
4903
+		$array_of_objects = array();
4904
+		if (empty($rows)) {
4905
+			return array();
4906
+		}
4907
+		$count_if_model_has_no_primary_key = 0;
4908
+		$has_primary_key = $this->has_primary_key_field();
4909
+		$primary_key_field = $has_primary_key ? $this->get_primary_key_field() : null;
4910
+		foreach ((array)$rows as $row) {
4911
+			if (empty($row)) {
4912
+				//wp did its weird thing where it returns an array like array(0=>null), which is totally not helpful...
4913
+				return array();
4914
+			}
4915
+			//check if we've already set this object in the results array,
4916
+			//in which case there's no need to process it further (again)
4917
+			if ($has_primary_key) {
4918
+				$table_pk_value = $this->_get_column_value_with_table_alias_or_not(
4919
+					$row,
4920
+					$primary_key_field->get_qualified_column(),
4921
+					$primary_key_field->get_table_column()
4922
+				);
4923
+				if ($table_pk_value && isset($array_of_objects[$table_pk_value])) {
4924
+					continue;
4925
+				}
4926
+			}
4927
+			$classInstance = $this->instantiate_class_from_array_or_object($row);
4928
+			if (! $classInstance) {
4929
+				throw new EE_Error(
4930
+					sprintf(
4931
+						__('Could not create instance of class %s from row %s', 'event_espresso'),
4932
+						$this->get_this_model_name(),
4933
+						http_build_query($row)
4934
+					)
4935
+				);
4936
+			}
4937
+			//set the timezone on the instantiated objects
4938
+			$classInstance->set_timezone($this->_timezone);
4939
+			//make sure if there is any timezone setting present that we set the timezone for the object
4940
+			$key = $has_primary_key ? $classInstance->ID() : $count_if_model_has_no_primary_key++;
4941
+			$array_of_objects[$key] = $classInstance;
4942
+			//also, for all the relations of type BelongsTo, see if we can cache
4943
+			//those related models
4944
+			//(we could do this for other relations too, but if there are conditions
4945
+			//that filtered out some fo the results, then we'd be caching an incomplete set
4946
+			//so it requires a little more thought than just caching them immediately...)
4947
+			foreach ($this->_model_relations as $modelName => $relation_obj) {
4948
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
4949
+					//check if this model's INFO is present. If so, cache it on the model
4950
+					$other_model = $relation_obj->get_other_model();
4951
+					$other_model_obj_maybe = $other_model->instantiate_class_from_array_or_object($row);
4952
+					//if we managed to make a model object from the results, cache it on the main model object
4953
+					if ($other_model_obj_maybe) {
4954
+						//set timezone on these other model objects if they are present
4955
+						$other_model_obj_maybe->set_timezone($this->_timezone);
4956
+						$classInstance->cache($modelName, $other_model_obj_maybe);
4957
+					}
4958
+				}
4959
+			}
4960
+		}
4961
+		return $array_of_objects;
4962
+	}
4963
+
4964
+
4965
+
4966
+	/**
4967
+	 * The purpose of this method is to allow us to create a model object that is not in the db that holds default
4968
+	 * values. A typical example of where this is used is when creating a new item and the initial load of a form.  We
4969
+	 * dont' necessarily want to test for if the object is present but just assume it is BUT load the defaults from the
4970
+	 * object (as set in the model_field!).
4971
+	 *
4972
+	 * @return EE_Base_Class single EE_Base_Class object with default values for the properties.
4973
+	 */
4974
+	public function create_default_object()
4975
+	{
4976
+		$this_model_fields_and_values = array();
4977
+		//setup the row using default values;
4978
+		foreach ($this->field_settings() as $field_name => $field_obj) {
4979
+			$this_model_fields_and_values[$field_name] = $field_obj->get_default_value();
4980
+		}
4981
+		$className = $this->_get_class_name();
4982
+		$classInstance = EE_Registry::instance()
4983
+									->load_class($className, array($this_model_fields_and_values), false, false);
4984
+		return $classInstance;
4985
+	}
4986
+
4987
+
4988
+
4989
+	/**
4990
+	 * @param mixed $cols_n_values either an array of where each key is the name of a field, and the value is its value
4991
+	 *                             or an stdClass where each property is the name of a column,
4992
+	 * @return EE_Base_Class
4993
+	 * @throws EE_Error
4994
+	 */
4995
+	public function instantiate_class_from_array_or_object($cols_n_values)
4996
+	{
4997
+		if (! is_array($cols_n_values) && is_object($cols_n_values)) {
4998
+			$cols_n_values = get_object_vars($cols_n_values);
4999
+		}
5000
+		$primary_key = null;
5001
+		//make sure the array only has keys that are fields/columns on this model
5002
+		$this_model_fields_n_values = $this->_deduce_fields_n_values_from_cols_n_values($cols_n_values);
5003
+		if ($this->has_primary_key_field() && isset($this_model_fields_n_values[$this->primary_key_name()])) {
5004
+			$primary_key = $this_model_fields_n_values[$this->primary_key_name()];
5005
+		}
5006
+		$className = $this->_get_class_name();
5007
+		//check we actually found results that we can use to build our model object
5008
+		//if not, return null
5009
+		if ($this->has_primary_key_field()) {
5010
+			if (empty($this_model_fields_n_values[$this->primary_key_name()])) {
5011
+				return null;
5012
+			}
5013
+		} else if ($this->unique_indexes()) {
5014
+			$first_column = reset($this_model_fields_n_values);
5015
+			if (empty($first_column)) {
5016
+				return null;
5017
+			}
5018
+		}
5019
+		// if there is no primary key or the object doesn't already exist in the entity map, then create a new instance
5020
+		if ($primary_key) {
5021
+			$classInstance = $this->get_from_entity_map($primary_key);
5022
+			if (! $classInstance) {
5023
+				$classInstance = EE_Registry::instance()
5024
+											->load_class($className,
5025
+												array($this_model_fields_n_values, $this->_timezone), true, false);
5026
+				// add this new object to the entity map
5027
+				$classInstance = $this->add_to_entity_map($classInstance);
5028
+			}
5029
+		} else {
5030
+			$classInstance = EE_Registry::instance()
5031
+										->load_class($className, array($this_model_fields_n_values, $this->_timezone),
5032
+											true, false);
5033
+		}
5034
+		return $classInstance;
5035
+	}
5036
+
5037
+
5038
+
5039
+	/**
5040
+	 * Gets the model object from the  entity map if it exists
5041
+	 *
5042
+	 * @param int|string $id the ID of the model object
5043
+	 * @return EE_Base_Class
5044
+	 */
5045
+	public function get_from_entity_map($id)
5046
+	{
5047
+		return isset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id])
5048
+			? $this->_entity_map[EEM_Base::$_model_query_blog_id][$id] : null;
5049
+	}
5050
+
5051
+
5052
+
5053
+	/**
5054
+	 * add_to_entity_map
5055
+	 * Adds the object to the model's entity mappings
5056
+	 *        Effectively tells the models "Hey, this model object is the most up-to-date representation of the data,
5057
+	 *        and for the remainder of the request, it's even more up-to-date than what's in the database.
5058
+	 *        So, if the database doesn't agree with what's in the entity mapper, ignore the database"
5059
+	 *        If the database gets updated directly and you want the entity mapper to reflect that change,
5060
+	 *        then this method should be called immediately after the update query
5061
+	 * Note: The map is indexed by whatever the current blog id is set (via EEM_Base::$_model_query_blog_id).  This is
5062
+	 * so on multisite, the entity map is specific to the query being done for a specific site.
5063
+	 *
5064
+	 * @param    EE_Base_Class $object
5065
+	 * @throws EE_Error
5066
+	 * @return \EE_Base_Class
5067
+	 */
5068
+	public function add_to_entity_map(EE_Base_Class $object)
5069
+	{
5070
+		$className = $this->_get_class_name();
5071
+		if (! $object instanceof $className) {
5072
+			throw new EE_Error(sprintf(__("You tried adding a %s to a mapping of %ss", "event_espresso"),
5073
+				is_object($object) ? get_class($object) : $object, $className));
5074
+		}
5075
+		/** @var $object EE_Base_Class */
5076
+		if (! $object->ID()) {
5077
+			throw new EE_Error(sprintf(__("You tried storing a model object with NO ID in the %s entity mapper.",
5078
+				"event_espresso"), get_class($this)));
5079
+		}
5080
+		// double check it's not already there
5081
+		$classInstance = $this->get_from_entity_map($object->ID());
5082
+		if ($classInstance) {
5083
+			return $classInstance;
5084
+		}
5085
+		$this->_entity_map[EEM_Base::$_model_query_blog_id][$object->ID()] = $object;
5086
+		return $object;
5087
+	}
5088
+
5089
+
5090
+
5091
+	/**
5092
+	 * if a valid identifier is provided, then that entity is unset from the entity map,
5093
+	 * if no identifier is provided, then the entire entity map is emptied
5094
+	 *
5095
+	 * @param int|string $id the ID of the model object
5096
+	 * @return boolean
5097
+	 */
5098
+	public function clear_entity_map($id = null)
5099
+	{
5100
+		if (empty($id)) {
5101
+			$this->_entity_map[EEM_Base::$_model_query_blog_id] = array();
5102
+			return true;
5103
+		}
5104
+		if (isset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id])) {
5105
+			unset($this->_entity_map[EEM_Base::$_model_query_blog_id][$id]);
5106
+			return true;
5107
+		}
5108
+		return false;
5109
+	}
5110
+
5111
+
5112
+
5113
+	/**
5114
+	 * Public wrapper for _deduce_fields_n_values_from_cols_n_values.
5115
+	 * Given an array where keys are column (or column alias) names and values,
5116
+	 * returns an array of their corresponding field names and database values
5117
+	 *
5118
+	 * @param array $cols_n_values
5119
+	 * @return array
5120
+	 */
5121
+	public function deduce_fields_n_values_from_cols_n_values($cols_n_values)
5122
+	{
5123
+		return $this->_deduce_fields_n_values_from_cols_n_values($cols_n_values);
5124
+	}
5125
+
5126
+
5127
+
5128
+	/**
5129
+	 * _deduce_fields_n_values_from_cols_n_values
5130
+	 * Given an array where keys are column (or column alias) names and values,
5131
+	 * returns an array of their corresponding field names and database values
5132
+	 *
5133
+	 * @param string $cols_n_values
5134
+	 * @return array
5135
+	 */
5136
+	protected function _deduce_fields_n_values_from_cols_n_values($cols_n_values)
5137
+	{
5138
+		$this_model_fields_n_values = array();
5139
+		foreach ($this->get_tables() as $table_alias => $table_obj) {
5140
+			$table_pk_value = $this->_get_column_value_with_table_alias_or_not($cols_n_values,
5141
+				$table_obj->get_fully_qualified_pk_column(), $table_obj->get_pk_column());
5142
+			//there is a primary key on this table and its not set. Use defaults for all its columns
5143
+			if ($table_pk_value === null && $table_obj->get_pk_column()) {
5144
+				foreach ($this->_get_fields_for_table($table_alias) as $field_name => $field_obj) {
5145
+					if (! $field_obj->is_db_only_field()) {
5146
+						//prepare field as if its coming from db
5147
+						$prepared_value = $field_obj->prepare_for_set($field_obj->get_default_value());
5148
+						$this_model_fields_n_values[$field_name] = $field_obj->prepare_for_use_in_db($prepared_value);
5149
+					}
5150
+				}
5151
+			} else {
5152
+				//the table's rows existed. Use their values
5153
+				foreach ($this->_get_fields_for_table($table_alias) as $field_name => $field_obj) {
5154
+					if (! $field_obj->is_db_only_field()) {
5155
+						$this_model_fields_n_values[$field_name] = $this->_get_column_value_with_table_alias_or_not(
5156
+							$cols_n_values, $field_obj->get_qualified_column(),
5157
+							$field_obj->get_table_column()
5158
+						);
5159
+					}
5160
+				}
5161
+			}
5162
+		}
5163
+		return $this_model_fields_n_values;
5164
+	}
5165
+
5166
+
5167
+
5168
+	/**
5169
+	 * @param $cols_n_values
5170
+	 * @param $qualified_column
5171
+	 * @param $regular_column
5172
+	 * @return null
5173
+	 */
5174
+	protected function _get_column_value_with_table_alias_or_not($cols_n_values, $qualified_column, $regular_column)
5175
+	{
5176
+		$value = null;
5177
+		//ask the field what it think it's table_name.column_name should be, and call it the "qualified column"
5178
+		//does the field on the model relate to this column retrieved from the db?
5179
+		//or is it a db-only field? (not relating to the model)
5180
+		if (isset($cols_n_values[$qualified_column])) {
5181
+			$value = $cols_n_values[$qualified_column];
5182
+		} elseif (isset($cols_n_values[$regular_column])) {
5183
+			$value = $cols_n_values[$regular_column];
5184
+		}
5185
+		return $value;
5186
+	}
5187
+
5188
+
5189
+
5190
+	/**
5191
+	 * refresh_entity_map_from_db
5192
+	 * Makes sure the model object in the entity map at $id assumes the values
5193
+	 * of the database (opposite of EE_base_Class::save())
5194
+	 *
5195
+	 * @param int|string $id
5196
+	 * @return EE_Base_Class
5197
+	 * @throws EE_Error
5198
+	 */
5199
+	public function refresh_entity_map_from_db($id)
5200
+	{
5201
+		$obj_in_map = $this->get_from_entity_map($id);
5202
+		if ($obj_in_map) {
5203
+			$wpdb_results = $this->_get_all_wpdb_results(
5204
+				array(array($this->get_primary_key_field()->get_name() => $id), 'limit' => 1)
5205
+			);
5206
+			if ($wpdb_results && is_array($wpdb_results)) {
5207
+				$one_row = reset($wpdb_results);
5208
+				foreach ($this->_deduce_fields_n_values_from_cols_n_values($one_row) as $field_name => $db_value) {
5209
+					$obj_in_map->set_from_db($field_name, $db_value);
5210
+				}
5211
+				//clear the cache of related model objects
5212
+				foreach ($this->relation_settings() as $relation_name => $relation_obj) {
5213
+					$obj_in_map->clear_cache($relation_name, null, true);
5214
+				}
5215
+			}
5216
+			$this->_entity_map[EEM_Base::$_model_query_blog_id][$id] = $obj_in_map;
5217
+			return $obj_in_map;
5218
+		}
5219
+		return $this->get_one_by_ID($id);
5220
+	}
5221
+
5222
+
5223
+
5224
+	/**
5225
+	 * refresh_entity_map_with
5226
+	 * Leaves the entry in the entity map alone, but updates it to match the provided
5227
+	 * $replacing_model_obj (which we assume to be its equivalent but somehow NOT in the entity map).
5228
+	 * This is useful if you have a model object you want to make authoritative over what's in the entity map currently.
5229
+	 * Note: The old $replacing_model_obj should now be destroyed as it's now un-authoritative
5230
+	 *
5231
+	 * @param int|string    $id
5232
+	 * @param EE_Base_Class $replacing_model_obj
5233
+	 * @return \EE_Base_Class
5234
+	 * @throws EE_Error
5235
+	 */
5236
+	public function refresh_entity_map_with($id, $replacing_model_obj)
5237
+	{
5238
+		$obj_in_map = $this->get_from_entity_map($id);
5239
+		if ($obj_in_map) {
5240
+			if ($replacing_model_obj instanceof EE_Base_Class) {
5241
+				foreach ($replacing_model_obj->model_field_array() as $field_name => $value) {
5242
+					$obj_in_map->set($field_name, $value);
5243
+				}
5244
+				//make the model object in the entity map's cache match the $replacing_model_obj
5245
+				foreach ($this->relation_settings() as $relation_name => $relation_obj) {
5246
+					$obj_in_map->clear_cache($relation_name, null, true);
5247
+					foreach ($replacing_model_obj->get_all_from_cache($relation_name) as $cache_id => $cached_obj) {
5248
+						$obj_in_map->cache($relation_name, $cached_obj, $cache_id);
5249
+					}
5250
+				}
5251
+			}
5252
+			return $obj_in_map;
5253
+		}
5254
+		$this->add_to_entity_map($replacing_model_obj);
5255
+		return $replacing_model_obj;
5256
+	}
5257
+
5258
+
5259
+
5260
+	/**
5261
+	 * Gets the EE class that corresponds to this model. Eg, for EEM_Answer that
5262
+	 * would be EE_Answer.To import that class, you'd just add ".class.php" to the name, like so
5263
+	 * require_once($this->_getClassName().".class.php");
5264
+	 *
5265
+	 * @return string
5266
+	 */
5267
+	private function _get_class_name()
5268
+	{
5269
+		return "EE_" . $this->get_this_model_name();
5270
+	}
5271
+
5272
+
5273
+
5274
+	/**
5275
+	 * Get the name of the items this model represents, for the quantity specified. Eg,
5276
+	 * if $quantity==1, on EEM_Event, it would 'Event' (internationalized), otherwise
5277
+	 * it would be 'Events'.
5278
+	 *
5279
+	 * @param int $quantity
5280
+	 * @return string
5281
+	 */
5282
+	public function item_name($quantity = 1)
5283
+	{
5284
+		return (int)$quantity === 1 ? $this->singular_item : $this->plural_item;
5285
+	}
5286
+
5287
+
5288
+
5289
+	/**
5290
+	 * Very handy general function to allow for plugins to extend any child of EE_TempBase.
5291
+	 * If a method is called on a child of EE_TempBase that doesn't exist, this function is called
5292
+	 * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
5293
+	 * requiring a plugin to extend the EE_TempBase (which works fine is there's only 1 plugin, but when will that
5294
+	 * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
5295
+	 * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
5296
+	 * was called, and an array of the original arguments passed to the function. Whatever their callback function
5297
+	 * returns will be returned by this function. Example: in functions.php (or in a plugin):
5298
+	 * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
5299
+	 * my_callback($previousReturnValue,EE_TempBase $object,$argsArray){
5300
+	 * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
5301
+	 *        return $previousReturnValue.$returnString;
5302
+	 * }
5303
+	 * require('EEM_Answer.model.php');
5304
+	 * $answer=EEM_Answer::instance();
5305
+	 * echo $answer->my_callback('monkeys',100);
5306
+	 * //will output "you called my_callback! and passed args:monkeys,100"
5307
+	 *
5308
+	 * @param string $methodName name of method which was called on a child of EE_TempBase, but which
5309
+	 * @param array  $args       array of original arguments passed to the function
5310
+	 * @throws EE_Error
5311
+	 * @return mixed whatever the plugin which calls add_filter decides
5312
+	 */
5313
+	public function __call($methodName, $args)
5314
+	{
5315
+		$className = get_class($this);
5316
+		$tagName = "FHEE__{$className}__{$methodName}";
5317
+		if (! has_filter($tagName)) {
5318
+			throw new EE_Error(
5319
+				sprintf(
5320
+					__('Method %1$s on model %2$s does not exist! You can create one with the following code in functions.php or in a plugin: %4$s function my_callback(%4$s \$previousReturnValue, EEM_Base \$object\ $argsArray=NULL ){%4$s     /*function body*/%4$s      return \$whatever;%4$s }%4$s add_filter( \'%3$s\', \'my_callback\', 10, 3 );',
5321
+						'event_espresso'),
5322
+					$methodName,
5323
+					$className,
5324
+					$tagName,
5325
+					'<br />'
5326
+				)
5327
+			);
5328
+		}
5329
+		return apply_filters($tagName, null, $this, $args);
5330
+	}
5331
+
5332
+
5333
+
5334
+	/**
5335
+	 * Ensures $base_class_obj_or_id is of the EE_Base_Class child that corresponds ot this model.
5336
+	 * If not, assumes its an ID, and uses $this->get_one_by_ID() to get the EE_Base_Class.
5337
+	 *
5338
+	 * @param EE_Base_Class|string|int $base_class_obj_or_id either:
5339
+	 *                                                       the EE_Base_Class object that corresponds to this Model,
5340
+	 *                                                       the object's class name
5341
+	 *                                                       or object's ID
5342
+	 * @param boolean                  $ensure_is_in_db      if set, we will also verify this model object
5343
+	 *                                                       exists in the database. If it does not, we add it
5344
+	 * @throws EE_Error
5345
+	 * @return EE_Base_Class
5346
+	 */
5347
+	public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false)
5348
+	{
5349
+		$className = $this->_get_class_name();
5350
+		if ($base_class_obj_or_id instanceof $className) {
5351
+			$model_object = $base_class_obj_or_id;
5352
+		} else {
5353
+			$primary_key_field = $this->get_primary_key_field();
5354
+			if (
5355
+				$primary_key_field instanceof EE_Primary_Key_Int_Field
5356
+				&& (
5357
+					is_int($base_class_obj_or_id)
5358
+					|| is_string($base_class_obj_or_id)
5359
+				)
5360
+			) {
5361
+				// assume it's an ID.
5362
+				// either a proper integer or a string representing an integer (eg "101" instead of 101)
5363
+				$model_object = $this->get_one_by_ID($base_class_obj_or_id);
5364
+			} else if (
5365
+				$primary_key_field instanceof EE_Primary_Key_String_Field
5366
+				&& is_string($base_class_obj_or_id)
5367
+			) {
5368
+				// assume its a string representation of the object
5369
+				$model_object = $this->get_one_by_ID($base_class_obj_or_id);
5370
+			} else {
5371
+				throw new EE_Error(
5372
+					sprintf(
5373
+						__(
5374
+							"'%s' is neither an object of type %s, nor an ID! Its full value is '%s'",
5375
+							'event_espresso'
5376
+						),
5377
+						$base_class_obj_or_id,
5378
+						$this->_get_class_name(),
5379
+						print_r($base_class_obj_or_id, true)
5380
+					)
5381
+				);
5382
+			}
5383
+		}
5384
+		if ($ensure_is_in_db && $model_object->ID() !== null) {
5385
+			$model_object->save();
5386
+		}
5387
+		return $model_object;
5388
+	}
5389
+
5390
+
5391
+
5392
+	/**
5393
+	 * Similar to ensure_is_obj(), this method makes sure $base_class_obj_or_id
5394
+	 * is a value of the this model's primary key. If it's an EE_Base_Class child,
5395
+	 * returns it ID.
5396
+	 *
5397
+	 * @param EE_Base_Class|int|string $base_class_obj_or_id
5398
+	 * @return int|string depending on the type of this model object's ID
5399
+	 * @throws EE_Error
5400
+	 */
5401
+	public function ensure_is_ID($base_class_obj_or_id)
5402
+	{
5403
+		$className = $this->_get_class_name();
5404
+		if ($base_class_obj_or_id instanceof $className) {
5405
+			/** @var $base_class_obj_or_id EE_Base_Class */
5406
+			$id = $base_class_obj_or_id->ID();
5407
+		} elseif (is_int($base_class_obj_or_id)) {
5408
+			//assume it's an ID
5409
+			$id = $base_class_obj_or_id;
5410
+		} elseif (is_string($base_class_obj_or_id)) {
5411
+			//assume its a string representation of the object
5412
+			$id = $base_class_obj_or_id;
5413
+		} else {
5414
+			throw new EE_Error(sprintf(__("'%s' is neither an object of type %s, nor an ID! Its full value is '%s'",
5415
+				'event_espresso'), $base_class_obj_or_id, $this->_get_class_name(),
5416
+				print_r($base_class_obj_or_id, true)));
5417
+		}
5418
+		return $id;
5419
+	}
5420
+
5421
+
5422
+
5423
+	/**
5424
+	 * Sets whether the values passed to the model (eg, values in WHERE, values in INSERT, UPDATE, etc)
5425
+	 * have already been ran through the appropriate model field's prepare_for_use_in_db method. IE, they have
5426
+	 * been sanitized and converted into the appropriate domain.
5427
+	 * Usually the only place you'll want to change the default (which is to assume values have NOT been sanitized by
5428
+	 * the model object/model field) is when making a method call from WITHIN a model object, which has direct access
5429
+	 * to its sanitized values. Note: after changing this setting, you should set it back to its previous value (using
5430
+	 * get_assumption_concerning_values_already_prepared_by_model_object()) eg.
5431
+	 * $EVT = EEM_Event::instance(); $old_setting =
5432
+	 * $EVT->get_assumption_concerning_values_already_prepared_by_model_object();
5433
+	 * $EVT->assume_values_already_prepared_by_model_object(true);
5434
+	 * $EVT->update(array('foo'=>'bar'),array(array('foo'=>'monkey')));
5435
+	 * $EVT->assume_values_already_prepared_by_model_object($old_setting);
5436
+	 *
5437
+	 * @param int $values_already_prepared like one of the constants on EEM_Base
5438
+	 * @return void
5439
+	 */
5440
+	public function assume_values_already_prepared_by_model_object(
5441
+		$values_already_prepared = self::not_prepared_by_model_object
5442
+	) {
5443
+		$this->_values_already_prepared_by_model_object = $values_already_prepared;
5444
+	}
5445
+
5446
+
5447
+
5448
+	/**
5449
+	 * Read comments for assume_values_already_prepared_by_model_object()
5450
+	 *
5451
+	 * @return int
5452
+	 */
5453
+	public function get_assumption_concerning_values_already_prepared_by_model_object()
5454
+	{
5455
+		return $this->_values_already_prepared_by_model_object;
5456
+	}
5457
+
5458
+
5459
+
5460
+	/**
5461
+	 * Gets all the indexes on this model
5462
+	 *
5463
+	 * @return EE_Index[]
5464
+	 */
5465
+	public function indexes()
5466
+	{
5467
+		return $this->_indexes;
5468
+	}
5469
+
5470
+
5471
+
5472
+	/**
5473
+	 * Gets all the Unique Indexes on this model
5474
+	 *
5475
+	 * @return EE_Unique_Index[]
5476
+	 */
5477
+	public function unique_indexes()
5478
+	{
5479
+		$unique_indexes = array();
5480
+		foreach ($this->_indexes as $name => $index) {
5481
+			if ($index instanceof EE_Unique_Index) {
5482
+				$unique_indexes [$name] = $index;
5483
+			}
5484
+		}
5485
+		return $unique_indexes;
5486
+	}
5487
+
5488
+
5489
+
5490
+	/**
5491
+	 * Gets all the fields which, when combined, make the primary key.
5492
+	 * This is usually just an array with 1 element (the primary key), but in cases
5493
+	 * where there is no primary key, it's a combination of fields as defined
5494
+	 * on a primary index
5495
+	 *
5496
+	 * @return EE_Model_Field_Base[] indexed by the field's name
5497
+	 * @throws EE_Error
5498
+	 */
5499
+	public function get_combined_primary_key_fields()
5500
+	{
5501
+		foreach ($this->indexes() as $index) {
5502
+			if ($index instanceof EE_Primary_Key_Index) {
5503
+				return $index->fields();
5504
+			}
5505
+		}
5506
+		return array($this->primary_key_name() => $this->get_primary_key_field());
5507
+	}
5508
+
5509
+
5510
+
5511
+	/**
5512
+	 * Used to build a primary key string (when the model has no primary key),
5513
+	 * which can be used a unique string to identify this model object.
5514
+	 *
5515
+	 * @param array $cols_n_values keys are field names, values are their values
5516
+	 * @return string
5517
+	 * @throws EE_Error
5518
+	 */
5519
+	public function get_index_primary_key_string($cols_n_values)
5520
+	{
5521
+		$cols_n_values_for_primary_key_index = array_intersect_key($cols_n_values,
5522
+			$this->get_combined_primary_key_fields());
5523
+		return http_build_query($cols_n_values_for_primary_key_index);
5524
+	}
5525
+
5526
+
5527
+
5528
+	/**
5529
+	 * Gets the field values from the primary key string
5530
+	 *
5531
+	 * @see EEM_Base::get_combined_primary_key_fields() and EEM_Base::get_index_primary_key_string()
5532
+	 * @param string $index_primary_key_string
5533
+	 * @return null|array
5534
+	 * @throws EE_Error
5535
+	 */
5536
+	public function parse_index_primary_key_string($index_primary_key_string)
5537
+	{
5538
+		$key_fields = $this->get_combined_primary_key_fields();
5539
+		//check all of them are in the $id
5540
+		$key_vals_in_combined_pk = array();
5541
+		parse_str($index_primary_key_string, $key_vals_in_combined_pk);
5542
+		foreach ($key_fields as $key_field_name => $field_obj) {
5543
+			if (! isset($key_vals_in_combined_pk[$key_field_name])) {
5544
+				return null;
5545
+			}
5546
+		}
5547
+		return $key_vals_in_combined_pk;
5548
+	}
5549
+
5550
+
5551
+
5552
+	/**
5553
+	 * verifies that an array of key-value pairs for model fields has a key
5554
+	 * for each field comprising the primary key index
5555
+	 *
5556
+	 * @param array $key_vals
5557
+	 * @return boolean
5558
+	 * @throws EE_Error
5559
+	 */
5560
+	public function has_all_combined_primary_key_fields($key_vals)
5561
+	{
5562
+		$keys_it_should_have = array_keys($this->get_combined_primary_key_fields());
5563
+		foreach ($keys_it_should_have as $key) {
5564
+			if (! isset($key_vals[$key])) {
5565
+				return false;
5566
+			}
5567
+		}
5568
+		return true;
5569
+	}
5570
+
5571
+
5572
+
5573
+	/**
5574
+	 * Finds all model objects in the DB that appear to be a copy of $model_object_or_attributes_array.
5575
+	 * We consider something to be a copy if all the attributes match (except the ID, of course).
5576
+	 *
5577
+	 * @param array|EE_Base_Class $model_object_or_attributes_array If its an array, it's field-value pairs
5578
+	 * @param array               $query_params                     like EEM_Base::get_all's query_params.
5579
+	 * @throws EE_Error
5580
+	 * @return \EE_Base_Class[] Array keys are object IDs (if there is a primary key on the model. if not, numerically
5581
+	 *                                                              indexed)
5582
+	 */
5583
+	public function get_all_copies($model_object_or_attributes_array, $query_params = array())
5584
+	{
5585
+		if ($model_object_or_attributes_array instanceof EE_Base_Class) {
5586
+			$attributes_array = $model_object_or_attributes_array->model_field_array();
5587
+		} elseif (is_array($model_object_or_attributes_array)) {
5588
+			$attributes_array = $model_object_or_attributes_array;
5589
+		} else {
5590
+			throw new EE_Error(sprintf(__("get_all_copies should be provided with either a model object or an array of field-value-pairs, but was given %s",
5591
+				"event_espresso"), $model_object_or_attributes_array));
5592
+		}
5593
+		//even copies obviously won't have the same ID, so remove the primary key
5594
+		//from the WHERE conditions for finding copies (if there is a primary key, of course)
5595
+		if ($this->has_primary_key_field() && isset($attributes_array[$this->primary_key_name()])) {
5596
+			unset($attributes_array[$this->primary_key_name()]);
5597
+		}
5598
+		if (isset($query_params[0])) {
5599
+			$query_params[0] = array_merge($attributes_array, $query_params);
5600
+		} else {
5601
+			$query_params[0] = $attributes_array;
5602
+		}
5603
+		return $this->get_all($query_params);
5604
+	}
5605
+
5606
+
5607
+
5608
+	/**
5609
+	 * Gets the first copy we find. See get_all_copies for more details
5610
+	 *
5611
+	 * @param       mixed EE_Base_Class | array        $model_object_or_attributes_array
5612
+	 * @param array $query_params
5613
+	 * @return EE_Base_Class
5614
+	 * @throws EE_Error
5615
+	 */
5616
+	public function get_one_copy($model_object_or_attributes_array, $query_params = array())
5617
+	{
5618
+		if (! is_array($query_params)) {
5619
+			EE_Error::doing_it_wrong('EEM_Base::get_one_copy',
5620
+				sprintf(__('$query_params should be an array, you passed a variable of type %s', 'event_espresso'),
5621
+					gettype($query_params)), '4.6.0');
5622
+			$query_params = array();
5623
+		}
5624
+		$query_params['limit'] = 1;
5625
+		$copies = $this->get_all_copies($model_object_or_attributes_array, $query_params);
5626
+		if (is_array($copies)) {
5627
+			return array_shift($copies);
5628
+		}
5629
+		return null;
5630
+	}
5631
+
5632
+
5633
+
5634
+	/**
5635
+	 * Updates the item with the specified id. Ignores default query parameters because
5636
+	 * we have specified the ID, and its assumed we KNOW what we're doing
5637
+	 *
5638
+	 * @param array      $fields_n_values keys are field names, values are their new values
5639
+	 * @param int|string $id              the value of the primary key to update
5640
+	 * @return int number of rows updated
5641
+	 * @throws EE_Error
5642
+	 */
5643
+	public function update_by_ID($fields_n_values, $id)
5644
+	{
5645
+		$query_params = array(
5646
+			0                          => array($this->get_primary_key_field()->get_name() => $id),
5647
+			'default_where_conditions' => EEM_Base::default_where_conditions_others_only,
5648
+		);
5649
+		return $this->update($fields_n_values, $query_params);
5650
+	}
5651
+
5652
+
5653
+
5654
+	/**
5655
+	 * Changes an operator which was supplied to the models into one usable in SQL
5656
+	 *
5657
+	 * @param string $operator_supplied
5658
+	 * @return string an operator which can be used in SQL
5659
+	 * @throws EE_Error
5660
+	 */
5661
+	private function _prepare_operator_for_sql($operator_supplied)
5662
+	{
5663
+		$sql_operator = isset($this->_valid_operators[$operator_supplied]) ? $this->_valid_operators[$operator_supplied]
5664
+			: null;
5665
+		if ($sql_operator) {
5666
+			return $sql_operator;
5667
+		}
5668
+		throw new EE_Error(
5669
+			sprintf(
5670
+				__(
5671
+					"The operator '%s' is not in the list of valid operators: %s",
5672
+					"event_espresso"
5673
+				), $operator_supplied, implode(",", array_keys($this->_valid_operators))
5674
+			)
5675
+		);
5676
+	}
5677
+
5678
+
5679
+
5680
+	/**
5681
+	 * Gets the valid operators
5682
+	 * @return array keys are accepted strings, values are the SQL they are converted to
5683
+	 */
5684
+	public function valid_operators(){
5685
+		return $this->_valid_operators;
5686
+	}
5687
+
5688
+
5689
+
5690
+	/**
5691
+	 * Gets the between-style operators (take 2 arguments).
5692
+	 * @return array keys are accepted strings, values are the SQL they are converted to
5693
+	 */
5694
+	public function valid_between_style_operators()
5695
+	{
5696
+		return array_intersect(
5697
+			$this->valid_operators(),
5698
+			$this->_between_style_operators
5699
+		);
5700
+	}
5701
+
5702
+	/**
5703
+	 * Gets the "like"-style operators (take a single argument, but it may contain wildcards)
5704
+	 * @return array keys are accepted strings, values are the SQL they are converted to
5705
+	 */
5706
+	public function valid_like_style_operators()
5707
+	{
5708
+		return array_intersect(
5709
+			$this->valid_operators(),
5710
+			$this->_like_style_operators
5711
+		);
5712
+	}
5713
+
5714
+	/**
5715
+	 * Gets the "in"-style operators
5716
+	 * @return array keys are accepted strings, values are the SQL they are converted to
5717
+	 */
5718
+	public function valid_in_style_operators()
5719
+	{
5720
+		return array_intersect(
5721
+			$this->valid_operators(),
5722
+			$this->_in_style_operators
5723
+		);
5724
+	}
5725
+
5726
+	/**
5727
+	 * Gets the "null"-style operators (accept no arguments)
5728
+	 * @return array keys are accepted strings, values are the SQL they are converted to
5729
+	 */
5730
+	public function valid_null_style_operators()
5731
+	{
5732
+		return array_intersect(
5733
+			$this->valid_operators(),
5734
+			$this->_null_style_operators
5735
+		);
5736
+	}
5737
+
5738
+	/**
5739
+	 * Gets an array where keys are the primary keys and values are their 'names'
5740
+	 * (as determined by the model object's name() function, which is often overridden)
5741
+	 *
5742
+	 * @param array $query_params like get_all's
5743
+	 * @return string[]
5744
+	 * @throws EE_Error
5745
+	 */
5746
+	public function get_all_names($query_params = array())
5747
+	{
5748
+		$objs = $this->get_all($query_params);
5749
+		$names = array();
5750
+		foreach ($objs as $obj) {
5751
+			$names[$obj->ID()] = $obj->name();
5752
+		}
5753
+		return $names;
5754
+	}
5755
+
5756
+
5757
+
5758
+	/**
5759
+	 * Gets an array of primary keys from the model objects. If you acquired the model objects
5760
+	 * using EEM_Base::get_all() you don't need to call this (and probably shouldn't because
5761
+	 * this is duplicated effort and reduces efficiency) you would be better to use
5762
+	 * array_keys() on $model_objects.
5763
+	 *
5764
+	 * @param \EE_Base_Class[] $model_objects
5765
+	 * @param boolean          $filter_out_empty_ids if a model object has an ID of '' or 0, don't bother including it
5766
+	 *                                               in the returned array
5767
+	 * @return array
5768
+	 * @throws EE_Error
5769
+	 */
5770
+	public function get_IDs($model_objects, $filter_out_empty_ids = false)
5771
+	{
5772
+		if (! $this->has_primary_key_field()) {
5773
+			if (WP_DEBUG) {
5774
+				EE_Error::add_error(
5775
+					__('Trying to get IDs from a model than has no primary key', 'event_espresso'),
5776
+					__FILE__,
5777
+					__FUNCTION__,
5778
+					__LINE__
5779
+				);
5780
+			}
5781
+		}
5782
+		$IDs = array();
5783
+		foreach ($model_objects as $model_object) {
5784
+			$id = $model_object->ID();
5785
+			if (! $id) {
5786
+				if ($filter_out_empty_ids) {
5787
+					continue;
5788
+				}
5789
+				if (WP_DEBUG) {
5790
+					EE_Error::add_error(
5791
+						__(
5792
+							'Called %1$s on a model object that has no ID and so probably hasn\'t been saved to the database',
5793
+							'event_espresso'
5794
+						),
5795
+						__FILE__,
5796
+						__FUNCTION__,
5797
+						__LINE__
5798
+					);
5799
+				}
5800
+			}
5801
+			$IDs[] = $id;
5802
+		}
5803
+		return $IDs;
5804
+	}
5805
+
5806
+
5807
+
5808
+	/**
5809
+	 * Returns the string used in capabilities relating to this model. If there
5810
+	 * are no capabilities that relate to this model returns false
5811
+	 *
5812
+	 * @return string|false
5813
+	 */
5814
+	public function cap_slug()
5815
+	{
5816
+		return apply_filters('FHEE__EEM_Base__cap_slug', $this->_caps_slug, $this);
5817
+	}
5818
+
5819
+
5820
+
5821
+	/**
5822
+	 * Returns the capability-restrictions array (@see EEM_Base::_cap_restrictions).
5823
+	 * If $context is provided (which should be set to one of EEM_Base::valid_cap_contexts())
5824
+	 * only returns the cap restrictions array in that context (ie, the array
5825
+	 * at that key)
5826
+	 *
5827
+	 * @param string $context
5828
+	 * @return EE_Default_Where_Conditions[] indexed by associated capability
5829
+	 * @throws EE_Error
5830
+	 */
5831
+	public function cap_restrictions($context = EEM_Base::caps_read)
5832
+	{
5833
+		EEM_Base::verify_is_valid_cap_context($context);
5834
+		//check if we ought to run the restriction generator first
5835
+		if (
5836
+			isset($this->_cap_restriction_generators[$context])
5837
+			&& $this->_cap_restriction_generators[$context] instanceof EE_Restriction_Generator_Base
5838
+			&& ! $this->_cap_restriction_generators[$context]->has_generated_cap_restrictions()
5839
+		) {
5840
+			$this->_cap_restrictions[$context] = array_merge(
5841
+				$this->_cap_restrictions[$context],
5842
+				$this->_cap_restriction_generators[$context]->generate_restrictions()
5843
+			);
5844
+		}
5845
+		//and make sure we've finalized the construction of each restriction
5846
+		foreach ($this->_cap_restrictions[$context] as $where_conditions_obj) {
5847
+			if ($where_conditions_obj instanceof EE_Default_Where_Conditions) {
5848
+				$where_conditions_obj->_finalize_construct($this);
5849
+			}
5850
+		}
5851
+		return $this->_cap_restrictions[$context];
5852
+	}
5853
+
5854
+
5855
+
5856
+	/**
5857
+	 * Indicating whether or not this model thinks its a wp core model
5858
+	 *
5859
+	 * @return boolean
5860
+	 */
5861
+	public function is_wp_core_model()
5862
+	{
5863
+		return $this->_wp_core_model;
5864
+	}
5865
+
5866
+
5867
+
5868
+	/**
5869
+	 * Gets all the caps that are missing which impose a restriction on
5870
+	 * queries made in this context
5871
+	 *
5872
+	 * @param string $context one of EEM_Base::caps_ constants
5873
+	 * @return EE_Default_Where_Conditions[] indexed by capability name
5874
+	 * @throws EE_Error
5875
+	 */
5876
+	public function caps_missing($context = EEM_Base::caps_read)
5877
+	{
5878
+		$missing_caps = array();
5879
+		$cap_restrictions = $this->cap_restrictions($context);
5880
+		foreach ($cap_restrictions as $cap => $restriction_if_no_cap) {
5881
+			if (! EE_Capabilities::instance()
5882
+								 ->current_user_can($cap, $this->get_this_model_name() . '_model_applying_caps')
5883
+			) {
5884
+				$missing_caps[$cap] = $restriction_if_no_cap;
5885
+			}
5886
+		}
5887
+		return $missing_caps;
5888
+	}
5889
+
5890
+
5891
+
5892
+	/**
5893
+	 * Gets the mapping from capability contexts to action strings used in capability names
5894
+	 *
5895
+	 * @return array keys are one of EEM_Base::valid_cap_contexts(), and values are usually
5896
+	 * one of 'read', 'edit', or 'delete'
5897
+	 */
5898
+	public function cap_contexts_to_cap_action_map()
5899
+	{
5900
+		return apply_filters('FHEE__EEM_Base__cap_contexts_to_cap_action_map', $this->_cap_contexts_to_cap_action_map,
5901
+			$this);
5902
+	}
5903
+
5904
+
5905
+
5906
+	/**
5907
+	 * Gets the action string for the specified capability context
5908
+	 *
5909
+	 * @param string $context
5910
+	 * @return string one of EEM_Base::cap_contexts_to_cap_action_map() values
5911
+	 * @throws EE_Error
5912
+	 */
5913
+	public function cap_action_for_context($context)
5914
+	{
5915
+		$mapping = $this->cap_contexts_to_cap_action_map();
5916
+		if (isset($mapping[$context])) {
5917
+			return $mapping[$context];
5918
+		}
5919
+		if ($action = apply_filters('FHEE__EEM_Base__cap_action_for_context', null, $this, $mapping, $context)) {
5920
+			return $action;
5921
+		}
5922
+		throw new EE_Error(
5923
+			sprintf(
5924
+				__('Cannot find capability restrictions for context "%1$s", allowed values are:%2$s', 'event_espresso'),
5925
+				$context,
5926
+				implode(',', array_keys($this->cap_contexts_to_cap_action_map()))
5927
+			)
5928
+		);
5929
+	}
5930
+
5931
+
5932
+
5933
+	/**
5934
+	 * Returns all the capability contexts which are valid when querying models
5935
+	 *
5936
+	 * @return array
5937
+	 */
5938
+	public static function valid_cap_contexts()
5939
+	{
5940
+		return apply_filters('FHEE__EEM_Base__valid_cap_contexts', array(
5941
+			self::caps_read,
5942
+			self::caps_read_admin,
5943
+			self::caps_edit,
5944
+			self::caps_delete,
5945
+		));
5946
+	}
5947
+
5948
+
5949
+
5950
+	/**
5951
+	 * Returns all valid options for 'default_where_conditions'
5952
+	 *
5953
+	 * @return array
5954
+	 */
5955
+	public static function valid_default_where_conditions()
5956
+	{
5957
+		return array(
5958
+			EEM_Base::default_where_conditions_all,
5959
+			EEM_Base::default_where_conditions_this_only,
5960
+			EEM_Base::default_where_conditions_others_only,
5961
+			EEM_Base::default_where_conditions_minimum_all,
5962
+			EEM_Base::default_where_conditions_minimum_others,
5963
+			EEM_Base::default_where_conditions_none
5964
+		);
5965
+	}
5966
+
5967
+	// public static function default_where_conditions_full
5968
+	/**
5969
+	 * Verifies $context is one of EEM_Base::valid_cap_contexts(), if not it throws an exception
5970
+	 *
5971
+	 * @param string $context
5972
+	 * @return bool
5973
+	 * @throws EE_Error
5974
+	 */
5975
+	static public function verify_is_valid_cap_context($context)
5976
+	{
5977
+		$valid_cap_contexts = EEM_Base::valid_cap_contexts();
5978
+		if (in_array($context, $valid_cap_contexts)) {
5979
+			return true;
5980
+		}
5981
+		throw new EE_Error(
5982
+			sprintf(
5983
+				__(
5984
+					'Context "%1$s" passed into model "%2$s" is not a valid context. They are: %3$s',
5985
+					'event_espresso'
5986
+				),
5987
+				$context,
5988
+				'EEM_Base',
5989
+				implode(',', $valid_cap_contexts)
5990
+			)
5991
+		);
5992
+	}
5993
+
5994
+
5995
+
5996
+	/**
5997
+	 * Clears all the models field caches. This is only useful when a sub-class
5998
+	 * might have added a field or something and these caches might be invalidated
5999
+	 */
6000
+	protected function _invalidate_field_caches()
6001
+	{
6002
+		$this->_cache_foreign_key_to_fields = array();
6003
+		$this->_cached_fields = null;
6004
+		$this->_cached_fields_non_db_only = null;
6005
+	}
6006
+
6007
+
6008
+
6009
+	/**
6010
+	 * Gets the list of all the where query param keys that relate to logic instead of field names
6011
+	 * (eg "and", "or", "not").
6012
+	 *
6013
+	 * @return array
6014
+	 */
6015
+	public function logic_query_param_keys()
6016
+	{
6017
+		return $this->_logic_query_param_keys;
6018
+	}
6019
+
6020
+
6021
+
6022
+	/**
6023
+	 * Determines whether or not the where query param array key is for a logic query param.
6024
+	 * Eg 'OR', 'not*', and 'and*because-i-say-so' should all return true, whereas
6025
+	 * 'ATT_fname', 'EVT_name*not-you-or-me', and 'ORG_name' should return false
6026
+	 *
6027
+	 * @param $query_param_key
6028
+	 * @return bool
6029
+	 */
6030
+	public function is_logic_query_param_key($query_param_key)
6031
+	{
6032
+		foreach ($this->logic_query_param_keys() as $logic_query_param_key) {
6033
+			if ($query_param_key === $logic_query_param_key
6034
+				|| strpos($query_param_key, $logic_query_param_key . '*') === 0
6035
+			) {
6036
+				return true;
6037
+			}
6038
+		}
6039
+		return false;
6040
+	}
6041 6041
 
6042 6042
 
6043 6043
 
Please login to merge, or discard this patch.
admin_pages/registrations/Registrations_Admin_Page.core.php 1 patch
Indentation   +3532 added lines, -3532 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 
5 5
 
@@ -23,2218 +23,2218 @@  discard block
 block discarded – undo
23 23
 class Registrations_Admin_Page extends EE_Admin_Page_CPT
24 24
 {
25 25
 
26
-    /**
27
-     * @var EE_Registration
28
-     */
29
-    private $_registration;
30
-
31
-    /**
32
-     * @var EE_Event
33
-     */
34
-    private $_reg_event;
35
-
36
-    /**
37
-     * @var EE_Session
38
-     */
39
-    private $_session;
40
-
41
-    private static $_reg_status;
42
-
43
-    /**
44
-     * Form for displaying the custom questions for this registration.
45
-     * This gets used a few times throughout the request so its best to cache it
46
-     *
47
-     * @var EE_Registration_Custom_Questions_Form
48
-     */
49
-    protected $_reg_custom_questions_form = null;
50
-
51
-
52
-    /**
53
-     *        constructor
54
-     *
55
-     * @Constructor
56
-     * @access public
57
-     * @param bool $routing
58
-     * @return Registrations_Admin_Page
59
-     */
60
-    public function __construct($routing = true)
61
-    {
62
-        parent::__construct($routing);
63
-        add_action('wp_loaded', array($this, 'wp_loaded'));
64
-    }
65
-
66
-
67
-    public function wp_loaded()
68
-    {
69
-        // when adding a new registration...
70
-        if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'new_registration') {
71
-            EE_System::do_not_cache();
72
-            if (! isset($this->_req_data['processing_registration'])
73
-                 || absint($this->_req_data['processing_registration']) !== 1
74
-            ) {
75
-                // and it's NOT the attendee information reg step
76
-                // force cookie expiration by setting time to last week
77
-                setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
78
-                // and update the global
79
-                $_COOKIE['ee_registration_added'] = 0;
80
-            }
81
-        }
82
-    }
83
-
84
-
85
-    protected function _init_page_props()
86
-    {
87
-        $this->page_slug        = REG_PG_SLUG;
88
-        $this->_admin_base_url  = REG_ADMIN_URL;
89
-        $this->_admin_base_path = REG_ADMIN;
90
-        $this->page_label       = esc_html__('Registrations', 'event_espresso');
91
-        $this->_cpt_routes      = array(
92
-            'add_new_attendee' => 'espresso_attendees',
93
-            'edit_attendee'    => 'espresso_attendees',
94
-            'insert_attendee'  => 'espresso_attendees',
95
-            'update_attendee'  => 'espresso_attendees',
96
-        );
97
-        $this->_cpt_model_names = array(
98
-            'add_new_attendee' => 'EEM_Attendee',
99
-            'edit_attendee'    => 'EEM_Attendee',
100
-        );
101
-        $this->_cpt_edit_routes = array(
102
-            'espresso_attendees' => 'edit_attendee',
103
-        );
104
-        $this->_pagenow_map     = array(
105
-            'add_new_attendee' => 'post-new.php',
106
-            'edit_attendee'    => 'post.php',
107
-            'trash'            => 'post.php',
108
-        );
109
-        add_action('edit_form_after_title', array($this, 'after_title_form_fields'), 10);
110
-        //add filters so that the comment urls don't take users to a confusing 404 page
111
-        add_filter('get_comment_link', array($this, 'clear_comment_link'), 10, 3);
112
-    }
113
-
114
-
115
-    public function clear_comment_link($link, $comment, $args)
116
-    {
117
-        //gotta make sure this only happens on this route
118
-        $post_type = get_post_type($comment->comment_post_ID);
119
-        if ($post_type === 'espresso_attendees') {
120
-            return '#commentsdiv';
121
-        }
122
-        return $link;
123
-    }
124
-
125
-
126
-    protected function _ajax_hooks()
127
-    {
128
-        //todo: all hooks for registrations ajax goes in here
129
-        add_action('wp_ajax_toggle_checkin_status', array($this, 'toggle_checkin_status'));
130
-    }
131
-
132
-
133
-    protected function _define_page_props()
134
-    {
135
-        $this->_admin_page_title = $this->page_label;
136
-        $this->_labels           = array(
137
-            'buttons'                      => array(
138
-                'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
139
-                'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
140
-                'edit'                => esc_html__('Edit Contact', 'event_espresso'),
141
-                'report'              => esc_html__("Event Registrations CSV Report", "event_espresso"),
142
-                'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
143
-                'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
144
-                'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
145
-                'contact_list_export' => esc_html__("Export Data", "event_espresso"),
146
-            ),
147
-            'publishbox'                   => array(
148
-                'add_new_attendee' => esc_html__("Add Contact Record", 'event_espresso'),
149
-                'edit_attendee'    => esc_html__("Update Contact Record", 'event_espresso'),
150
-            ),
151
-            'hide_add_button_on_cpt_route' => array(
152
-                'edit_attendee' => true,
153
-            ),
154
-        );
155
-    }
156
-
157
-
158
-    /**
159
-     *        grab url requests and route them
160
-     *
161
-     * @access private
162
-     * @return void
163
-     */
164
-    public function _set_page_routes()
165
-    {
166
-        $this->_get_registration_status_array();
167
-        $reg_id             = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
168
-            ? $this->_req_data['_REG_ID'] : 0;
169
-        $reg_id = empty($reg_id) && ! empty($this->_req_data['reg_status_change_form']['REG_ID'])
170
-            ? $this->_req_data['reg_status_change_form']['REG_ID']
171
-            : $reg_id;
172
-        $att_id             = ! empty($this->_req_data['ATT_ID']) && ! is_array($this->_req_data['ATT_ID'])
173
-            ? $this->_req_data['ATT_ID'] : 0;
174
-        $att_id             = ! empty($this->_req_data['post']) && ! is_array($this->_req_data['post'])
175
-            ? $this->_req_data['post']
176
-            : $att_id;
177
-        $this->_page_routes = array(
178
-            'default'                            => array(
179
-                'func'       => '_registrations_overview_list_table',
180
-                'capability' => 'ee_read_registrations',
181
-            ),
182
-            'view_registration'                  => array(
183
-                'func'       => '_registration_details',
184
-                'capability' => 'ee_read_registration',
185
-                'obj_id'     => $reg_id,
186
-            ),
187
-            'edit_registration'                  => array(
188
-                'func'               => '_update_attendee_registration_form',
189
-                'noheader'           => true,
190
-                'headers_sent_route' => 'view_registration',
191
-                'capability'         => 'ee_edit_registration',
192
-                'obj_id'             => $reg_id,
193
-                '_REG_ID'            => $reg_id,
194
-            ),
195
-            'trash_registrations'                => array(
196
-                'func'       => '_trash_or_restore_registrations',
197
-                'args'       => array('trash' => true),
198
-                'noheader'   => true,
199
-                'capability' => 'ee_delete_registrations',
200
-            ),
201
-            'restore_registrations'              => array(
202
-                'func'       => '_trash_or_restore_registrations',
203
-                'args'       => array('trash' => false),
204
-                'noheader'   => true,
205
-                'capability' => 'ee_delete_registrations',
206
-            ),
207
-            'delete_registrations'               => array(
208
-                'func'       => '_delete_registrations',
209
-                'noheader'   => true,
210
-                'capability' => 'ee_delete_registrations',
211
-            ),
212
-            'new_registration'                   => array(
213
-                'func'       => 'new_registration',
214
-                'capability' => 'ee_edit_registrations',
215
-            ),
216
-            'process_reg_step'                   => array(
217
-                'func'       => 'process_reg_step',
218
-                'noheader'   => true,
219
-                'capability' => 'ee_edit_registrations',
220
-            ),
221
-            'redirect_to_txn'                    => array(
222
-                'func'       => 'redirect_to_txn',
223
-                'noheader'   => true,
224
-                'capability' => 'ee_edit_registrations',
225
-            ),
226
-            'change_reg_status'                  => array(
227
-                'func'       => '_change_reg_status',
228
-                'noheader'   => true,
229
-                'capability' => 'ee_edit_registration',
230
-                'obj_id'     => $reg_id,
231
-            ),
232
-            'approve_registration'               => array(
233
-                'func'       => 'approve_registration',
234
-                'noheader'   => true,
235
-                'capability' => 'ee_edit_registration',
236
-                'obj_id'     => $reg_id,
237
-            ),
238
-            'approve_and_notify_registration'    => array(
239
-                'func'       => 'approve_registration',
240
-                'noheader'   => true,
241
-                'args'       => array(true),
242
-                'capability' => 'ee_edit_registration',
243
-                'obj_id'     => $reg_id,
244
-            ),
245
-            'approve_registrations'               => array(
246
-                'func'       => 'bulk_action_on_registrations',
247
-                'noheader'   => true,
248
-                'capability' => 'ee_edit_registrations',
249
-                'args' => array('approve')
250
-            ),
251
-            'approve_and_notify_registrations'               => array(
252
-                'func'       => 'bulk_action_on_registrations',
253
-                'noheader'   => true,
254
-                'capability' => 'ee_edit_registrations',
255
-                'args' => array('approve', true)
256
-            ),
257
-            'decline_registration'               => array(
258
-                'func'       => 'decline_registration',
259
-                'noheader'   => true,
260
-                'capability' => 'ee_edit_registration',
261
-                'obj_id'     => $reg_id,
262
-            ),
263
-            'decline_and_notify_registration'    => array(
264
-                'func'       => 'decline_registration',
265
-                'noheader'   => true,
266
-                'args'       => array(true),
267
-                'capability' => 'ee_edit_registration',
268
-                'obj_id'     => $reg_id,
269
-            ),
270
-            'decline_registrations'               => array(
271
-                'func'       => 'bulk_action_on_registrations',
272
-                'noheader'   => true,
273
-                'capability' => 'ee_edit_registrations',
274
-                'args' => array('decline')
275
-            ),
276
-            'decline_and_notify_registrations'    => array(
277
-                'func'       => 'bulk_action_on_registrations',
278
-                'noheader'   => true,
279
-                'capability' => 'ee_edit_registrations',
280
-                'args' => array('decline', true)
281
-            ),
282
-            'pending_registration'               => array(
283
-                'func'       => 'pending_registration',
284
-                'noheader'   => true,
285
-                'capability' => 'ee_edit_registration',
286
-                'obj_id'     => $reg_id,
287
-            ),
288
-            'pending_and_notify_registration'    => array(
289
-                'func'       => 'pending_registration',
290
-                'noheader'   => true,
291
-                'args'       => array(true),
292
-                'capability' => 'ee_edit_registration',
293
-                'obj_id'     => $reg_id,
294
-            ),
295
-            'pending_registrations'               => array(
296
-                'func'       => 'bulk_action_on_registrations',
297
-                'noheader'   => true,
298
-                'capability' => 'ee_edit_registrations',
299
-                'args' => array('pending')
300
-            ),
301
-            'pending_and_notify_registrations'    => array(
302
-                'func'       => 'bulk_action_on_registrations',
303
-                'noheader'   => true,
304
-                'capability' => 'ee_edit_registrations',
305
-                'args' => array('pending', true)
306
-            ),
307
-            'no_approve_registration'            => array(
308
-                'func'       => 'not_approve_registration',
309
-                'noheader'   => true,
310
-                'capability' => 'ee_edit_registration',
311
-                'obj_id'     => $reg_id,
312
-            ),
313
-            'no_approve_and_notify_registration' => array(
314
-                'func'       => 'not_approve_registration',
315
-                'noheader'   => true,
316
-                'args'       => array(true),
317
-                'capability' => 'ee_edit_registration',
318
-                'obj_id'     => $reg_id,
319
-            ),
320
-            'no_approve_registrations'            => array(
321
-                'func'       => 'bulk_action_on_registrations',
322
-                'noheader'   => true,
323
-                'capability' => 'ee_edit_registrations',
324
-                'args' => array('not_approve')
325
-            ),
326
-            'no_approve_and_notify_registrations' => array(
327
-                'func'       => 'bulk_action_on_registrations',
328
-                'noheader'   => true,
329
-                'capability' => 'ee_edit_registrations',
330
-                'args' => array('not_approve', true)
331
-            ),
332
-            'cancel_registration'                => array(
333
-                'func'       => 'cancel_registration',
334
-                'noheader'   => true,
335
-                'capability' => 'ee_edit_registration',
336
-                'obj_id'     => $reg_id,
337
-            ),
338
-            'cancel_and_notify_registration'     => array(
339
-                'func'       => 'cancel_registration',
340
-                'noheader'   => true,
341
-                'args'       => array(true),
342
-                'capability' => 'ee_edit_registration',
343
-                'obj_id'     => $reg_id,
344
-            ),
345
-            'cancel_registrations'                => array(
346
-                'func'       => 'bulk_action_on_registrations',
347
-                'noheader'   => true,
348
-                'capability' => 'ee_edit_registrations',
349
-                'args' => array('cancel')
350
-            ),
351
-            'cancel_and_notify_registrations'     => array(
352
-                'func'       => 'bulk_action_on_registrations',
353
-                'noheader'   => true,
354
-                'capability' => 'ee_edit_registrations',
355
-                'args' => array('cancel', true)
356
-            ),
357
-            'wait_list_registration' => array(
358
-                'func'       => 'wait_list_registration',
359
-                'noheader'   => true,
360
-                'capability' => 'ee_edit_registration',
361
-                'obj_id'     => $reg_id,
362
-            ),
363
-            'contact_list'                       => array(
364
-                'func'       => '_attendee_contact_list_table',
365
-                'capability' => 'ee_read_contacts',
366
-            ),
367
-            'add_new_attendee'                   => array(
368
-                'func' => '_create_new_cpt_item',
369
-                'args' => array(
370
-                    'new_attendee' => true,
371
-                    'capability'   => 'ee_edit_contacts',
372
-                ),
373
-            ),
374
-            'edit_attendee'                      => array(
375
-                'func'       => '_edit_cpt_item',
376
-                'capability' => 'ee_edit_contacts',
377
-                'obj_id'     => $att_id,
378
-            ),
379
-            'duplicate_attendee'                 => array(
380
-                'func'       => '_duplicate_attendee',
381
-                'noheader'   => true,
382
-                'capability' => 'ee_edit_contacts',
383
-                'obj_id'     => $att_id,
384
-            ),
385
-            'insert_attendee'                    => array(
386
-                'func'       => '_insert_or_update_attendee',
387
-                'args'       => array(
388
-                    'new_attendee' => true,
389
-                ),
390
-                'noheader'   => true,
391
-                'capability' => 'ee_edit_contacts',
392
-            ),
393
-            'update_attendee'                    => array(
394
-                'func'       => '_insert_or_update_attendee',
395
-                'args'       => array(
396
-                    'new_attendee' => false,
397
-                ),
398
-                'noheader'   => true,
399
-                'capability' => 'ee_edit_contacts',
400
-                'obj_id'     => $att_id,
401
-            ),
402
-            'trash_attendees' => array(
403
-                'func' => '_trash_or_restore_attendees',
404
-                'args' => array(
405
-                    'trash' => 'true'
406
-                ),
407
-                'noheader' => true,
408
-                'capability' => 'ee_delete_contacts'
409
-            ),
410
-            'trash_attendee'                    => array(
411
-                'func'       => '_trash_or_restore_attendees',
412
-                'args'       => array(
413
-                    'trash' => true,
414
-                ),
415
-                'noheader'   => true,
416
-                'capability' => 'ee_delete_contacts',
417
-                'obj_id'     => $att_id,
418
-            ),
419
-            'restore_attendees'                  => array(
420
-                'func'       => '_trash_or_restore_attendees',
421
-                'args'       => array(
422
-                    'trash' => false,
423
-                ),
424
-                'noheader'   => true,
425
-                'capability' => 'ee_delete_contacts',
426
-                'obj_id'     => $att_id,
427
-            ),
428
-            'resend_registration'                => array(
429
-                'func'       => '_resend_registration',
430
-                'noheader'   => true,
431
-                'capability' => 'ee_send_message',
432
-            ),
433
-            'registrations_report'               => array(
434
-                'func'       => '_registrations_report',
435
-                'noheader'   => true,
436
-                'capability' => 'ee_read_registrations',
437
-            ),
438
-            'contact_list_export'                => array(
439
-                'func'       => '_contact_list_export',
440
-                'noheader'   => true,
441
-                'capability' => 'export',
442
-            ),
443
-            'contact_list_report'                => array(
444
-                'func'       => '_contact_list_report',
445
-                'noheader'   => true,
446
-                'capability' => 'ee_read_contacts',
447
-            ),
448
-        );
449
-    }
450
-
451
-
452
-    protected function _set_page_config()
453
-    {
454
-        $this->_page_config = array(
455
-            'default'           => array(
456
-                'nav'           => array(
457
-                    'label' => esc_html__('Overview', 'event_espresso'),
458
-                    'order' => 5,
459
-                ),
460
-                'help_tabs'     => array(
461
-                    'registrations_overview_help_tab'                       => array(
462
-                        'title'    => esc_html__('Registrations Overview', 'event_espresso'),
463
-                        'filename' => 'registrations_overview',
464
-                    ),
465
-                    'registrations_overview_table_column_headings_help_tab' => array(
466
-                        'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
467
-                        'filename' => 'registrations_overview_table_column_headings',
468
-                    ),
469
-                    'registrations_overview_filters_help_tab'               => array(
470
-                        'title'    => esc_html__('Registration Filters', 'event_espresso'),
471
-                        'filename' => 'registrations_overview_filters',
472
-                    ),
473
-                    'registrations_overview_views_help_tab'                 => array(
474
-                        'title'    => esc_html__('Registration Views', 'event_espresso'),
475
-                        'filename' => 'registrations_overview_views',
476
-                    ),
477
-                    'registrations_regoverview_other_help_tab'              => array(
478
-                        'title'    => esc_html__('Registrations Other', 'event_espresso'),
479
-                        'filename' => 'registrations_overview_other',
480
-                    ),
481
-                ),
482
-                'help_tour'     => array('Registration_Overview_Help_Tour'),
483
-                'qtips'         => array('Registration_List_Table_Tips'),
484
-                'list_table'    => 'EE_Registrations_List_Table',
485
-                'require_nonce' => false,
486
-            ),
487
-            'view_registration' => array(
488
-                'nav'           => array(
489
-                    'label'      => esc_html__('REG Details', 'event_espresso'),
490
-                    'order'      => 15,
491
-                    'url'        => isset($this->_req_data['_REG_ID'])
492
-                        ? add_query_arg(array('_REG_ID' => $this->_req_data['_REG_ID']), $this->_current_page_view_url)
493
-                        : $this->_admin_base_url,
494
-                    'persistent' => false,
495
-                ),
496
-                'help_tabs'     => array(
497
-                    'registrations_details_help_tab'                    => array(
498
-                        'title'    => esc_html__('Registration Details', 'event_espresso'),
499
-                        'filename' => 'registrations_details',
500
-                    ),
501
-                    'registrations_details_table_help_tab'              => array(
502
-                        'title'    => esc_html__('Registration Details Table', 'event_espresso'),
503
-                        'filename' => 'registrations_details_table',
504
-                    ),
505
-                    'registrations_details_form_answers_help_tab'       => array(
506
-                        'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
507
-                        'filename' => 'registrations_details_form_answers',
508
-                    ),
509
-                    'registrations_details_registrant_details_help_tab' => array(
510
-                        'title'    => esc_html__('Contact Details', 'event_espresso'),
511
-                        'filename' => 'registrations_details_registrant_details',
512
-                    ),
513
-                ),
514
-                'help_tour'     => array('Registration_Details_Help_Tour'),
515
-                'metaboxes'     => array_merge(
516
-                    $this->_default_espresso_metaboxes,
517
-                    array('_registration_details_metaboxes')
518
-                ),
519
-                'require_nonce' => false,
520
-            ),
521
-            'new_registration'  => array(
522
-                'nav'           => array(
523
-                    'label'      => esc_html__('Add New Registration', 'event_espresso'),
524
-                    'url'        => '#',
525
-                    'order'      => 15,
526
-                    'persistent' => false,
527
-                ),
528
-                'metaboxes'     => $this->_default_espresso_metaboxes,
529
-                'labels'        => array(
530
-                    'publishbox' => esc_html__('Save Registration', 'event_espresso'),
531
-                ),
532
-                'require_nonce' => false,
533
-            ),
534
-            'add_new_attendee'  => array(
535
-                'nav'           => array(
536
-                    'label'      => esc_html__('Add Contact', 'event_espresso'),
537
-                    'order'      => 15,
538
-                    'persistent' => false,
539
-                ),
540
-                'metaboxes'     => array_merge(
541
-                    $this->_default_espresso_metaboxes,
542
-                    array('_publish_post_box', 'attendee_editor_metaboxes')
543
-                ),
544
-                'require_nonce' => false,
545
-            ),
546
-            'edit_attendee'     => array(
547
-                'nav'           => array(
548
-                    'label'      => esc_html__('Edit Contact', 'event_espresso'),
549
-                    'order'      => 15,
550
-                    'persistent' => false,
551
-                    'url'        => isset($this->_req_data['ATT_ID'])
552
-                        ? add_query_arg(array('ATT_ID' => $this->_req_data['ATT_ID']), $this->_current_page_view_url)
553
-                        : $this->_admin_base_url,
554
-                ),
555
-                'metaboxes'     => array('attendee_editor_metaboxes'),
556
-                'require_nonce' => false,
557
-            ),
558
-            'contact_list'      => array(
559
-                'nav'           => array(
560
-                    'label' => esc_html__('Contact List', 'event_espresso'),
561
-                    'order' => 20,
562
-                ),
563
-                'list_table'    => 'EE_Attendee_Contact_List_Table',
564
-                'help_tabs'     => array(
565
-                    'registrations_contact_list_help_tab'                       => array(
566
-                        'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
567
-                        'filename' => 'registrations_contact_list',
568
-                    ),
569
-                    'registrations_contact-list_table_column_headings_help_tab' => array(
570
-                        'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
571
-                        'filename' => 'registrations_contact_list_table_column_headings',
572
-                    ),
573
-                    'registrations_contact_list_views_help_tab'                 => array(
574
-                        'title'    => esc_html__('Contact List Views', 'event_espresso'),
575
-                        'filename' => 'registrations_contact_list_views',
576
-                    ),
577
-                    'registrations_contact_list_other_help_tab'                 => array(
578
-                        'title'    => esc_html__('Contact List Other', 'event_espresso'),
579
-                        'filename' => 'registrations_contact_list_other',
580
-                    ),
581
-                ),
582
-                'help_tour'     => array('Contact_List_Help_Tour'),
583
-                'metaboxes'     => array(),
584
-                'require_nonce' => false,
585
-            ),
586
-            //override default cpt routes
587
-            'create_new'        => '',
588
-            'edit'              => '',
589
-        );
590
-    }
591
-
592
-
593
-    /**
594
-     * The below methods aren't used by this class currently
595
-     */
596
-    protected function _add_screen_options()
597
-    {
598
-    }
599
-
600
-
601
-    protected function _add_feature_pointers()
602
-    {
603
-    }
604
-
605
-
606
-    public function admin_init()
607
-    {
608
-        EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
609
-            'click "Update Registration Questions" to save your changes',
610
-            'event_espresso'
611
-        );
612
-    }
613
-
614
-
615
-    public function admin_notices()
616
-    {
617
-    }
618
-
619
-
620
-    public function admin_footer_scripts()
621
-    {
622
-    }
623
-
624
-
625
-    /**
626
-     *        get list of registration statuses
627
-     *
628
-     * @access private
629
-     * @return void
630
-     */
631
-    private function _get_registration_status_array()
632
-    {
633
-        self::$_reg_status = EEM_Registration::reg_status_array(array(), true);
634
-    }
635
-
636
-
637
-    protected function _add_screen_options_default()
638
-    {
639
-        $this->_per_page_screen_option();
640
-    }
641
-
642
-
643
-    protected function _add_screen_options_contact_list()
644
-    {
645
-        $page_title              = $this->_admin_page_title;
646
-        $this->_admin_page_title = esc_html__("Contacts", 'event_espresso');
647
-        $this->_per_page_screen_option();
648
-        $this->_admin_page_title = $page_title;
649
-    }
650
-
651
-
652
-    public function load_scripts_styles()
653
-    {
654
-        //style
655
-        wp_register_style(
656
-            'espresso_reg',
657
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
658
-            array('ee-admin-css'),
659
-            EVENT_ESPRESSO_VERSION
660
-        );
661
-        wp_enqueue_style('espresso_reg');
662
-        //script
663
-        wp_register_script(
664
-            'espresso_reg',
665
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
666
-            array('jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'),
667
-            EVENT_ESPRESSO_VERSION,
668
-            true
669
-        );
670
-        wp_enqueue_script('espresso_reg');
671
-    }
672
-
673
-
674
-    public function load_scripts_styles_edit_attendee()
675
-    {
676
-        //stuff to only show up on our attendee edit details page.
677
-        $attendee_details_translations = array(
678
-            'att_publish_text' => sprintf(
679
-                esc_html__('Created on: <b>%1$s</b>', 'event_espresso'),
680
-                $this->_cpt_model_obj->get_datetime('ATT_created')
681
-            ),
682
-        );
683
-        wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
684
-        wp_enqueue_script('jquery-validate');
685
-    }
686
-
687
-
688
-    public function load_scripts_styles_view_registration()
689
-    {
690
-        //styles
691
-        wp_enqueue_style('espresso-ui-theme');
692
-        //scripts
693
-        $this->_get_reg_custom_questions_form($this->_registration->ID());
694
-        $this->_reg_custom_questions_form->wp_enqueue_scripts(true);
695
-    }
696
-
697
-
698
-    public function load_scripts_styles_contact_list()
699
-    {
700
-        wp_deregister_style('espresso_reg');
701
-        wp_register_style(
702
-            'espresso_att',
703
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
704
-            array('ee-admin-css'),
705
-            EVENT_ESPRESSO_VERSION
706
-        );
707
-        wp_enqueue_style('espresso_att');
708
-    }
709
-
710
-
711
-    public function load_scripts_styles_new_registration()
712
-    {
713
-        wp_register_script(
714
-            'ee-spco-for-admin',
715
-            REG_ASSETS_URL . 'spco_for_admin.js',
716
-            array('underscore', 'jquery'),
717
-            EVENT_ESPRESSO_VERSION,
718
-            true
719
-        );
720
-        wp_enqueue_script('ee-spco-for-admin');
721
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
722
-        EE_Form_Section_Proper::wp_enqueue_scripts();
723
-        EED_Ticket_Selector::load_tckt_slctr_assets();
724
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
725
-    }
726
-
727
-
728
-    public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
729
-    {
730
-        add_filter('FHEE_load_EE_messages', '__return_true');
731
-    }
732
-
733
-
734
-    public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
735
-    {
736
-        add_filter('FHEE_load_EE_messages', '__return_true');
737
-    }
738
-
739
-
740
-    protected function _set_list_table_views_default()
741
-    {
742
-        //for notification related bulk actions we need to make sure only active messengers have an option.
743
-        EED_Messages::set_autoloaders();
744
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
745
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
746
-        $active_mts               = $message_resource_manager->list_of_active_message_types();
747
-        //key= bulk_action_slug, value= message type.
748
-        $match_array = array(
749
-            'approve_registrations'    => 'registration',
750
-            'decline_registrations'    => 'declined_registration',
751
-            'pending_registrations'    => 'pending_approval',
752
-            'no_approve_registrations' => 'not_approved_registration',
753
-            'cancel_registrations'     => 'cancelled_registration',
754
-        );
755
-        $can_send = EE_Registry::instance()->CAP->current_user_can(
756
-            'ee_send_message',
757
-            'batch_send_messages'
758
-        );
759
-        /** setup reg status bulk actions **/
760
-        $def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
761
-        if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
762
-                $def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
763
-                    'Approve and Notify Registrations',
764
-                    'event_espresso'
765
-                );
766
-        }
767
-        $def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
768
-        if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
769
-                $def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
770
-                    'Decline and Notify Registrations',
771
-                    'event_espresso'
772
-                );
773
-        }
774
-        $def_reg_status_actions['pending_registrations'] = esc_html__(
775
-            'Set Registrations to Pending Payment',
776
-            'event_espresso'
777
-        );
778
-        if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
779
-                $def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
780
-                    'Set Registrations to Pending Payment and Notify',
781
-                    'event_espresso'
782
-                );
783
-        }
784
-        $def_reg_status_actions['no_approve_registrations'] = esc_html__(
785
-            'Set Registrations to Not Approved',
786
-            'event_espresso'
787
-        );
788
-        if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
789
-                $def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
790
-                    'Set Registrations to Not Approved and Notify',
791
-                    'event_espresso'
792
-                );
793
-        }
794
-        $def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
795
-        if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
796
-                $def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
797
-                    'Cancel Registrations and Notify',
798
-                    'event_espresso'
799
-                );
800
-        }
801
-        $def_reg_status_actions = apply_filters(
802
-            'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
803
-            $def_reg_status_actions,
804
-            $active_mts
805
-        );
806
-
807
-        $this->_views = array(
808
-            'all'   => array(
809
-                'slug'        => 'all',
810
-                'label'       => esc_html__('View All Registrations', 'event_espresso'),
811
-                'count'       => 0,
812
-                'bulk_action' => array_merge($def_reg_status_actions, array(
813
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
814
-                )),
815
-            ),
816
-            'month' => array(
817
-                'slug'        => 'month',
818
-                'label'       => esc_html__('This Month', 'event_espresso'),
819
-                'count'       => 0,
820
-                'bulk_action' => array_merge($def_reg_status_actions, array(
821
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
822
-                )),
823
-            ),
824
-            'today' => array(
825
-                'slug'        => 'today',
826
-                'label'       => sprintf(
827
-                    esc_html__('Today - %s', 'event_espresso'),
828
-                    date('M d, Y', current_time('timestamp'))
829
-                ),
830
-                'count'       => 0,
831
-                'bulk_action' => array_merge($def_reg_status_actions, array(
832
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
833
-                )),
834
-            ),
835
-        );
836
-        if (EE_Registry::instance()->CAP->current_user_can(
837
-            'ee_delete_registrations',
838
-            'espresso_registrations_delete_registration'
839
-        )) {
840
-            $this->_views['incomplete'] = array(
841
-                'slug'        => 'incomplete',
842
-                'label'       => esc_html__('Incomplete', 'event_espresso'),
843
-                'count'       => 0,
844
-                'bulk_action' => array(
845
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
846
-                ),
847
-            );
848
-            $this->_views['trash']      = array(
849
-                'slug'        => 'trash',
850
-                'label'       => esc_html__('Trash', 'event_espresso'),
851
-                'count'       => 0,
852
-                'bulk_action' => array(
853
-                    'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
854
-                    'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
855
-                ),
856
-            );
857
-        }
858
-    }
859
-
860
-
861
-    protected function _set_list_table_views_contact_list()
862
-    {
863
-        $this->_views = array(
864
-            'in_use' => array(
865
-                'slug'        => 'in_use',
866
-                'label'       => esc_html__('In Use', 'event_espresso'),
867
-                'count'       => 0,
868
-                'bulk_action' => array(
869
-                    'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
870
-                ),
871
-            ),
872
-        );
873
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_contacts',
874
-            'espresso_registrations_trash_attendees')
875
-        ) {
876
-            $this->_views['trash'] = array(
877
-                'slug'        => 'trash',
878
-                'label'       => esc_html__('Trash', 'event_espresso'),
879
-                'count'       => 0,
880
-                'bulk_action' => array(
881
-                    'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
882
-                ),
883
-            );
884
-        }
885
-    }
886
-
887
-
888
-    protected function _registration_legend_items()
889
-    {
890
-        $fc_items = array(
891
-            'star-icon'        => array(
892
-                'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
893
-                'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
894
-            ),
895
-            'view_details'     => array(
896
-                'class' => 'dashicons dashicons-clipboard',
897
-                'desc'  => esc_html__('View Registration Details', 'event_espresso'),
898
-            ),
899
-            'edit_attendee'    => array(
900
-                'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
901
-                'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
902
-            ),
903
-            'view_transaction' => array(
904
-                'class' => 'dashicons dashicons-cart',
905
-                'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
906
-            ),
907
-            'view_invoice'     => array(
908
-                'class' => 'dashicons dashicons-media-spreadsheet',
909
-                'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
910
-            ),
911
-        );
912
-        if (EE_Registry::instance()->CAP->current_user_can(
913
-            'ee_send_message',
914
-            'espresso_registrations_resend_registration'
915
-        )) {
916
-            $fc_items['resend_registration'] = array(
917
-                'class' => 'dashicons dashicons-email-alt',
918
-                'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
919
-            );
920
-        } else {
921
-            $fc_items['blank'] = array('class' => 'blank', 'desc' => '');
922
-        }
923
-        if (EE_Registry::instance()->CAP->current_user_can(
924
-            'ee_read_global_messages',
925
-            'view_filtered_messages'
926
-        )) {
927
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
928
-            if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
929
-                $fc_items['view_related_messages'] = array(
930
-                    'class' => $related_for_icon['css_class'],
931
-                    'desc'  => $related_for_icon['label'],
932
-                );
933
-            }
934
-        }
935
-        $sc_items = array(
936
-            'approved_status'   => array(
937
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
938
-                'desc'  => EEH_Template::pretty_status(
939
-                    EEM_Registration::status_id_approved,
940
-                    false,
941
-                    'sentence'
942
-                ),
943
-            ),
944
-            'pending_status'    => array(
945
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
946
-                'desc'  => EEH_Template::pretty_status(
947
-                    EEM_Registration::status_id_pending_payment,
948
-                    false,
949
-                    'sentence'
950
-                ),
951
-            ),
952
-            'wait_list'         => array(
953
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
954
-                'desc'  => EEH_Template::pretty_status(
955
-                    EEM_Registration::status_id_wait_list,
956
-                    false,
957
-                    'sentence'
958
-                ),
959
-            ),
960
-            'incomplete_status' => array(
961
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
962
-                'desc'  => EEH_Template::pretty_status(
963
-                    EEM_Registration::status_id_incomplete,
964
-                    false,
965
-                    'sentence'
966
-                ),
967
-            ),
968
-            'not_approved'      => array(
969
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
970
-                'desc'  => EEH_Template::pretty_status(
971
-                    EEM_Registration::status_id_not_approved,
972
-                    false,
973
-                    'sentence'
974
-                ),
975
-            ),
976
-            'declined_status'   => array(
977
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
978
-                'desc'  => EEH_Template::pretty_status(
979
-                    EEM_Registration::status_id_declined,
980
-                    false,
981
-                    'sentence'
982
-                ),
983
-            ),
984
-            'cancelled_status'  => array(
985
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
986
-                'desc'  => EEH_Template::pretty_status(
987
-                    EEM_Registration::status_id_cancelled,
988
-                    false,
989
-                    'sentence'
990
-                ),
991
-            ),
992
-        );
993
-        return array_merge($fc_items, $sc_items);
994
-    }
995
-
996
-
997
-
998
-    /***************************************        REGISTRATION OVERVIEW        **************************************/
999
-    /**
1000
-     * @throws \EE_Error
1001
-     */
1002
-    protected function _registrations_overview_list_table()
1003
-    {
1004
-        $this->_template_args['admin_page_header'] = '';
1005
-        $EVT_ID                                    = ! empty($this->_req_data['event_id'])
1006
-            ? absint($this->_req_data['event_id'])
1007
-            : 0;
1008
-        if ($EVT_ID) {
1009
-            if (EE_Registry::instance()->CAP->current_user_can(
1010
-                'ee_edit_registrations',
1011
-                'espresso_registrations_new_registration',
1012
-                $EVT_ID
1013
-            )) {
1014
-                $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1015
-                    'new_registration',
1016
-                    'add-registrant',
1017
-                    array('event_id' => $EVT_ID),
1018
-                    'add-new-h2'
1019
-                );
1020
-            }
1021
-            $event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
1022
-            if ($event instanceof EE_Event) {
1023
-                $this->_template_args['admin_page_header'] = sprintf(
1024
-                    esc_html__(
1025
-                        '%s Viewing registrations for the event: %s%s',
1026
-                        'event_espresso'
1027
-                    ),
1028
-                    '<h3 style="line-height:1.5em;">',
1029
-                    '<br /><a href="'
1030
-                        . EE_Admin_Page::add_query_args_and_nonce(
1031
-                            array(
1032
-                                'action' => 'edit',
1033
-                                'post'   => $event->ID(),
1034
-                            ),
1035
-                            EVENTS_ADMIN_URL
1036
-                        )
1037
-                        . '">&nbsp;'
1038
-                        . $event->get('EVT_name')
1039
-                        . '&nbsp;</a>&nbsp;',
1040
-                    '</h3>'
1041
-                );
1042
-            }
1043
-            $DTT_ID   = ! empty($this->_req_data['datetime_id']) ? absint($this->_req_data['datetime_id']) : 0;
1044
-            $datetime = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
1045
-            if ($datetime instanceof EE_Datetime && $this->_template_args['admin_page_header'] !== '') {
1046
-                $this->_template_args['admin_page_header'] = substr(
1047
-                    $this->_template_args['admin_page_header'],
1048
-                    0,
1049
-                    -5
1050
-                );
1051
-                $this->_template_args['admin_page_header'] .= ' &nbsp;<span class="drk-grey-text">';
1052
-                $this->_template_args['admin_page_header'] .= '<span class="dashicons dashicons-calendar"></span>';
1053
-                $this->_template_args['admin_page_header'] .= $datetime->name();
1054
-                $this->_template_args['admin_page_header'] .= ' ( ' . $datetime->start_date() . ' )';
1055
-                $this->_template_args['admin_page_header'] .= '</span></h3>';
1056
-            }
1057
-        }
1058
-        $this->_template_args['after_list_table'] = $this->_display_legend($this->_registration_legend_items());
1059
-        $this->display_admin_list_table_page_with_no_sidebar();
1060
-    }
1061
-
1062
-
1063
-    /**
1064
-     * This sets the _registration property for the registration details screen
1065
-     *
1066
-     * @access private
1067
-     * @return bool
1068
-     */
1069
-    private function _set_registration_object()
1070
-    {
1071
-        //get out if we've already set the object
1072
-        if (is_object($this->_registration)) {
1073
-            return true;
1074
-        }
1075
-        $REG    = EEM_Registration::instance();
1076
-        $REG_ID = ( ! empty($this->_req_data['_REG_ID'])) ? absint($this->_req_data['_REG_ID']) : false;
1077
-        if ($this->_registration = $REG->get_one_by_ID($REG_ID)) {
1078
-            return true;
1079
-        } else {
1080
-            $error_msg = sprintf(
1081
-                esc_html__(
1082
-                    'An error occurred and the details for Registration ID #%s could not be retrieved.',
1083
-                    'event_espresso'
1084
-                ),
1085
-                $REG_ID
1086
-            );
1087
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1088
-            $this->_registration = null;
1089
-            return false;
1090
-        }
1091
-    }
1092
-
1093
-
1094
-    /**
1095
-     * Used to retrieve registrations for the list table.
1096
-     *
1097
-     * @param int  $per_page
1098
-     * @param bool $count
1099
-     * @param bool $this_month
1100
-     * @param bool $today
1101
-     * @return EE_Registration[]|int
1102
-     * @throws EE_Error
1103
-     */
1104
-    public function get_registrations(
1105
-        $per_page = 10,
1106
-        $count = false,
1107
-        $this_month = false,
1108
-        $today = false
1109
-    ) {
1110
-        if ($this_month) {
1111
-            $this->_req_data['status'] = 'month';
1112
-        }
1113
-        if ($today) {
1114
-            $this->_req_data['status'] = 'today';
1115
-        }
1116
-        $query_params = $this->_get_registration_query_parameters($this->_req_data, $per_page, $count);
1117
-        /**
1118
-         * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1119
-         * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1120
-         * @see EEM_Base::get_all()
1121
-         */
1122
-        $query_params['group_by'] = '';
1123
-
1124
-        return $count
1125
-            ? EEM_Registration::instance()->count($query_params)
1126
-            /** @type EE_Registration[] */
1127
-            : EEM_Registration::instance()->get_all($query_params);
1128
-    }
1129
-
1130
-
1131
-
1132
-    /**
1133
-     * Retrieves the query parameters to be used by the Registration model for getting registrations.
1134
-     * Note: this listens to values on the request for some of the query parameters.
1135
-     *
1136
-     * @param array $request
1137
-     * @param int    $per_page
1138
-     * @param bool   $count
1139
-     * @return array
1140
-     */
1141
-    protected function _get_registration_query_parameters(
1142
-        $request = array(),
1143
-        $per_page = 10,
1144
-        $count = false
1145
-    ) {
1146
-
1147
-        $query_params = array(
1148
-            0                          => $this->_get_where_conditions_for_registrations_query(
1149
-                $request
1150
-            ),
1151
-            'caps'                     => EEM_Registration::caps_read_admin,
1152
-            'default_where_conditions' => 'this_model_only',
1153
-        );
1154
-        if (! $count) {
1155
-            $query_params = array_merge(
1156
-                $query_params,
1157
-                $this->_get_orderby_for_registrations_query(),
1158
-                $this->_get_limit($per_page)
1159
-            );
1160
-        }
1161
-
1162
-        return $query_params;
1163
-    }
1164
-
1165
-
1166
-    /**
1167
-     * This will add EVT_ID to the provided $where array for EE model query parameters.
1168
-     *
1169
-     * @param array $request usually the same as $this->_req_data but not necessarily
1170
-     * @return array
1171
-     */
1172
-    protected function _add_event_id_to_where_conditions(array $request)
1173
-    {
1174
-        $where = array();
1175
-        if (! empty($request['event_id'])) {
1176
-            $where['EVT_ID'] = absint($request['event_id']);
1177
-        }
1178
-        return $where;
1179
-    }
1180
-
1181
-
1182
-    /**
1183
-     * Adds category ID if it exists in the request to the where conditions for the registrations query.
1184
-     *
1185
-     * @param array $request usually the same as $this->_req_data but not necessarily
1186
-     * @return array
1187
-     */
1188
-    protected function _add_category_id_to_where_conditions(array $request)
1189
-    {
1190
-        $where = array();
1191
-        if (! empty($request['EVT_CAT']) && (int)$request['EVT_CAT'] !== -1) {
1192
-            $where['Event.Term_Taxonomy.term_id'] = absint($request['EVT_CAT']);
1193
-        }
1194
-        return $where;
1195
-    }
1196
-
1197
-
1198
-    /**
1199
-     * Adds the datetime ID if it exists in the request to the where conditions for the registrations query.
1200
-     *
1201
-     * @param array $request usually the same as $this->_req_data but not necessarily
1202
-     * @return array
1203
-     */
1204
-    protected function _add_datetime_id_to_where_conditions(array $request)
1205
-    {
1206
-        $where = array();
1207
-        if (! empty($request['datetime_id'])) {
1208
-            $where['Ticket.Datetime.DTT_ID'] = absint($request['datetime_id']);
1209
-        }
1210
-        if (! empty($request['DTT_ID'])) {
1211
-            $where['Ticket.Datetime.DTT_ID'] = absint($request['DTT_ID']);
1212
-        }
1213
-        return $where;
1214
-    }
1215
-
1216
-
1217
-    /**
1218
-     * Adds the correct registration status to the where conditions for the registrations query.
1219
-     *
1220
-     * @param array $request usually the same as $this->_req_data but not necessarily
1221
-     * @return array
1222
-     */
1223
-    protected function _add_registration_status_to_where_conditions(array $request)
1224
-    {
1225
-        $where = array();
1226
-        $view = EEH_Array::is_set($request, 'status', '');
1227
-        $registration_status = ! empty($request['_reg_status'])
1228
-            ? sanitize_text_field($request['_reg_status'])
1229
-            : '';
1230
-
1231
-        /*
26
+	/**
27
+	 * @var EE_Registration
28
+	 */
29
+	private $_registration;
30
+
31
+	/**
32
+	 * @var EE_Event
33
+	 */
34
+	private $_reg_event;
35
+
36
+	/**
37
+	 * @var EE_Session
38
+	 */
39
+	private $_session;
40
+
41
+	private static $_reg_status;
42
+
43
+	/**
44
+	 * Form for displaying the custom questions for this registration.
45
+	 * This gets used a few times throughout the request so its best to cache it
46
+	 *
47
+	 * @var EE_Registration_Custom_Questions_Form
48
+	 */
49
+	protected $_reg_custom_questions_form = null;
50
+
51
+
52
+	/**
53
+	 *        constructor
54
+	 *
55
+	 * @Constructor
56
+	 * @access public
57
+	 * @param bool $routing
58
+	 * @return Registrations_Admin_Page
59
+	 */
60
+	public function __construct($routing = true)
61
+	{
62
+		parent::__construct($routing);
63
+		add_action('wp_loaded', array($this, 'wp_loaded'));
64
+	}
65
+
66
+
67
+	public function wp_loaded()
68
+	{
69
+		// when adding a new registration...
70
+		if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'new_registration') {
71
+			EE_System::do_not_cache();
72
+			if (! isset($this->_req_data['processing_registration'])
73
+				 || absint($this->_req_data['processing_registration']) !== 1
74
+			) {
75
+				// and it's NOT the attendee information reg step
76
+				// force cookie expiration by setting time to last week
77
+				setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
78
+				// and update the global
79
+				$_COOKIE['ee_registration_added'] = 0;
80
+			}
81
+		}
82
+	}
83
+
84
+
85
+	protected function _init_page_props()
86
+	{
87
+		$this->page_slug        = REG_PG_SLUG;
88
+		$this->_admin_base_url  = REG_ADMIN_URL;
89
+		$this->_admin_base_path = REG_ADMIN;
90
+		$this->page_label       = esc_html__('Registrations', 'event_espresso');
91
+		$this->_cpt_routes      = array(
92
+			'add_new_attendee' => 'espresso_attendees',
93
+			'edit_attendee'    => 'espresso_attendees',
94
+			'insert_attendee'  => 'espresso_attendees',
95
+			'update_attendee'  => 'espresso_attendees',
96
+		);
97
+		$this->_cpt_model_names = array(
98
+			'add_new_attendee' => 'EEM_Attendee',
99
+			'edit_attendee'    => 'EEM_Attendee',
100
+		);
101
+		$this->_cpt_edit_routes = array(
102
+			'espresso_attendees' => 'edit_attendee',
103
+		);
104
+		$this->_pagenow_map     = array(
105
+			'add_new_attendee' => 'post-new.php',
106
+			'edit_attendee'    => 'post.php',
107
+			'trash'            => 'post.php',
108
+		);
109
+		add_action('edit_form_after_title', array($this, 'after_title_form_fields'), 10);
110
+		//add filters so that the comment urls don't take users to a confusing 404 page
111
+		add_filter('get_comment_link', array($this, 'clear_comment_link'), 10, 3);
112
+	}
113
+
114
+
115
+	public function clear_comment_link($link, $comment, $args)
116
+	{
117
+		//gotta make sure this only happens on this route
118
+		$post_type = get_post_type($comment->comment_post_ID);
119
+		if ($post_type === 'espresso_attendees') {
120
+			return '#commentsdiv';
121
+		}
122
+		return $link;
123
+	}
124
+
125
+
126
+	protected function _ajax_hooks()
127
+	{
128
+		//todo: all hooks for registrations ajax goes in here
129
+		add_action('wp_ajax_toggle_checkin_status', array($this, 'toggle_checkin_status'));
130
+	}
131
+
132
+
133
+	protected function _define_page_props()
134
+	{
135
+		$this->_admin_page_title = $this->page_label;
136
+		$this->_labels           = array(
137
+			'buttons'                      => array(
138
+				'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
139
+				'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
140
+				'edit'                => esc_html__('Edit Contact', 'event_espresso'),
141
+				'report'              => esc_html__("Event Registrations CSV Report", "event_espresso"),
142
+				'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
143
+				'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
144
+				'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
145
+				'contact_list_export' => esc_html__("Export Data", "event_espresso"),
146
+			),
147
+			'publishbox'                   => array(
148
+				'add_new_attendee' => esc_html__("Add Contact Record", 'event_espresso'),
149
+				'edit_attendee'    => esc_html__("Update Contact Record", 'event_espresso'),
150
+			),
151
+			'hide_add_button_on_cpt_route' => array(
152
+				'edit_attendee' => true,
153
+			),
154
+		);
155
+	}
156
+
157
+
158
+	/**
159
+	 *        grab url requests and route them
160
+	 *
161
+	 * @access private
162
+	 * @return void
163
+	 */
164
+	public function _set_page_routes()
165
+	{
166
+		$this->_get_registration_status_array();
167
+		$reg_id             = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
168
+			? $this->_req_data['_REG_ID'] : 0;
169
+		$reg_id = empty($reg_id) && ! empty($this->_req_data['reg_status_change_form']['REG_ID'])
170
+			? $this->_req_data['reg_status_change_form']['REG_ID']
171
+			: $reg_id;
172
+		$att_id             = ! empty($this->_req_data['ATT_ID']) && ! is_array($this->_req_data['ATT_ID'])
173
+			? $this->_req_data['ATT_ID'] : 0;
174
+		$att_id             = ! empty($this->_req_data['post']) && ! is_array($this->_req_data['post'])
175
+			? $this->_req_data['post']
176
+			: $att_id;
177
+		$this->_page_routes = array(
178
+			'default'                            => array(
179
+				'func'       => '_registrations_overview_list_table',
180
+				'capability' => 'ee_read_registrations',
181
+			),
182
+			'view_registration'                  => array(
183
+				'func'       => '_registration_details',
184
+				'capability' => 'ee_read_registration',
185
+				'obj_id'     => $reg_id,
186
+			),
187
+			'edit_registration'                  => array(
188
+				'func'               => '_update_attendee_registration_form',
189
+				'noheader'           => true,
190
+				'headers_sent_route' => 'view_registration',
191
+				'capability'         => 'ee_edit_registration',
192
+				'obj_id'             => $reg_id,
193
+				'_REG_ID'            => $reg_id,
194
+			),
195
+			'trash_registrations'                => array(
196
+				'func'       => '_trash_or_restore_registrations',
197
+				'args'       => array('trash' => true),
198
+				'noheader'   => true,
199
+				'capability' => 'ee_delete_registrations',
200
+			),
201
+			'restore_registrations'              => array(
202
+				'func'       => '_trash_or_restore_registrations',
203
+				'args'       => array('trash' => false),
204
+				'noheader'   => true,
205
+				'capability' => 'ee_delete_registrations',
206
+			),
207
+			'delete_registrations'               => array(
208
+				'func'       => '_delete_registrations',
209
+				'noheader'   => true,
210
+				'capability' => 'ee_delete_registrations',
211
+			),
212
+			'new_registration'                   => array(
213
+				'func'       => 'new_registration',
214
+				'capability' => 'ee_edit_registrations',
215
+			),
216
+			'process_reg_step'                   => array(
217
+				'func'       => 'process_reg_step',
218
+				'noheader'   => true,
219
+				'capability' => 'ee_edit_registrations',
220
+			),
221
+			'redirect_to_txn'                    => array(
222
+				'func'       => 'redirect_to_txn',
223
+				'noheader'   => true,
224
+				'capability' => 'ee_edit_registrations',
225
+			),
226
+			'change_reg_status'                  => array(
227
+				'func'       => '_change_reg_status',
228
+				'noheader'   => true,
229
+				'capability' => 'ee_edit_registration',
230
+				'obj_id'     => $reg_id,
231
+			),
232
+			'approve_registration'               => array(
233
+				'func'       => 'approve_registration',
234
+				'noheader'   => true,
235
+				'capability' => 'ee_edit_registration',
236
+				'obj_id'     => $reg_id,
237
+			),
238
+			'approve_and_notify_registration'    => array(
239
+				'func'       => 'approve_registration',
240
+				'noheader'   => true,
241
+				'args'       => array(true),
242
+				'capability' => 'ee_edit_registration',
243
+				'obj_id'     => $reg_id,
244
+			),
245
+			'approve_registrations'               => array(
246
+				'func'       => 'bulk_action_on_registrations',
247
+				'noheader'   => true,
248
+				'capability' => 'ee_edit_registrations',
249
+				'args' => array('approve')
250
+			),
251
+			'approve_and_notify_registrations'               => array(
252
+				'func'       => 'bulk_action_on_registrations',
253
+				'noheader'   => true,
254
+				'capability' => 'ee_edit_registrations',
255
+				'args' => array('approve', true)
256
+			),
257
+			'decline_registration'               => array(
258
+				'func'       => 'decline_registration',
259
+				'noheader'   => true,
260
+				'capability' => 'ee_edit_registration',
261
+				'obj_id'     => $reg_id,
262
+			),
263
+			'decline_and_notify_registration'    => array(
264
+				'func'       => 'decline_registration',
265
+				'noheader'   => true,
266
+				'args'       => array(true),
267
+				'capability' => 'ee_edit_registration',
268
+				'obj_id'     => $reg_id,
269
+			),
270
+			'decline_registrations'               => array(
271
+				'func'       => 'bulk_action_on_registrations',
272
+				'noheader'   => true,
273
+				'capability' => 'ee_edit_registrations',
274
+				'args' => array('decline')
275
+			),
276
+			'decline_and_notify_registrations'    => array(
277
+				'func'       => 'bulk_action_on_registrations',
278
+				'noheader'   => true,
279
+				'capability' => 'ee_edit_registrations',
280
+				'args' => array('decline', true)
281
+			),
282
+			'pending_registration'               => array(
283
+				'func'       => 'pending_registration',
284
+				'noheader'   => true,
285
+				'capability' => 'ee_edit_registration',
286
+				'obj_id'     => $reg_id,
287
+			),
288
+			'pending_and_notify_registration'    => array(
289
+				'func'       => 'pending_registration',
290
+				'noheader'   => true,
291
+				'args'       => array(true),
292
+				'capability' => 'ee_edit_registration',
293
+				'obj_id'     => $reg_id,
294
+			),
295
+			'pending_registrations'               => array(
296
+				'func'       => 'bulk_action_on_registrations',
297
+				'noheader'   => true,
298
+				'capability' => 'ee_edit_registrations',
299
+				'args' => array('pending')
300
+			),
301
+			'pending_and_notify_registrations'    => array(
302
+				'func'       => 'bulk_action_on_registrations',
303
+				'noheader'   => true,
304
+				'capability' => 'ee_edit_registrations',
305
+				'args' => array('pending', true)
306
+			),
307
+			'no_approve_registration'            => array(
308
+				'func'       => 'not_approve_registration',
309
+				'noheader'   => true,
310
+				'capability' => 'ee_edit_registration',
311
+				'obj_id'     => $reg_id,
312
+			),
313
+			'no_approve_and_notify_registration' => array(
314
+				'func'       => 'not_approve_registration',
315
+				'noheader'   => true,
316
+				'args'       => array(true),
317
+				'capability' => 'ee_edit_registration',
318
+				'obj_id'     => $reg_id,
319
+			),
320
+			'no_approve_registrations'            => array(
321
+				'func'       => 'bulk_action_on_registrations',
322
+				'noheader'   => true,
323
+				'capability' => 'ee_edit_registrations',
324
+				'args' => array('not_approve')
325
+			),
326
+			'no_approve_and_notify_registrations' => array(
327
+				'func'       => 'bulk_action_on_registrations',
328
+				'noheader'   => true,
329
+				'capability' => 'ee_edit_registrations',
330
+				'args' => array('not_approve', true)
331
+			),
332
+			'cancel_registration'                => array(
333
+				'func'       => 'cancel_registration',
334
+				'noheader'   => true,
335
+				'capability' => 'ee_edit_registration',
336
+				'obj_id'     => $reg_id,
337
+			),
338
+			'cancel_and_notify_registration'     => array(
339
+				'func'       => 'cancel_registration',
340
+				'noheader'   => true,
341
+				'args'       => array(true),
342
+				'capability' => 'ee_edit_registration',
343
+				'obj_id'     => $reg_id,
344
+			),
345
+			'cancel_registrations'                => array(
346
+				'func'       => 'bulk_action_on_registrations',
347
+				'noheader'   => true,
348
+				'capability' => 'ee_edit_registrations',
349
+				'args' => array('cancel')
350
+			),
351
+			'cancel_and_notify_registrations'     => array(
352
+				'func'       => 'bulk_action_on_registrations',
353
+				'noheader'   => true,
354
+				'capability' => 'ee_edit_registrations',
355
+				'args' => array('cancel', true)
356
+			),
357
+			'wait_list_registration' => array(
358
+				'func'       => 'wait_list_registration',
359
+				'noheader'   => true,
360
+				'capability' => 'ee_edit_registration',
361
+				'obj_id'     => $reg_id,
362
+			),
363
+			'contact_list'                       => array(
364
+				'func'       => '_attendee_contact_list_table',
365
+				'capability' => 'ee_read_contacts',
366
+			),
367
+			'add_new_attendee'                   => array(
368
+				'func' => '_create_new_cpt_item',
369
+				'args' => array(
370
+					'new_attendee' => true,
371
+					'capability'   => 'ee_edit_contacts',
372
+				),
373
+			),
374
+			'edit_attendee'                      => array(
375
+				'func'       => '_edit_cpt_item',
376
+				'capability' => 'ee_edit_contacts',
377
+				'obj_id'     => $att_id,
378
+			),
379
+			'duplicate_attendee'                 => array(
380
+				'func'       => '_duplicate_attendee',
381
+				'noheader'   => true,
382
+				'capability' => 'ee_edit_contacts',
383
+				'obj_id'     => $att_id,
384
+			),
385
+			'insert_attendee'                    => array(
386
+				'func'       => '_insert_or_update_attendee',
387
+				'args'       => array(
388
+					'new_attendee' => true,
389
+				),
390
+				'noheader'   => true,
391
+				'capability' => 'ee_edit_contacts',
392
+			),
393
+			'update_attendee'                    => array(
394
+				'func'       => '_insert_or_update_attendee',
395
+				'args'       => array(
396
+					'new_attendee' => false,
397
+				),
398
+				'noheader'   => true,
399
+				'capability' => 'ee_edit_contacts',
400
+				'obj_id'     => $att_id,
401
+			),
402
+			'trash_attendees' => array(
403
+				'func' => '_trash_or_restore_attendees',
404
+				'args' => array(
405
+					'trash' => 'true'
406
+				),
407
+				'noheader' => true,
408
+				'capability' => 'ee_delete_contacts'
409
+			),
410
+			'trash_attendee'                    => array(
411
+				'func'       => '_trash_or_restore_attendees',
412
+				'args'       => array(
413
+					'trash' => true,
414
+				),
415
+				'noheader'   => true,
416
+				'capability' => 'ee_delete_contacts',
417
+				'obj_id'     => $att_id,
418
+			),
419
+			'restore_attendees'                  => array(
420
+				'func'       => '_trash_or_restore_attendees',
421
+				'args'       => array(
422
+					'trash' => false,
423
+				),
424
+				'noheader'   => true,
425
+				'capability' => 'ee_delete_contacts',
426
+				'obj_id'     => $att_id,
427
+			),
428
+			'resend_registration'                => array(
429
+				'func'       => '_resend_registration',
430
+				'noheader'   => true,
431
+				'capability' => 'ee_send_message',
432
+			),
433
+			'registrations_report'               => array(
434
+				'func'       => '_registrations_report',
435
+				'noheader'   => true,
436
+				'capability' => 'ee_read_registrations',
437
+			),
438
+			'contact_list_export'                => array(
439
+				'func'       => '_contact_list_export',
440
+				'noheader'   => true,
441
+				'capability' => 'export',
442
+			),
443
+			'contact_list_report'                => array(
444
+				'func'       => '_contact_list_report',
445
+				'noheader'   => true,
446
+				'capability' => 'ee_read_contacts',
447
+			),
448
+		);
449
+	}
450
+
451
+
452
+	protected function _set_page_config()
453
+	{
454
+		$this->_page_config = array(
455
+			'default'           => array(
456
+				'nav'           => array(
457
+					'label' => esc_html__('Overview', 'event_espresso'),
458
+					'order' => 5,
459
+				),
460
+				'help_tabs'     => array(
461
+					'registrations_overview_help_tab'                       => array(
462
+						'title'    => esc_html__('Registrations Overview', 'event_espresso'),
463
+						'filename' => 'registrations_overview',
464
+					),
465
+					'registrations_overview_table_column_headings_help_tab' => array(
466
+						'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
467
+						'filename' => 'registrations_overview_table_column_headings',
468
+					),
469
+					'registrations_overview_filters_help_tab'               => array(
470
+						'title'    => esc_html__('Registration Filters', 'event_espresso'),
471
+						'filename' => 'registrations_overview_filters',
472
+					),
473
+					'registrations_overview_views_help_tab'                 => array(
474
+						'title'    => esc_html__('Registration Views', 'event_espresso'),
475
+						'filename' => 'registrations_overview_views',
476
+					),
477
+					'registrations_regoverview_other_help_tab'              => array(
478
+						'title'    => esc_html__('Registrations Other', 'event_espresso'),
479
+						'filename' => 'registrations_overview_other',
480
+					),
481
+				),
482
+				'help_tour'     => array('Registration_Overview_Help_Tour'),
483
+				'qtips'         => array('Registration_List_Table_Tips'),
484
+				'list_table'    => 'EE_Registrations_List_Table',
485
+				'require_nonce' => false,
486
+			),
487
+			'view_registration' => array(
488
+				'nav'           => array(
489
+					'label'      => esc_html__('REG Details', 'event_espresso'),
490
+					'order'      => 15,
491
+					'url'        => isset($this->_req_data['_REG_ID'])
492
+						? add_query_arg(array('_REG_ID' => $this->_req_data['_REG_ID']), $this->_current_page_view_url)
493
+						: $this->_admin_base_url,
494
+					'persistent' => false,
495
+				),
496
+				'help_tabs'     => array(
497
+					'registrations_details_help_tab'                    => array(
498
+						'title'    => esc_html__('Registration Details', 'event_espresso'),
499
+						'filename' => 'registrations_details',
500
+					),
501
+					'registrations_details_table_help_tab'              => array(
502
+						'title'    => esc_html__('Registration Details Table', 'event_espresso'),
503
+						'filename' => 'registrations_details_table',
504
+					),
505
+					'registrations_details_form_answers_help_tab'       => array(
506
+						'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
507
+						'filename' => 'registrations_details_form_answers',
508
+					),
509
+					'registrations_details_registrant_details_help_tab' => array(
510
+						'title'    => esc_html__('Contact Details', 'event_espresso'),
511
+						'filename' => 'registrations_details_registrant_details',
512
+					),
513
+				),
514
+				'help_tour'     => array('Registration_Details_Help_Tour'),
515
+				'metaboxes'     => array_merge(
516
+					$this->_default_espresso_metaboxes,
517
+					array('_registration_details_metaboxes')
518
+				),
519
+				'require_nonce' => false,
520
+			),
521
+			'new_registration'  => array(
522
+				'nav'           => array(
523
+					'label'      => esc_html__('Add New Registration', 'event_espresso'),
524
+					'url'        => '#',
525
+					'order'      => 15,
526
+					'persistent' => false,
527
+				),
528
+				'metaboxes'     => $this->_default_espresso_metaboxes,
529
+				'labels'        => array(
530
+					'publishbox' => esc_html__('Save Registration', 'event_espresso'),
531
+				),
532
+				'require_nonce' => false,
533
+			),
534
+			'add_new_attendee'  => array(
535
+				'nav'           => array(
536
+					'label'      => esc_html__('Add Contact', 'event_espresso'),
537
+					'order'      => 15,
538
+					'persistent' => false,
539
+				),
540
+				'metaboxes'     => array_merge(
541
+					$this->_default_espresso_metaboxes,
542
+					array('_publish_post_box', 'attendee_editor_metaboxes')
543
+				),
544
+				'require_nonce' => false,
545
+			),
546
+			'edit_attendee'     => array(
547
+				'nav'           => array(
548
+					'label'      => esc_html__('Edit Contact', 'event_espresso'),
549
+					'order'      => 15,
550
+					'persistent' => false,
551
+					'url'        => isset($this->_req_data['ATT_ID'])
552
+						? add_query_arg(array('ATT_ID' => $this->_req_data['ATT_ID']), $this->_current_page_view_url)
553
+						: $this->_admin_base_url,
554
+				),
555
+				'metaboxes'     => array('attendee_editor_metaboxes'),
556
+				'require_nonce' => false,
557
+			),
558
+			'contact_list'      => array(
559
+				'nav'           => array(
560
+					'label' => esc_html__('Contact List', 'event_espresso'),
561
+					'order' => 20,
562
+				),
563
+				'list_table'    => 'EE_Attendee_Contact_List_Table',
564
+				'help_tabs'     => array(
565
+					'registrations_contact_list_help_tab'                       => array(
566
+						'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
567
+						'filename' => 'registrations_contact_list',
568
+					),
569
+					'registrations_contact-list_table_column_headings_help_tab' => array(
570
+						'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
571
+						'filename' => 'registrations_contact_list_table_column_headings',
572
+					),
573
+					'registrations_contact_list_views_help_tab'                 => array(
574
+						'title'    => esc_html__('Contact List Views', 'event_espresso'),
575
+						'filename' => 'registrations_contact_list_views',
576
+					),
577
+					'registrations_contact_list_other_help_tab'                 => array(
578
+						'title'    => esc_html__('Contact List Other', 'event_espresso'),
579
+						'filename' => 'registrations_contact_list_other',
580
+					),
581
+				),
582
+				'help_tour'     => array('Contact_List_Help_Tour'),
583
+				'metaboxes'     => array(),
584
+				'require_nonce' => false,
585
+			),
586
+			//override default cpt routes
587
+			'create_new'        => '',
588
+			'edit'              => '',
589
+		);
590
+	}
591
+
592
+
593
+	/**
594
+	 * The below methods aren't used by this class currently
595
+	 */
596
+	protected function _add_screen_options()
597
+	{
598
+	}
599
+
600
+
601
+	protected function _add_feature_pointers()
602
+	{
603
+	}
604
+
605
+
606
+	public function admin_init()
607
+	{
608
+		EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
609
+			'click "Update Registration Questions" to save your changes',
610
+			'event_espresso'
611
+		);
612
+	}
613
+
614
+
615
+	public function admin_notices()
616
+	{
617
+	}
618
+
619
+
620
+	public function admin_footer_scripts()
621
+	{
622
+	}
623
+
624
+
625
+	/**
626
+	 *        get list of registration statuses
627
+	 *
628
+	 * @access private
629
+	 * @return void
630
+	 */
631
+	private function _get_registration_status_array()
632
+	{
633
+		self::$_reg_status = EEM_Registration::reg_status_array(array(), true);
634
+	}
635
+
636
+
637
+	protected function _add_screen_options_default()
638
+	{
639
+		$this->_per_page_screen_option();
640
+	}
641
+
642
+
643
+	protected function _add_screen_options_contact_list()
644
+	{
645
+		$page_title              = $this->_admin_page_title;
646
+		$this->_admin_page_title = esc_html__("Contacts", 'event_espresso');
647
+		$this->_per_page_screen_option();
648
+		$this->_admin_page_title = $page_title;
649
+	}
650
+
651
+
652
+	public function load_scripts_styles()
653
+	{
654
+		//style
655
+		wp_register_style(
656
+			'espresso_reg',
657
+			REG_ASSETS_URL . 'espresso_registrations_admin.css',
658
+			array('ee-admin-css'),
659
+			EVENT_ESPRESSO_VERSION
660
+		);
661
+		wp_enqueue_style('espresso_reg');
662
+		//script
663
+		wp_register_script(
664
+			'espresso_reg',
665
+			REG_ASSETS_URL . 'espresso_registrations_admin.js',
666
+			array('jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'),
667
+			EVENT_ESPRESSO_VERSION,
668
+			true
669
+		);
670
+		wp_enqueue_script('espresso_reg');
671
+	}
672
+
673
+
674
+	public function load_scripts_styles_edit_attendee()
675
+	{
676
+		//stuff to only show up on our attendee edit details page.
677
+		$attendee_details_translations = array(
678
+			'att_publish_text' => sprintf(
679
+				esc_html__('Created on: <b>%1$s</b>', 'event_espresso'),
680
+				$this->_cpt_model_obj->get_datetime('ATT_created')
681
+			),
682
+		);
683
+		wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
684
+		wp_enqueue_script('jquery-validate');
685
+	}
686
+
687
+
688
+	public function load_scripts_styles_view_registration()
689
+	{
690
+		//styles
691
+		wp_enqueue_style('espresso-ui-theme');
692
+		//scripts
693
+		$this->_get_reg_custom_questions_form($this->_registration->ID());
694
+		$this->_reg_custom_questions_form->wp_enqueue_scripts(true);
695
+	}
696
+
697
+
698
+	public function load_scripts_styles_contact_list()
699
+	{
700
+		wp_deregister_style('espresso_reg');
701
+		wp_register_style(
702
+			'espresso_att',
703
+			REG_ASSETS_URL . 'espresso_attendees_admin.css',
704
+			array('ee-admin-css'),
705
+			EVENT_ESPRESSO_VERSION
706
+		);
707
+		wp_enqueue_style('espresso_att');
708
+	}
709
+
710
+
711
+	public function load_scripts_styles_new_registration()
712
+	{
713
+		wp_register_script(
714
+			'ee-spco-for-admin',
715
+			REG_ASSETS_URL . 'spco_for_admin.js',
716
+			array('underscore', 'jquery'),
717
+			EVENT_ESPRESSO_VERSION,
718
+			true
719
+		);
720
+		wp_enqueue_script('ee-spco-for-admin');
721
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
722
+		EE_Form_Section_Proper::wp_enqueue_scripts();
723
+		EED_Ticket_Selector::load_tckt_slctr_assets();
724
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
725
+	}
726
+
727
+
728
+	public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
729
+	{
730
+		add_filter('FHEE_load_EE_messages', '__return_true');
731
+	}
732
+
733
+
734
+	public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
735
+	{
736
+		add_filter('FHEE_load_EE_messages', '__return_true');
737
+	}
738
+
739
+
740
+	protected function _set_list_table_views_default()
741
+	{
742
+		//for notification related bulk actions we need to make sure only active messengers have an option.
743
+		EED_Messages::set_autoloaders();
744
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
745
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
746
+		$active_mts               = $message_resource_manager->list_of_active_message_types();
747
+		//key= bulk_action_slug, value= message type.
748
+		$match_array = array(
749
+			'approve_registrations'    => 'registration',
750
+			'decline_registrations'    => 'declined_registration',
751
+			'pending_registrations'    => 'pending_approval',
752
+			'no_approve_registrations' => 'not_approved_registration',
753
+			'cancel_registrations'     => 'cancelled_registration',
754
+		);
755
+		$can_send = EE_Registry::instance()->CAP->current_user_can(
756
+			'ee_send_message',
757
+			'batch_send_messages'
758
+		);
759
+		/** setup reg status bulk actions **/
760
+		$def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
761
+		if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
762
+				$def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
763
+					'Approve and Notify Registrations',
764
+					'event_espresso'
765
+				);
766
+		}
767
+		$def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
768
+		if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
769
+				$def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
770
+					'Decline and Notify Registrations',
771
+					'event_espresso'
772
+				);
773
+		}
774
+		$def_reg_status_actions['pending_registrations'] = esc_html__(
775
+			'Set Registrations to Pending Payment',
776
+			'event_espresso'
777
+		);
778
+		if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
779
+				$def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
780
+					'Set Registrations to Pending Payment and Notify',
781
+					'event_espresso'
782
+				);
783
+		}
784
+		$def_reg_status_actions['no_approve_registrations'] = esc_html__(
785
+			'Set Registrations to Not Approved',
786
+			'event_espresso'
787
+		);
788
+		if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
789
+				$def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
790
+					'Set Registrations to Not Approved and Notify',
791
+					'event_espresso'
792
+				);
793
+		}
794
+		$def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
795
+		if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
796
+				$def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
797
+					'Cancel Registrations and Notify',
798
+					'event_espresso'
799
+				);
800
+		}
801
+		$def_reg_status_actions = apply_filters(
802
+			'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
803
+			$def_reg_status_actions,
804
+			$active_mts
805
+		);
806
+
807
+		$this->_views = array(
808
+			'all'   => array(
809
+				'slug'        => 'all',
810
+				'label'       => esc_html__('View All Registrations', 'event_espresso'),
811
+				'count'       => 0,
812
+				'bulk_action' => array_merge($def_reg_status_actions, array(
813
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
814
+				)),
815
+			),
816
+			'month' => array(
817
+				'slug'        => 'month',
818
+				'label'       => esc_html__('This Month', 'event_espresso'),
819
+				'count'       => 0,
820
+				'bulk_action' => array_merge($def_reg_status_actions, array(
821
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
822
+				)),
823
+			),
824
+			'today' => array(
825
+				'slug'        => 'today',
826
+				'label'       => sprintf(
827
+					esc_html__('Today - %s', 'event_espresso'),
828
+					date('M d, Y', current_time('timestamp'))
829
+				),
830
+				'count'       => 0,
831
+				'bulk_action' => array_merge($def_reg_status_actions, array(
832
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
833
+				)),
834
+			),
835
+		);
836
+		if (EE_Registry::instance()->CAP->current_user_can(
837
+			'ee_delete_registrations',
838
+			'espresso_registrations_delete_registration'
839
+		)) {
840
+			$this->_views['incomplete'] = array(
841
+				'slug'        => 'incomplete',
842
+				'label'       => esc_html__('Incomplete', 'event_espresso'),
843
+				'count'       => 0,
844
+				'bulk_action' => array(
845
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
846
+				),
847
+			);
848
+			$this->_views['trash']      = array(
849
+				'slug'        => 'trash',
850
+				'label'       => esc_html__('Trash', 'event_espresso'),
851
+				'count'       => 0,
852
+				'bulk_action' => array(
853
+					'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
854
+					'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
855
+				),
856
+			);
857
+		}
858
+	}
859
+
860
+
861
+	protected function _set_list_table_views_contact_list()
862
+	{
863
+		$this->_views = array(
864
+			'in_use' => array(
865
+				'slug'        => 'in_use',
866
+				'label'       => esc_html__('In Use', 'event_espresso'),
867
+				'count'       => 0,
868
+				'bulk_action' => array(
869
+					'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
870
+				),
871
+			),
872
+		);
873
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_contacts',
874
+			'espresso_registrations_trash_attendees')
875
+		) {
876
+			$this->_views['trash'] = array(
877
+				'slug'        => 'trash',
878
+				'label'       => esc_html__('Trash', 'event_espresso'),
879
+				'count'       => 0,
880
+				'bulk_action' => array(
881
+					'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
882
+				),
883
+			);
884
+		}
885
+	}
886
+
887
+
888
+	protected function _registration_legend_items()
889
+	{
890
+		$fc_items = array(
891
+			'star-icon'        => array(
892
+				'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
893
+				'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
894
+			),
895
+			'view_details'     => array(
896
+				'class' => 'dashicons dashicons-clipboard',
897
+				'desc'  => esc_html__('View Registration Details', 'event_espresso'),
898
+			),
899
+			'edit_attendee'    => array(
900
+				'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
901
+				'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
902
+			),
903
+			'view_transaction' => array(
904
+				'class' => 'dashicons dashicons-cart',
905
+				'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
906
+			),
907
+			'view_invoice'     => array(
908
+				'class' => 'dashicons dashicons-media-spreadsheet',
909
+				'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
910
+			),
911
+		);
912
+		if (EE_Registry::instance()->CAP->current_user_can(
913
+			'ee_send_message',
914
+			'espresso_registrations_resend_registration'
915
+		)) {
916
+			$fc_items['resend_registration'] = array(
917
+				'class' => 'dashicons dashicons-email-alt',
918
+				'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
919
+			);
920
+		} else {
921
+			$fc_items['blank'] = array('class' => 'blank', 'desc' => '');
922
+		}
923
+		if (EE_Registry::instance()->CAP->current_user_can(
924
+			'ee_read_global_messages',
925
+			'view_filtered_messages'
926
+		)) {
927
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
928
+			if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
929
+				$fc_items['view_related_messages'] = array(
930
+					'class' => $related_for_icon['css_class'],
931
+					'desc'  => $related_for_icon['label'],
932
+				);
933
+			}
934
+		}
935
+		$sc_items = array(
936
+			'approved_status'   => array(
937
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
938
+				'desc'  => EEH_Template::pretty_status(
939
+					EEM_Registration::status_id_approved,
940
+					false,
941
+					'sentence'
942
+				),
943
+			),
944
+			'pending_status'    => array(
945
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
946
+				'desc'  => EEH_Template::pretty_status(
947
+					EEM_Registration::status_id_pending_payment,
948
+					false,
949
+					'sentence'
950
+				),
951
+			),
952
+			'wait_list'         => array(
953
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
954
+				'desc'  => EEH_Template::pretty_status(
955
+					EEM_Registration::status_id_wait_list,
956
+					false,
957
+					'sentence'
958
+				),
959
+			),
960
+			'incomplete_status' => array(
961
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
962
+				'desc'  => EEH_Template::pretty_status(
963
+					EEM_Registration::status_id_incomplete,
964
+					false,
965
+					'sentence'
966
+				),
967
+			),
968
+			'not_approved'      => array(
969
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
970
+				'desc'  => EEH_Template::pretty_status(
971
+					EEM_Registration::status_id_not_approved,
972
+					false,
973
+					'sentence'
974
+				),
975
+			),
976
+			'declined_status'   => array(
977
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
978
+				'desc'  => EEH_Template::pretty_status(
979
+					EEM_Registration::status_id_declined,
980
+					false,
981
+					'sentence'
982
+				),
983
+			),
984
+			'cancelled_status'  => array(
985
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
986
+				'desc'  => EEH_Template::pretty_status(
987
+					EEM_Registration::status_id_cancelled,
988
+					false,
989
+					'sentence'
990
+				),
991
+			),
992
+		);
993
+		return array_merge($fc_items, $sc_items);
994
+	}
995
+
996
+
997
+
998
+	/***************************************        REGISTRATION OVERVIEW        **************************************/
999
+	/**
1000
+	 * @throws \EE_Error
1001
+	 */
1002
+	protected function _registrations_overview_list_table()
1003
+	{
1004
+		$this->_template_args['admin_page_header'] = '';
1005
+		$EVT_ID                                    = ! empty($this->_req_data['event_id'])
1006
+			? absint($this->_req_data['event_id'])
1007
+			: 0;
1008
+		if ($EVT_ID) {
1009
+			if (EE_Registry::instance()->CAP->current_user_can(
1010
+				'ee_edit_registrations',
1011
+				'espresso_registrations_new_registration',
1012
+				$EVT_ID
1013
+			)) {
1014
+				$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1015
+					'new_registration',
1016
+					'add-registrant',
1017
+					array('event_id' => $EVT_ID),
1018
+					'add-new-h2'
1019
+				);
1020
+			}
1021
+			$event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
1022
+			if ($event instanceof EE_Event) {
1023
+				$this->_template_args['admin_page_header'] = sprintf(
1024
+					esc_html__(
1025
+						'%s Viewing registrations for the event: %s%s',
1026
+						'event_espresso'
1027
+					),
1028
+					'<h3 style="line-height:1.5em;">',
1029
+					'<br /><a href="'
1030
+						. EE_Admin_Page::add_query_args_and_nonce(
1031
+							array(
1032
+								'action' => 'edit',
1033
+								'post'   => $event->ID(),
1034
+							),
1035
+							EVENTS_ADMIN_URL
1036
+						)
1037
+						. '">&nbsp;'
1038
+						. $event->get('EVT_name')
1039
+						. '&nbsp;</a>&nbsp;',
1040
+					'</h3>'
1041
+				);
1042
+			}
1043
+			$DTT_ID   = ! empty($this->_req_data['datetime_id']) ? absint($this->_req_data['datetime_id']) : 0;
1044
+			$datetime = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
1045
+			if ($datetime instanceof EE_Datetime && $this->_template_args['admin_page_header'] !== '') {
1046
+				$this->_template_args['admin_page_header'] = substr(
1047
+					$this->_template_args['admin_page_header'],
1048
+					0,
1049
+					-5
1050
+				);
1051
+				$this->_template_args['admin_page_header'] .= ' &nbsp;<span class="drk-grey-text">';
1052
+				$this->_template_args['admin_page_header'] .= '<span class="dashicons dashicons-calendar"></span>';
1053
+				$this->_template_args['admin_page_header'] .= $datetime->name();
1054
+				$this->_template_args['admin_page_header'] .= ' ( ' . $datetime->start_date() . ' )';
1055
+				$this->_template_args['admin_page_header'] .= '</span></h3>';
1056
+			}
1057
+		}
1058
+		$this->_template_args['after_list_table'] = $this->_display_legend($this->_registration_legend_items());
1059
+		$this->display_admin_list_table_page_with_no_sidebar();
1060
+	}
1061
+
1062
+
1063
+	/**
1064
+	 * This sets the _registration property for the registration details screen
1065
+	 *
1066
+	 * @access private
1067
+	 * @return bool
1068
+	 */
1069
+	private function _set_registration_object()
1070
+	{
1071
+		//get out if we've already set the object
1072
+		if (is_object($this->_registration)) {
1073
+			return true;
1074
+		}
1075
+		$REG    = EEM_Registration::instance();
1076
+		$REG_ID = ( ! empty($this->_req_data['_REG_ID'])) ? absint($this->_req_data['_REG_ID']) : false;
1077
+		if ($this->_registration = $REG->get_one_by_ID($REG_ID)) {
1078
+			return true;
1079
+		} else {
1080
+			$error_msg = sprintf(
1081
+				esc_html__(
1082
+					'An error occurred and the details for Registration ID #%s could not be retrieved.',
1083
+					'event_espresso'
1084
+				),
1085
+				$REG_ID
1086
+			);
1087
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1088
+			$this->_registration = null;
1089
+			return false;
1090
+		}
1091
+	}
1092
+
1093
+
1094
+	/**
1095
+	 * Used to retrieve registrations for the list table.
1096
+	 *
1097
+	 * @param int  $per_page
1098
+	 * @param bool $count
1099
+	 * @param bool $this_month
1100
+	 * @param bool $today
1101
+	 * @return EE_Registration[]|int
1102
+	 * @throws EE_Error
1103
+	 */
1104
+	public function get_registrations(
1105
+		$per_page = 10,
1106
+		$count = false,
1107
+		$this_month = false,
1108
+		$today = false
1109
+	) {
1110
+		if ($this_month) {
1111
+			$this->_req_data['status'] = 'month';
1112
+		}
1113
+		if ($today) {
1114
+			$this->_req_data['status'] = 'today';
1115
+		}
1116
+		$query_params = $this->_get_registration_query_parameters($this->_req_data, $per_page, $count);
1117
+		/**
1118
+		 * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1119
+		 * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1120
+		 * @see EEM_Base::get_all()
1121
+		 */
1122
+		$query_params['group_by'] = '';
1123
+
1124
+		return $count
1125
+			? EEM_Registration::instance()->count($query_params)
1126
+			/** @type EE_Registration[] */
1127
+			: EEM_Registration::instance()->get_all($query_params);
1128
+	}
1129
+
1130
+
1131
+
1132
+	/**
1133
+	 * Retrieves the query parameters to be used by the Registration model for getting registrations.
1134
+	 * Note: this listens to values on the request for some of the query parameters.
1135
+	 *
1136
+	 * @param array $request
1137
+	 * @param int    $per_page
1138
+	 * @param bool   $count
1139
+	 * @return array
1140
+	 */
1141
+	protected function _get_registration_query_parameters(
1142
+		$request = array(),
1143
+		$per_page = 10,
1144
+		$count = false
1145
+	) {
1146
+
1147
+		$query_params = array(
1148
+			0                          => $this->_get_where_conditions_for_registrations_query(
1149
+				$request
1150
+			),
1151
+			'caps'                     => EEM_Registration::caps_read_admin,
1152
+			'default_where_conditions' => 'this_model_only',
1153
+		);
1154
+		if (! $count) {
1155
+			$query_params = array_merge(
1156
+				$query_params,
1157
+				$this->_get_orderby_for_registrations_query(),
1158
+				$this->_get_limit($per_page)
1159
+			);
1160
+		}
1161
+
1162
+		return $query_params;
1163
+	}
1164
+
1165
+
1166
+	/**
1167
+	 * This will add EVT_ID to the provided $where array for EE model query parameters.
1168
+	 *
1169
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1170
+	 * @return array
1171
+	 */
1172
+	protected function _add_event_id_to_where_conditions(array $request)
1173
+	{
1174
+		$where = array();
1175
+		if (! empty($request['event_id'])) {
1176
+			$where['EVT_ID'] = absint($request['event_id']);
1177
+		}
1178
+		return $where;
1179
+	}
1180
+
1181
+
1182
+	/**
1183
+	 * Adds category ID if it exists in the request to the where conditions for the registrations query.
1184
+	 *
1185
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1186
+	 * @return array
1187
+	 */
1188
+	protected function _add_category_id_to_where_conditions(array $request)
1189
+	{
1190
+		$where = array();
1191
+		if (! empty($request['EVT_CAT']) && (int)$request['EVT_CAT'] !== -1) {
1192
+			$where['Event.Term_Taxonomy.term_id'] = absint($request['EVT_CAT']);
1193
+		}
1194
+		return $where;
1195
+	}
1196
+
1197
+
1198
+	/**
1199
+	 * Adds the datetime ID if it exists in the request to the where conditions for the registrations query.
1200
+	 *
1201
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1202
+	 * @return array
1203
+	 */
1204
+	protected function _add_datetime_id_to_where_conditions(array $request)
1205
+	{
1206
+		$where = array();
1207
+		if (! empty($request['datetime_id'])) {
1208
+			$where['Ticket.Datetime.DTT_ID'] = absint($request['datetime_id']);
1209
+		}
1210
+		if (! empty($request['DTT_ID'])) {
1211
+			$where['Ticket.Datetime.DTT_ID'] = absint($request['DTT_ID']);
1212
+		}
1213
+		return $where;
1214
+	}
1215
+
1216
+
1217
+	/**
1218
+	 * Adds the correct registration status to the where conditions for the registrations query.
1219
+	 *
1220
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1221
+	 * @return array
1222
+	 */
1223
+	protected function _add_registration_status_to_where_conditions(array $request)
1224
+	{
1225
+		$where = array();
1226
+		$view = EEH_Array::is_set($request, 'status', '');
1227
+		$registration_status = ! empty($request['_reg_status'])
1228
+			? sanitize_text_field($request['_reg_status'])
1229
+			: '';
1230
+
1231
+		/*
1232 1232
          * If filtering by registration status, then we show registrations matching that status.
1233 1233
          * If not filtering by specified status, then we show all registrations excluding incomplete registrations
1234 1234
          * UNLESS viewing trashed registrations.
1235 1235
          */
1236
-        if (! empty($registration_status)) {
1237
-            $where['STS_ID'] = $registration_status;
1238
-        } else {
1239
-            //make sure we exclude incomplete registrations, but only if not trashed.
1240
-            if ($view === 'trash') {
1241
-                $where['REG_deleted'] = true;
1242
-            } elseif ($view === 'incomplete') {
1243
-                $where['STS_ID'] = EEM_Registration::status_id_incomplete;
1244
-            } else {
1245
-                $where['STS_ID'] = array('!=', EEM_Registration::status_id_incomplete);
1246
-            }
1247
-        }
1248
-        return $where;
1249
-    }
1250
-
1251
-
1252
-    /**
1253
-     * Adds any provided date restraints to the where conditions for the registrations query.
1254
-     *
1255
-     * @param array $request usually the same as $this->_req_data but not necessarily
1256
-     * @return array
1257
-     * @throws EE_Error
1258
-     */
1259
-    protected function _add_date_to_where_conditions(array $request)
1260
-    {
1261
-        $where = array();
1262
-        $view = EEH_Array::is_set($request, 'status', '');
1263
-        $month_range             = ! empty($request['month_range'])
1264
-            ? sanitize_text_field($request['month_range'])
1265
-            : '';
1266
-        $retrieve_for_today      = $view === 'today';
1267
-        $retrieve_for_this_month = $view === 'month';
1268
-
1269
-        if ($retrieve_for_today) {
1270
-            $now               = date('Y-m-d', current_time('timestamp'));
1271
-            $where['REG_date'] = array(
1272
-                'BETWEEN',
1273
-                array(
1274
-                    EEM_Registration::instance()->convert_datetime_for_query(
1275
-                        'REG_date',
1276
-                        $now . ' 00:00:00',
1277
-                        'Y-m-d H:i:s'
1278
-                    ),
1279
-                    EEM_Registration::instance()->convert_datetime_for_query(
1280
-                        'REG_date',
1281
-                        $now . ' 23:59:59',
1282
-                        'Y-m-d H:i:s'
1283
-                    ),
1284
-                ),
1285
-            );
1286
-        } elseif ($retrieve_for_this_month) {
1287
-            $current_year_and_month = date('Y-m', current_time('timestamp'));
1288
-            $days_this_month        = date('t', current_time('timestamp'));
1289
-            $where['REG_date']      = array(
1290
-                'BETWEEN',
1291
-                array(
1292
-                    EEM_Registration::instance()->convert_datetime_for_query(
1293
-                        'REG_date',
1294
-                        $current_year_and_month . '-01 00:00:00',
1295
-                        'Y-m-d H:i:s'
1296
-                    ),
1297
-                    EEM_Registration::instance()->convert_datetime_for_query(
1298
-                        'REG_date',
1299
-                        $current_year_and_month . '-' . $days_this_month . ' 23:59:59',
1300
-                        'Y-m-d H:i:s'
1301
-                    ),
1302
-                ),
1303
-            );
1304
-        } elseif ($month_range) {
1305
-            $pieces          = explode(' ', $month_range, 3);
1306
-            $month_requested = ! empty($pieces[0])
1307
-                ? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0]))
1308
-                : '';
1309
-            $year_requested  = ! empty($pieces[1])
1310
-                ? $pieces[1]
1311
-                : '';
1312
-            //if there is not a month or year then we can't go further
1313
-            if ($month_requested && $year_requested) {
1314
-                $days_in_month     = date('t', strtotime($year_requested . '-' . $month_requested . '-' . '01'));
1315
-                $where['REG_date'] = array(
1316
-                    'BETWEEN',
1317
-                    array(
1318
-                        EEM_Registration::instance()->convert_datetime_for_query(
1319
-                            'REG_date',
1320
-                            $year_requested . '-' . $month_requested . '-01 00:00:00',
1321
-                            'Y-m-d H:i:s'
1322
-                        ),
1323
-                        EEM_Registration::instance()->convert_datetime_for_query(
1324
-                            'REG_date',
1325
-                            $year_requested . '-' . $month_requested . '-' . $days_in_month . ' 23:59:59',
1326
-                            'Y-m-d H:i:s'
1327
-                        ),
1328
-                    ),
1329
-                );
1330
-            }
1331
-        }
1332
-        return $where;
1333
-    }
1334
-
1335
-
1336
-    /**
1337
-     * Adds any provided search restraints to the where conditions for the registrations query
1338
-     *
1339
-     * @param array $request usually the same as $this->_req_data but not necessarily
1340
-     * @return array
1341
-     */
1342
-    protected function _add_search_to_where_conditions(array $request)
1343
-    {
1344
-        $where = array();
1345
-        if (! empty($request['s'])) {
1346
-            $search_string = '%' . sanitize_text_field($request['s']) . '%';
1347
-            $where['OR*search_conditions'] = array(
1348
-                'Event.EVT_name'                          => array('LIKE', $search_string),
1349
-                'Event.EVT_desc'                          => array('LIKE', $search_string),
1350
-                'Event.EVT_short_desc'                    => array('LIKE', $search_string),
1351
-                'Attendee.ATT_full_name'                  => array('LIKE', $search_string),
1352
-                'Attendee.ATT_fname'                      => array('LIKE', $search_string),
1353
-                'Attendee.ATT_lname'                      => array('LIKE', $search_string),
1354
-                'Attendee.ATT_short_bio'                  => array('LIKE', $search_string),
1355
-                'Attendee.ATT_email'                      => array('LIKE', $search_string),
1356
-                'Attendee.ATT_address'                    => array('LIKE', $search_string),
1357
-                'Attendee.ATT_address2'                   => array('LIKE', $search_string),
1358
-                'Attendee.ATT_city'                       => array('LIKE', $search_string),
1359
-                'REG_final_price'                         => array('LIKE', $search_string),
1360
-                'REG_code'                                => array('LIKE', $search_string),
1361
-                'REG_count'                               => array('LIKE', $search_string),
1362
-                'REG_group_size'                          => array('LIKE', $search_string),
1363
-                'Ticket.TKT_name'                         => array('LIKE', $search_string),
1364
-                'Ticket.TKT_description'                  => array('LIKE', $search_string),
1365
-                'Transaction.Payment.PAY_txn_id_chq_nmbr' => array('LIKE', $search_string),
1366
-            );
1367
-        }
1368
-        return $where;
1369
-    }
1370
-
1371
-
1372
-    /**
1373
-     * Sets up the where conditions for the registrations query.
1374
-     *
1375
-     * @param array $request
1376
-     * @return array
1377
-     * @throws EE_Error
1378
-     */
1379
-    protected function _get_where_conditions_for_registrations_query($request)
1380
-    {
1381
-        return apply_filters(
1382
-            'FHEE__Registrations_Admin_Page___get_where_conditions_for_registrations_query',
1383
-            array_merge(
1384
-                $this->_add_event_id_to_where_conditions($request),
1385
-                $this->_add_category_id_to_where_conditions($request),
1386
-                $this->_add_datetime_id_to_where_conditions($request),
1387
-                $this->_add_registration_status_to_where_conditions($request),
1388
-                $this->_add_date_to_where_conditions($request),
1389
-                $this->_add_search_to_where_conditions($request)
1390
-            ),
1391
-            $request
1392
-        );
1393
-    }
1394
-
1395
-
1396
-    /**
1397
-     * Sets up the orderby for the registrations query.
1398
-     *
1399
-     * @return array
1400
-     */
1401
-    protected function _get_orderby_for_registrations_query()
1402
-    {
1403
-        $orderby_field = ! empty($this->_req_data['orderby'])
1404
-            ? sanitize_text_field($this->_req_data['orderby'])
1405
-            : '';
1406
-        switch ($orderby_field) {
1407
-            case '_REG_ID':
1408
-                $orderby_field = 'REG_ID';
1409
-                break;
1410
-            case '_Reg_status':
1411
-                $orderby_field = 'STS_ID';
1412
-                break;
1413
-            case 'ATT_fname':
1414
-                $orderby_field = array('Attendee.ATT_fname', 'Attendee.ATT_lname');
1415
-                break;
1416
-            case 'ATT_lname':
1417
-                $orderby_field = array('Attendee.ATT_lname', 'Attendee.ATT_fname');
1418
-                break;
1419
-            case 'event_name':
1420
-                $orderby_field = 'Event.EVT_name';
1421
-                break;
1422
-            case 'DTT_EVT_start':
1423
-                $orderby_field = 'Event.Datetime.DTT_EVT_start';
1424
-                break;
1425
-            default: //'REG_date'
1426
-                $orderby_field = 'REG_date';
1427
-        }
1428
-
1429
-        //order
1430
-        $order = ! empty($this->_req_data['order'])
1431
-            ? sanitize_text_field($this->_req_data['order'])
1432
-            : 'DESC';
1433
-
1434
-        //mutate orderby_field
1435
-        $orderby_field = array_combine(
1436
-            (array) $orderby_field,
1437
-            array_fill(0, count($orderby_field), $order)
1438
-        );
1439
-        return array('order_by' => $orderby_field);
1440
-    }
1441
-
1442
-
1443
-    /**
1444
-     * Sets up the limit for the registrations query.
1445
-     *
1446
-     * @param $per_page
1447
-     * @return array
1448
-     */
1449
-    protected function _get_limit($per_page)
1450
-    {
1451
-        $current_page = ! empty($this->_req_data['paged'])
1452
-            ? absint($this->_req_data['paged'])
1453
-            : 1;
1454
-        $per_page     = ! empty($this->_req_data['perpage'])
1455
-            ? $this->_req_data['perpage']
1456
-            : $per_page;
1457
-
1458
-        //-1 means return all results so get out if that's set.
1459
-        if ((int)$per_page === -1) {
1460
-            return array();
1461
-        }
1462
-        $per_page = absint($per_page);
1463
-        $offset   = ($current_page - 1) * $per_page;
1464
-        return array('limit' => array($offset, $per_page));
1465
-    }
1466
-
1467
-
1468
-    public function get_registration_status_array()
1469
-    {
1470
-        return self::$_reg_status;
1471
-    }
1472
-
1473
-
1474
-
1475
-
1476
-    /***************************************        REGISTRATION DETAILS        ***************************************/
1477
-    /**
1478
-     *        generates HTML for the View Registration Details Admin page
1479
-     *
1480
-     * @access protected
1481
-     * @return void
1482
-     * @throws DomainException
1483
-     * @throws EE_Error
1484
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1485
-     */
1486
-    protected function _registration_details()
1487
-    {
1488
-        $this->_template_args = array();
1489
-        $this->_set_registration_object();
1490
-        if (is_object($this->_registration)) {
1491
-            $transaction                                   = $this->_registration->transaction()
1492
-                ? $this->_registration->transaction()
1493
-                : EE_Transaction::new_instance();
1494
-            $this->_session                                = $transaction->session_data();
1495
-            $event_id                                      = $this->_registration->event_ID();
1496
-            $this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1497
-            $this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1498
-            $this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1499
-            $this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1500
-            $this->_template_args['grand_total']           = $transaction->total();
1501
-            $this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1502
-            // link back to overview
1503
-            $this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1504
-            $this->_template_args['registration']                = $this->_registration;
1505
-            $this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1506
-                array(
1507
-                    'action'   => 'default',
1508
-                    'event_id' => $event_id,
1509
-                ),
1510
-                REG_ADMIN_URL
1511
-            );
1512
-            $this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1513
-                array(
1514
-                    'action' => 'default',
1515
-                    'EVT_ID' => $event_id,
1516
-                    'page'   => 'espresso_transactions',
1517
-                ),
1518
-                admin_url('admin.php')
1519
-            );
1520
-            $this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1521
-                array(
1522
-                    'page'   => 'espresso_events',
1523
-                    'action' => 'edit',
1524
-                    'post'   => $event_id,
1525
-                ),
1526
-                admin_url('admin.php')
1527
-            );
1528
-            //next and previous links
1529
-            $next_reg                                      = $this->_registration->next(
1530
-                null,
1531
-                array(),
1532
-                'REG_ID'
1533
-            );
1534
-            $this->_template_args['next_registration']     = $next_reg
1535
-                ? $this->_next_link(
1536
-                    EE_Admin_Page::add_query_args_and_nonce(
1537
-                        array(
1538
-                            'action'  => 'view_registration',
1539
-                            '_REG_ID' => $next_reg['REG_ID'],
1540
-                        ),
1541
-                        REG_ADMIN_URL
1542
-                    ),
1543
-                    'dashicons dashicons-arrow-right ee-icon-size-22'
1544
-                )
1545
-                : '';
1546
-            $previous_reg                                  = $this->_registration->previous(
1547
-                null,
1548
-                array(),
1549
-                'REG_ID'
1550
-            );
1551
-            $this->_template_args['previous_registration'] = $previous_reg
1552
-                ? $this->_previous_link(
1553
-                    EE_Admin_Page::add_query_args_and_nonce(
1554
-                        array(
1555
-                            'action'  => 'view_registration',
1556
-                            '_REG_ID' => $previous_reg['REG_ID'],
1557
-                        ),
1558
-                        REG_ADMIN_URL
1559
-                    ),
1560
-                    'dashicons dashicons-arrow-left ee-icon-size-22'
1561
-                )
1562
-                : '';
1563
-            // grab header
1564
-            $template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1565
-            $this->_template_args['REG_ID']            = $this->_registration->ID();
1566
-            $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1567
-                $template_path,
1568
-                $this->_template_args,
1569
-                true
1570
-            );
1571
-        } else {
1572
-            $this->_template_args['admin_page_header'] = $this->display_espresso_notices();
1573
-        }
1574
-        // the details template wrapper
1575
-        $this->display_admin_page_with_sidebar();
1576
-    }
1577
-
1578
-
1579
-    protected function _registration_details_metaboxes()
1580
-    {
1581
-        do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1582
-        $this->_set_registration_object();
1583
-        $attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1584
-        add_meta_box('edit-reg-status-mbox', esc_html__('Registration Status', 'event_espresso'),
1585
-            array($this, 'set_reg_status_buttons_metabox'), $this->wp_page_slug, 'normal', 'high');
1586
-        add_meta_box('edit-reg-details-mbox', esc_html__('Registration Details', 'event_espresso'),
1587
-            array($this, '_reg_details_meta_box'), $this->wp_page_slug, 'normal', 'high');
1588
-        if ($attendee instanceof EE_Attendee
1589
-            && EE_Registry::instance()->CAP->current_user_can(
1590
-                'ee_edit_registration',
1591
-                'edit-reg-questions-mbox',
1592
-                $this->_registration->ID()
1593
-            )
1594
-        ) {
1595
-            add_meta_box(
1596
-                'edit-reg-questions-mbox',
1597
-                esc_html__('Registration Form Answers', 'event_espresso'),
1598
-                array($this, '_reg_questions_meta_box'),
1599
-                $this->wp_page_slug,
1600
-                'normal',
1601
-                'high'
1602
-            );
1603
-        }
1604
-        add_meta_box(
1605
-            'edit-reg-registrant-mbox',
1606
-            esc_html__('Contact Details', 'event_espresso'),
1607
-            array($this, '_reg_registrant_side_meta_box'),
1608
-            $this->wp_page_slug,
1609
-            'side',
1610
-            'high'
1611
-        );
1612
-        if ($this->_registration->group_size() > 1) {
1613
-            add_meta_box(
1614
-                'edit-reg-attendees-mbox',
1615
-                esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1616
-                array($this, '_reg_attendees_meta_box'),
1617
-                $this->wp_page_slug,
1618
-                'normal',
1619
-                'high'
1620
-            );
1621
-        }
1622
-    }
1623
-
1624
-
1625
-    /**
1626
-     * set_reg_status_buttons_metabox
1627
-     *
1628
-     * @access protected
1629
-     * @return string
1630
-     * @throws \EE_Error
1631
-     */
1632
-    public function set_reg_status_buttons_metabox()
1633
-    {
1634
-        $this->_set_registration_object();
1635
-        $change_reg_status_form = $this->_generate_reg_status_change_form();
1636
-        echo $change_reg_status_form->form_open(
1637
-            self::add_query_args_and_nonce(
1638
-                array(
1639
-                    'action' => 'change_reg_status',
1640
-                ),
1641
-                REG_ADMIN_URL
1642
-            )
1643
-        );
1644
-        echo $change_reg_status_form->get_html();
1645
-        echo $change_reg_status_form->form_close();
1646
-    }
1647
-
1648
-
1649
-
1650
-    /**
1651
-     * @return EE_Form_Section_Proper
1652
-     * @throws EE_Error
1653
-     */
1654
-    protected function _generate_reg_status_change_form()
1655
-    {
1656
-        return new EE_Form_Section_Proper(array(
1657
-            'name'            => 'reg_status_change_form',
1658
-            'html_id'         => 'reg-status-change-form',
1659
-            'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1660
-            'subsections'     => array(
1661
-                'return'             => new EE_Hidden_Input(array(
1662
-                    'name'    => 'return',
1663
-                    'default' => 'view_registration',
1664
-                )),
1665
-                'REG_ID'             => new EE_Hidden_Input(array(
1666
-                    'name'    => 'REG_ID',
1667
-                    'default' => $this->_registration->ID(),
1668
-                )),
1669
-                'current_status'     => new EE_Form_Section_HTML(
1670
-                    EEH_HTML::tr(
1671
-                        EEH_HTML::th(
1672
-                            EEH_HTML::label(
1673
-                                EEH_HTML::strong(esc_html__('Current Registration Status', 'event_espresso')
1674
-                                )
1675
-                            )
1676
-                        )
1677
-                        . EEH_HTML::td(
1678
-                            EEH_HTML::strong(
1679
-                                $this->_registration->pretty_status(),
1680
-                                '',
1681
-                                'status-' . $this->_registration->status_ID(),
1682
-                                'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1683
-                            )
1684
-                        )
1685
-                    )
1686
-                ),
1687
-                'reg_status'         => new EE_Select_Input(
1688
-                    $this->_get_reg_statuses(),
1689
-                    array(
1690
-                        'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1691
-                        'default'         => $this->_registration->status_ID(),
1692
-                    )
1693
-                ),
1694
-                'send_notifications' => new EE_Yes_No_Input(
1695
-                    array(
1696
-                        'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1697
-                        'default'         => false,
1698
-                        'html_help_text'  => esc_html__(
1699
-                            'If set to "Yes", then the related messages will be sent to the registrant.',
1700
-                            'event_espresso'
1701
-                        ),
1702
-                    )
1703
-                ),
1704
-                'submit'             => new EE_Submit_Input(
1705
-                    array(
1706
-                        'html_class'      => 'button-primary',
1707
-                        'html_label_text' => '&nbsp;',
1708
-                        'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1709
-                    )
1710
-                ),
1711
-            ),
1712
-        ));
1713
-    }
1714
-
1715
-
1716
-    /**
1717
-     * Returns an array of all the buttons for the various statuses and switch status actions
1718
-     *
1719
-     * @return array
1720
-     * @throws EE_Error
1721
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1722
-     */
1723
-    protected function _get_reg_statuses()
1724
-    {
1725
-        $reg_status_array = EEM_Registration::instance()->reg_status_array();
1726
-        unset ($reg_status_array[EEM_Registration::status_id_incomplete]);
1727
-        // get current reg status
1728
-        $current_status = $this->_registration->status_ID();
1729
-        // is registration for free event? This will determine whether to display the pending payment option
1730
-        if (
1731
-            $current_status !== EEM_Registration::status_id_pending_payment
1732
-            && $this->_registration->transaction()->is_free()
1733
-        ) {
1734
-            unset($reg_status_array[EEM_Registration::status_id_pending_payment]);
1735
-        }
1736
-        return EEM_Status::instance()->localized_status($reg_status_array, false, 'sentence');
1737
-    }
1738
-
1739
-
1740
-
1741
-    /**
1742
-     * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1743
-     *
1744
-     * @param bool $status REG status given for changing registrations to.
1745
-     * @param bool $notify Whether to send messages notifications or not.
1746
-     * @return array  (array with reg_id(s) updated and whether update was successful.
1747
-     * @throws \EE_Error
1748
-     */
1749
-    protected function _set_registration_status_from_request($status = false, $notify = false)
1750
-    {
1751
-        if (isset($this->_req_data['reg_status_change_form'])) {
1752
-            $REG_IDs = isset($this->_req_data['reg_status_change_form']['REG_ID'])
1753
-                ? (array)$this->_req_data['reg_status_change_form']['REG_ID'] : array();
1754
-        } else {
1755
-            $REG_IDs = isset($this->_req_data['_REG_ID']) ? (array)$this->_req_data['_REG_ID'] : array();
1756
-        }
1757
-        $success = $this->_set_registration_status($REG_IDs, $status);
1758
-        //notify?
1759
-        if ($success
1760
-            && $notify
1761
-            && EE_Registry::instance()->CAP->current_user_can(
1762
-                'ee_send_message',
1763
-                'espresso_registrations_resend_registration'
1764
-            )
1765
-        ) {
1766
-            $this->_process_resend_registration();
1767
-        }
1768
-        return $success;
1769
-    }
1770
-
1771
-
1772
-
1773
-    /**
1774
-     * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1775
-     * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1776
-     *
1777
-     * @param array $REG_IDs
1778
-     * @param bool  $status
1779
-     * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1780
-     * @throws \RuntimeException
1781
-     * @throws \EE_Error
1782
-     *               the array of updated registrations).
1783
-     * @throws EE_Error
1784
-     * @throws RuntimeException
1785
-     */
1786
-    protected function _set_registration_status($REG_IDs = array(), $status = false)
1787
-    {
1788
-        $success = false;
1789
-        // typecast $REG_IDs
1790
-        $REG_IDs = (array)$REG_IDs;
1791
-        if ( ! empty($REG_IDs)) {
1792
-            $success = true;
1793
-            // set default status if none is passed
1794
-            $status = $status ? $status : EEM_Registration::status_id_pending_payment;
1795
-            // sanitize $REG_IDs
1796
-            $REG_IDs = array_filter($REG_IDs, 'absint');
1797
-            //loop through REG_ID's and change status
1798
-            foreach ($REG_IDs as $REG_ID) {
1799
-                $registration = EEM_Registration::instance()->get_one_by_ID($REG_ID);
1800
-                if ($registration instanceof EE_Registration) {
1801
-                    $registration->set_status($status);
1802
-                    $result = $registration->save();
1803
-                    // verifying explicit fails because update *may* just return 0 for 0 rows affected
1804
-                    $success = $result !== false ? $success : false;
1805
-                }
1806
-            }
1807
-        }
1808
-        //reset _req_data['_REG_ID'] for any potential future messages notifications
1809
-        $this->_req_data['_REG_ID'] = $REG_IDs;
1810
-        //return $success and processed registrations
1811
-        return array('REG_ID' => $REG_IDs, 'success' => $success);
1812
-    }
1813
-
1814
-
1815
-    /**
1816
-     * Common logic for setting up success message and redirecting to appropriate route
1817
-     *
1818
-     * @param  string $STS_ID status id for the registration changed to
1819
-     * @param   bool  $notify indicates whether the _set_registration_status_from_request does notifications or not.
1820
-     * @return void
1821
-     */
1822
-    protected function _reg_status_change_return($STS_ID, $notify = false)
1823
-    {
1824
-        $result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1825
-            : array('success' => false);
1826
-        $success = isset($result['success']) && $result['success'];
1827
-        //setup success message
1828
-        if ($success) {
1829
-            if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1830
-                $msg = sprintf(esc_html__('Registration status has been set to %s', 'event_espresso'),
1831
-                    EEH_Template::pretty_status($STS_ID, false, 'lower'));
1832
-            } else {
1833
-                $msg = sprintf(esc_html__('Registrations have been set to %s.', 'event_espresso'),
1834
-                    EEH_Template::pretty_status($STS_ID, false, 'lower'));
1835
-            }
1836
-            EE_Error::add_success($msg);
1837
-        } else {
1838
-            EE_Error::add_error(
1839
-                esc_html__(
1840
-                    'Something went wrong, and the status was not changed',
1841
-                    'event_espresso'
1842
-                ), __FILE__, __LINE__, __FUNCTION__
1843
-            );
1844
-        }
1845
-        if (isset($this->_req_data['return']) && $this->_req_data['return'] == 'view_registration') {
1846
-            $route = array('action' => 'view_registration', '_REG_ID' => reset($result['REG_ID']));
1847
-        } else {
1848
-            $route = array('action' => 'default');
1849
-        }
1850
-        //unset nonces
1851
-        foreach ($this->_req_data as $ref => $value) {
1852
-            if (strpos($ref, 'nonce') !== false) {
1853
-                unset($this->_req_data[$ref]);
1854
-                continue;
1855
-            }
1856
-            $value                 = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
1857
-            $this->_req_data[$ref] = $value;
1858
-        }
1859
-        //merge request vars so that the reloaded list table contains any existing filter query params
1860
-        $route = array_merge($this->_req_data, $route);
1861
-        $this->_redirect_after_action($success, '', '', $route, true);
1862
-    }
1863
-
1864
-
1865
-    /**
1866
-     * incoming reg status change from reg details page.
1867
-     *
1868
-     * @return void
1869
-     */
1870
-    protected function _change_reg_status()
1871
-    {
1872
-        $this->_req_data['return'] = 'view_registration';
1873
-        //set notify based on whether the send notifications toggle is set or not
1874
-        $notify = ! empty($this->_req_data['reg_status_change_form']['send_notifications']);
1875
-        //$notify = ! empty( $this->_req_data['txn_reg_status_change']['send_notifications'] );
1876
-        $this->_req_data['reg_status_change_form']['reg_status'] = isset($this->_req_data['reg_status_change_form']['reg_status'])
1877
-            ? $this->_req_data['reg_status_change_form']['reg_status'] : '';
1878
-        switch ($this->_req_data['reg_status_change_form']['reg_status']) {
1879
-            case EEM_Registration::status_id_approved :
1880
-            case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence') :
1881
-                $this->approve_registration($notify);
1882
-                break;
1883
-            case EEM_Registration::status_id_pending_payment :
1884
-            case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence') :
1885
-                $this->pending_registration($notify);
1886
-                break;
1887
-            case EEM_Registration::status_id_not_approved :
1888
-            case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence') :
1889
-                $this->not_approve_registration($notify);
1890
-                break;
1891
-            case EEM_Registration::status_id_declined :
1892
-            case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence') :
1893
-                $this->decline_registration($notify);
1894
-                break;
1895
-            case EEM_Registration::status_id_cancelled :
1896
-            case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence') :
1897
-                $this->cancel_registration($notify);
1898
-                break;
1899
-            case EEM_Registration::status_id_wait_list :
1900
-            case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence') :
1901
-                $this->wait_list_registration($notify);
1902
-                break;
1903
-            case EEM_Registration::status_id_incomplete :
1904
-            default :
1905
-                $result['success'] = false;
1906
-                unset($this->_req_data['return']);
1907
-                $this->_reg_status_change_return('', false);
1908
-                break;
1909
-        }
1910
-    }
1911
-
1912
-
1913
-    /**
1914
-     * Callback for bulk action routes.
1915
-     * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1916
-     * method was chosen so there is one central place all the registration status bulk actions are going through.
1917
-     * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1918
-     * when an action is happening on just a single registration).
1919
-     * @param      $action
1920
-     * @param bool $notify
1921
-     */
1922
-    protected function bulk_action_on_registrations($action, $notify = false) {
1923
-        do_action(
1924
-            'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1925
-            $this,
1926
-            $action,
1927
-            $notify
1928
-        );
1929
-        $method = $action . '_registration';
1930
-        if (method_exists($this, $method)) {
1931
-            $this->$method($notify);
1932
-        }
1933
-    }
1934
-
1935
-
1936
-    /**
1937
-     * approve_registration
1938
-     *
1939
-     * @access protected
1940
-     * @param bool $notify whether or not to notify the registrant about their approval.
1941
-     * @return void
1942
-     */
1943
-    protected function approve_registration($notify = false)
1944
-    {
1945
-        $this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1946
-    }
1947
-
1948
-
1949
-    /**
1950
-     *        decline_registration
1951
-     *
1952
-     * @access protected
1953
-     * @param bool $notify whether or not to notify the registrant about their status change.
1954
-     * @return void
1955
-     */
1956
-    protected function decline_registration($notify = false)
1957
-    {
1958
-        $this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1959
-    }
1960
-
1961
-
1962
-    /**
1963
-     *        cancel_registration
1964
-     *
1965
-     * @access protected
1966
-     * @param bool $notify whether or not to notify the registrant about their status change.
1967
-     * @return void
1968
-     */
1969
-    protected function cancel_registration($notify = false)
1970
-    {
1971
-        $this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1972
-    }
1973
-
1974
-
1975
-    /**
1976
-     *        not_approve_registration
1977
-     *
1978
-     * @access protected
1979
-     * @param bool $notify whether or not to notify the registrant about their status change.
1980
-     * @return void
1981
-     */
1982
-    protected function not_approve_registration($notify = false)
1983
-    {
1984
-        $this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1985
-    }
1986
-
1987
-
1988
-    /**
1989
-     *        decline_registration
1990
-     *
1991
-     * @access protected
1992
-     * @param bool $notify whether or not to notify the registrant about their status change.
1993
-     * @return void
1994
-     */
1995
-    protected function pending_registration($notify = false)
1996
-    {
1997
-        $this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1998
-    }
1999
-
2000
-
2001
-    /**
2002
-     * waitlist_registration
2003
-     *
2004
-     * @access protected
2005
-     * @param bool $notify whether or not to notify the registrant about their status change.
2006
-     * @return void
2007
-     */
2008
-    protected function wait_list_registration($notify = false)
2009
-    {
2010
-        $this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
2011
-    }
2012
-
2013
-
2014
-    /**
2015
-     *        generates HTML for the Registration main meta box
2016
-     *
2017
-     * @access public
2018
-     * @return void
2019
-     * @throws DomainException
2020
-     * @throws EE_Error
2021
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
2022
-     */
2023
-    public function _reg_details_meta_box()
2024
-    {
2025
-        EEH_Autoloader::register_line_item_display_autoloaders();
2026
-        EEH_Autoloader::register_line_item_filter_autoloaders();
2027
-        EE_Registry::instance()->load_helper('Line_Item');
2028
-        $transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
2029
-            : EE_Transaction::new_instance();
2030
-        $this->_session = $transaction->session_data();
2031
-        $filters        = new EE_Line_Item_Filter_Collection();
2032
-        //$filters->add( new EE_Non_Zero_Line_Item_Filter() );
2033
-        $filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2034
-        $line_item_filter_processor              = new EE_Line_Item_Filter_Processor($filters,
2035
-            $transaction->total_line_item());
2036
-        $filtered_line_item_tree                 = $line_item_filter_processor->process();
2037
-        $line_item_display                       = new EE_Line_Item_Display('reg_admin_table',
2038
-            'EE_Admin_Table_Registration_Line_Item_Display_Strategy');
2039
-        $this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2040
-            $filtered_line_item_tree,
2041
-            array('EE_Registration' => $this->_registration)
2042
-        );
2043
-        $attendee                                = $this->_registration->attendee();
2044
-        if (EE_Registry::instance()->CAP->current_user_can(
2045
-            'ee_read_transaction',
2046
-            'espresso_transactions_view_transaction'
2047
-        )) {
2048
-            $this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2049
-                EE_Admin_Page::add_query_args_and_nonce(
2050
-                    array(
2051
-                        'action' => 'view_transaction',
2052
-                        'TXN_ID' => $transaction->ID(),
2053
-                    ),
2054
-                    TXN_ADMIN_URL
2055
-                ),
2056
-                esc_html__(' View Transaction', 'event_espresso'),
2057
-                'button secondary-button right',
2058
-                'dashicons dashicons-cart'
2059
-            );
2060
-        } else {
2061
-            $this->_template_args['view_transaction_button'] = '';
2062
-        }
2063
-        if ($attendee instanceof EE_Attendee
2064
-            && EE_Registry::instance()->CAP->current_user_can(
2065
-                'ee_send_message',
2066
-                'espresso_registrations_resend_registration'
2067
-            )
2068
-        ) {
2069
-            $this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2070
-                EE_Admin_Page::add_query_args_and_nonce(
2071
-                    array(
2072
-                        'action'      => 'resend_registration',
2073
-                        '_REG_ID'     => $this->_registration->ID(),
2074
-                        'redirect_to' => 'view_registration',
2075
-                    ),
2076
-                    REG_ADMIN_URL
2077
-                ),
2078
-                esc_html__(' Resend Registration', 'event_espresso'),
2079
-                'button secondary-button right',
2080
-                'dashicons dashicons-email-alt'
2081
-            );
2082
-        } else {
2083
-            $this->_template_args['resend_registration_button'] = '';
2084
-        }
2085
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2086
-        $payment                               = $transaction->get_first_related('Payment');
2087
-        $payment                               = ! $payment instanceof EE_Payment
2088
-            ? EE_Payment::new_instance()
2089
-            : $payment;
2090
-        $payment_method                        = $payment->get_first_related('Payment_Method');
2091
-        $payment_method                        = ! $payment_method instanceof EE_Payment_Method
2092
-            ? EE_Payment_Method::new_instance()
2093
-            : $payment_method;
2094
-        $reg_details                           = array(
2095
-            'payment_method'       => $payment_method->name(),
2096
-            'response_msg'         => $payment->gateway_response(),
2097
-            'registration_id'      => $this->_registration->get('REG_code'),
2098
-            'registration_session' => $this->_registration->session_ID(),
2099
-            'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2100
-            'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2101
-        );
2102
-        if (isset($reg_details['registration_id'])) {
2103
-            $this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2104
-            $this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2105
-                'Registration ID',
2106
-                'event_espresso'
2107
-            );
2108
-            $this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2109
-        }
2110
-        if (isset($reg_details['payment_method'])) {
2111
-            $this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2112
-            $this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2113
-                'Most Recent Payment Method',
2114
-                'event_espresso'
2115
-            );
2116
-            $this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2117
-            $this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2118
-            $this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2119
-                'Payment method response',
2120
-                'event_espresso'
2121
-            );
2122
-            $this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2123
-        }
2124
-        $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2125
-        $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2126
-            'Registration Session',
2127
-            'event_espresso'
2128
-        );
2129
-        $this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2130
-        $this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2131
-        $this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2132
-            'Registration placed from IP',
2133
-            'event_espresso'
2134
-        );
2135
-        $this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2136
-        $this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2137
-        $this->_template_args['reg_details']['user_agent']['label']           = esc_html__('Registrant User Agent',
2138
-            'event_espresso');
2139
-        $this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2140
-        $this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2141
-            array(
2142
-                'action'   => 'default',
2143
-                'event_id' => $this->_registration->event_ID(),
2144
-            ),
2145
-            REG_ADMIN_URL
2146
-        );
2147
-        $this->_template_args['REG_ID']                                       = $this->_registration->ID();
2148
-        $this->_template_args['event_id']                                     = $this->_registration->event_ID();
2149
-        $template_path                                                        =
2150
-            REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2151
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2152
-    }
2153
-
2154
-
2155
-    /**
2156
-     * generates HTML for the Registration Questions meta box.
2157
-     * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2158
-     * otherwise uses new forms system
2159
-     *
2160
-     * @access public
2161
-     * @return void
2162
-     * @throws DomainException
2163
-     * @throws EE_Error
2164
-     */
2165
-    public function _reg_questions_meta_box()
2166
-    {
2167
-        //allow someone to override this method entirely
2168
-        if (apply_filters('FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default', true, $this,
2169
-            $this->_registration)) {
2170
-            $form                                              = $this->_get_reg_custom_questions_form(
2171
-                $this->_registration->ID()
2172
-            );
2173
-            $this->_template_args['att_questions']             = count($form->subforms()) > 0
2174
-                ? $form->get_html_and_js()
2175
-                : '';
2176
-            $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2177
-            $this->_template_args['REG_ID']                    = $this->_registration->ID();
2178
-            $template_path                                     =
2179
-                REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2180
-            echo EEH_Template::display_template($template_path, $this->_template_args, true);
2181
-        }
2182
-    }
2183
-
2184
-
2185
-    /**
2186
-     * form_before_question_group
2187
-     *
2188
-     * @deprecated    as of 4.8.32.rc.000
2189
-     * @access        public
2190
-     * @param        string $output
2191
-     * @return        string
2192
-     */
2193
-    public function form_before_question_group($output)
2194
-    {
2195
-        EE_Error::doing_it_wrong(
2196
-            __CLASS__ . '::' . __FUNCTION__,
2197
-            esc_html__(
2198
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2199
-                'event_espresso'
2200
-            ),
2201
-            '4.8.32.rc.000'
2202
-        );
2203
-        return '
1236
+		if (! empty($registration_status)) {
1237
+			$where['STS_ID'] = $registration_status;
1238
+		} else {
1239
+			//make sure we exclude incomplete registrations, but only if not trashed.
1240
+			if ($view === 'trash') {
1241
+				$where['REG_deleted'] = true;
1242
+			} elseif ($view === 'incomplete') {
1243
+				$where['STS_ID'] = EEM_Registration::status_id_incomplete;
1244
+			} else {
1245
+				$where['STS_ID'] = array('!=', EEM_Registration::status_id_incomplete);
1246
+			}
1247
+		}
1248
+		return $where;
1249
+	}
1250
+
1251
+
1252
+	/**
1253
+	 * Adds any provided date restraints to the where conditions for the registrations query.
1254
+	 *
1255
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1256
+	 * @return array
1257
+	 * @throws EE_Error
1258
+	 */
1259
+	protected function _add_date_to_where_conditions(array $request)
1260
+	{
1261
+		$where = array();
1262
+		$view = EEH_Array::is_set($request, 'status', '');
1263
+		$month_range             = ! empty($request['month_range'])
1264
+			? sanitize_text_field($request['month_range'])
1265
+			: '';
1266
+		$retrieve_for_today      = $view === 'today';
1267
+		$retrieve_for_this_month = $view === 'month';
1268
+
1269
+		if ($retrieve_for_today) {
1270
+			$now               = date('Y-m-d', current_time('timestamp'));
1271
+			$where['REG_date'] = array(
1272
+				'BETWEEN',
1273
+				array(
1274
+					EEM_Registration::instance()->convert_datetime_for_query(
1275
+						'REG_date',
1276
+						$now . ' 00:00:00',
1277
+						'Y-m-d H:i:s'
1278
+					),
1279
+					EEM_Registration::instance()->convert_datetime_for_query(
1280
+						'REG_date',
1281
+						$now . ' 23:59:59',
1282
+						'Y-m-d H:i:s'
1283
+					),
1284
+				),
1285
+			);
1286
+		} elseif ($retrieve_for_this_month) {
1287
+			$current_year_and_month = date('Y-m', current_time('timestamp'));
1288
+			$days_this_month        = date('t', current_time('timestamp'));
1289
+			$where['REG_date']      = array(
1290
+				'BETWEEN',
1291
+				array(
1292
+					EEM_Registration::instance()->convert_datetime_for_query(
1293
+						'REG_date',
1294
+						$current_year_and_month . '-01 00:00:00',
1295
+						'Y-m-d H:i:s'
1296
+					),
1297
+					EEM_Registration::instance()->convert_datetime_for_query(
1298
+						'REG_date',
1299
+						$current_year_and_month . '-' . $days_this_month . ' 23:59:59',
1300
+						'Y-m-d H:i:s'
1301
+					),
1302
+				),
1303
+			);
1304
+		} elseif ($month_range) {
1305
+			$pieces          = explode(' ', $month_range, 3);
1306
+			$month_requested = ! empty($pieces[0])
1307
+				? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0]))
1308
+				: '';
1309
+			$year_requested  = ! empty($pieces[1])
1310
+				? $pieces[1]
1311
+				: '';
1312
+			//if there is not a month or year then we can't go further
1313
+			if ($month_requested && $year_requested) {
1314
+				$days_in_month     = date('t', strtotime($year_requested . '-' . $month_requested . '-' . '01'));
1315
+				$where['REG_date'] = array(
1316
+					'BETWEEN',
1317
+					array(
1318
+						EEM_Registration::instance()->convert_datetime_for_query(
1319
+							'REG_date',
1320
+							$year_requested . '-' . $month_requested . '-01 00:00:00',
1321
+							'Y-m-d H:i:s'
1322
+						),
1323
+						EEM_Registration::instance()->convert_datetime_for_query(
1324
+							'REG_date',
1325
+							$year_requested . '-' . $month_requested . '-' . $days_in_month . ' 23:59:59',
1326
+							'Y-m-d H:i:s'
1327
+						),
1328
+					),
1329
+				);
1330
+			}
1331
+		}
1332
+		return $where;
1333
+	}
1334
+
1335
+
1336
+	/**
1337
+	 * Adds any provided search restraints to the where conditions for the registrations query
1338
+	 *
1339
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1340
+	 * @return array
1341
+	 */
1342
+	protected function _add_search_to_where_conditions(array $request)
1343
+	{
1344
+		$where = array();
1345
+		if (! empty($request['s'])) {
1346
+			$search_string = '%' . sanitize_text_field($request['s']) . '%';
1347
+			$where['OR*search_conditions'] = array(
1348
+				'Event.EVT_name'                          => array('LIKE', $search_string),
1349
+				'Event.EVT_desc'                          => array('LIKE', $search_string),
1350
+				'Event.EVT_short_desc'                    => array('LIKE', $search_string),
1351
+				'Attendee.ATT_full_name'                  => array('LIKE', $search_string),
1352
+				'Attendee.ATT_fname'                      => array('LIKE', $search_string),
1353
+				'Attendee.ATT_lname'                      => array('LIKE', $search_string),
1354
+				'Attendee.ATT_short_bio'                  => array('LIKE', $search_string),
1355
+				'Attendee.ATT_email'                      => array('LIKE', $search_string),
1356
+				'Attendee.ATT_address'                    => array('LIKE', $search_string),
1357
+				'Attendee.ATT_address2'                   => array('LIKE', $search_string),
1358
+				'Attendee.ATT_city'                       => array('LIKE', $search_string),
1359
+				'REG_final_price'                         => array('LIKE', $search_string),
1360
+				'REG_code'                                => array('LIKE', $search_string),
1361
+				'REG_count'                               => array('LIKE', $search_string),
1362
+				'REG_group_size'                          => array('LIKE', $search_string),
1363
+				'Ticket.TKT_name'                         => array('LIKE', $search_string),
1364
+				'Ticket.TKT_description'                  => array('LIKE', $search_string),
1365
+				'Transaction.Payment.PAY_txn_id_chq_nmbr' => array('LIKE', $search_string),
1366
+			);
1367
+		}
1368
+		return $where;
1369
+	}
1370
+
1371
+
1372
+	/**
1373
+	 * Sets up the where conditions for the registrations query.
1374
+	 *
1375
+	 * @param array $request
1376
+	 * @return array
1377
+	 * @throws EE_Error
1378
+	 */
1379
+	protected function _get_where_conditions_for_registrations_query($request)
1380
+	{
1381
+		return apply_filters(
1382
+			'FHEE__Registrations_Admin_Page___get_where_conditions_for_registrations_query',
1383
+			array_merge(
1384
+				$this->_add_event_id_to_where_conditions($request),
1385
+				$this->_add_category_id_to_where_conditions($request),
1386
+				$this->_add_datetime_id_to_where_conditions($request),
1387
+				$this->_add_registration_status_to_where_conditions($request),
1388
+				$this->_add_date_to_where_conditions($request),
1389
+				$this->_add_search_to_where_conditions($request)
1390
+			),
1391
+			$request
1392
+		);
1393
+	}
1394
+
1395
+
1396
+	/**
1397
+	 * Sets up the orderby for the registrations query.
1398
+	 *
1399
+	 * @return array
1400
+	 */
1401
+	protected function _get_orderby_for_registrations_query()
1402
+	{
1403
+		$orderby_field = ! empty($this->_req_data['orderby'])
1404
+			? sanitize_text_field($this->_req_data['orderby'])
1405
+			: '';
1406
+		switch ($orderby_field) {
1407
+			case '_REG_ID':
1408
+				$orderby_field = 'REG_ID';
1409
+				break;
1410
+			case '_Reg_status':
1411
+				$orderby_field = 'STS_ID';
1412
+				break;
1413
+			case 'ATT_fname':
1414
+				$orderby_field = array('Attendee.ATT_fname', 'Attendee.ATT_lname');
1415
+				break;
1416
+			case 'ATT_lname':
1417
+				$orderby_field = array('Attendee.ATT_lname', 'Attendee.ATT_fname');
1418
+				break;
1419
+			case 'event_name':
1420
+				$orderby_field = 'Event.EVT_name';
1421
+				break;
1422
+			case 'DTT_EVT_start':
1423
+				$orderby_field = 'Event.Datetime.DTT_EVT_start';
1424
+				break;
1425
+			default: //'REG_date'
1426
+				$orderby_field = 'REG_date';
1427
+		}
1428
+
1429
+		//order
1430
+		$order = ! empty($this->_req_data['order'])
1431
+			? sanitize_text_field($this->_req_data['order'])
1432
+			: 'DESC';
1433
+
1434
+		//mutate orderby_field
1435
+		$orderby_field = array_combine(
1436
+			(array) $orderby_field,
1437
+			array_fill(0, count($orderby_field), $order)
1438
+		);
1439
+		return array('order_by' => $orderby_field);
1440
+	}
1441
+
1442
+
1443
+	/**
1444
+	 * Sets up the limit for the registrations query.
1445
+	 *
1446
+	 * @param $per_page
1447
+	 * @return array
1448
+	 */
1449
+	protected function _get_limit($per_page)
1450
+	{
1451
+		$current_page = ! empty($this->_req_data['paged'])
1452
+			? absint($this->_req_data['paged'])
1453
+			: 1;
1454
+		$per_page     = ! empty($this->_req_data['perpage'])
1455
+			? $this->_req_data['perpage']
1456
+			: $per_page;
1457
+
1458
+		//-1 means return all results so get out if that's set.
1459
+		if ((int)$per_page === -1) {
1460
+			return array();
1461
+		}
1462
+		$per_page = absint($per_page);
1463
+		$offset   = ($current_page - 1) * $per_page;
1464
+		return array('limit' => array($offset, $per_page));
1465
+	}
1466
+
1467
+
1468
+	public function get_registration_status_array()
1469
+	{
1470
+		return self::$_reg_status;
1471
+	}
1472
+
1473
+
1474
+
1475
+
1476
+	/***************************************        REGISTRATION DETAILS        ***************************************/
1477
+	/**
1478
+	 *        generates HTML for the View Registration Details Admin page
1479
+	 *
1480
+	 * @access protected
1481
+	 * @return void
1482
+	 * @throws DomainException
1483
+	 * @throws EE_Error
1484
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1485
+	 */
1486
+	protected function _registration_details()
1487
+	{
1488
+		$this->_template_args = array();
1489
+		$this->_set_registration_object();
1490
+		if (is_object($this->_registration)) {
1491
+			$transaction                                   = $this->_registration->transaction()
1492
+				? $this->_registration->transaction()
1493
+				: EE_Transaction::new_instance();
1494
+			$this->_session                                = $transaction->session_data();
1495
+			$event_id                                      = $this->_registration->event_ID();
1496
+			$this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1497
+			$this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1498
+			$this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1499
+			$this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1500
+			$this->_template_args['grand_total']           = $transaction->total();
1501
+			$this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1502
+			// link back to overview
1503
+			$this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1504
+			$this->_template_args['registration']                = $this->_registration;
1505
+			$this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1506
+				array(
1507
+					'action'   => 'default',
1508
+					'event_id' => $event_id,
1509
+				),
1510
+				REG_ADMIN_URL
1511
+			);
1512
+			$this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1513
+				array(
1514
+					'action' => 'default',
1515
+					'EVT_ID' => $event_id,
1516
+					'page'   => 'espresso_transactions',
1517
+				),
1518
+				admin_url('admin.php')
1519
+			);
1520
+			$this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1521
+				array(
1522
+					'page'   => 'espresso_events',
1523
+					'action' => 'edit',
1524
+					'post'   => $event_id,
1525
+				),
1526
+				admin_url('admin.php')
1527
+			);
1528
+			//next and previous links
1529
+			$next_reg                                      = $this->_registration->next(
1530
+				null,
1531
+				array(),
1532
+				'REG_ID'
1533
+			);
1534
+			$this->_template_args['next_registration']     = $next_reg
1535
+				? $this->_next_link(
1536
+					EE_Admin_Page::add_query_args_and_nonce(
1537
+						array(
1538
+							'action'  => 'view_registration',
1539
+							'_REG_ID' => $next_reg['REG_ID'],
1540
+						),
1541
+						REG_ADMIN_URL
1542
+					),
1543
+					'dashicons dashicons-arrow-right ee-icon-size-22'
1544
+				)
1545
+				: '';
1546
+			$previous_reg                                  = $this->_registration->previous(
1547
+				null,
1548
+				array(),
1549
+				'REG_ID'
1550
+			);
1551
+			$this->_template_args['previous_registration'] = $previous_reg
1552
+				? $this->_previous_link(
1553
+					EE_Admin_Page::add_query_args_and_nonce(
1554
+						array(
1555
+							'action'  => 'view_registration',
1556
+							'_REG_ID' => $previous_reg['REG_ID'],
1557
+						),
1558
+						REG_ADMIN_URL
1559
+					),
1560
+					'dashicons dashicons-arrow-left ee-icon-size-22'
1561
+				)
1562
+				: '';
1563
+			// grab header
1564
+			$template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1565
+			$this->_template_args['REG_ID']            = $this->_registration->ID();
1566
+			$this->_template_args['admin_page_header'] = EEH_Template::display_template(
1567
+				$template_path,
1568
+				$this->_template_args,
1569
+				true
1570
+			);
1571
+		} else {
1572
+			$this->_template_args['admin_page_header'] = $this->display_espresso_notices();
1573
+		}
1574
+		// the details template wrapper
1575
+		$this->display_admin_page_with_sidebar();
1576
+	}
1577
+
1578
+
1579
+	protected function _registration_details_metaboxes()
1580
+	{
1581
+		do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1582
+		$this->_set_registration_object();
1583
+		$attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1584
+		add_meta_box('edit-reg-status-mbox', esc_html__('Registration Status', 'event_espresso'),
1585
+			array($this, 'set_reg_status_buttons_metabox'), $this->wp_page_slug, 'normal', 'high');
1586
+		add_meta_box('edit-reg-details-mbox', esc_html__('Registration Details', 'event_espresso'),
1587
+			array($this, '_reg_details_meta_box'), $this->wp_page_slug, 'normal', 'high');
1588
+		if ($attendee instanceof EE_Attendee
1589
+			&& EE_Registry::instance()->CAP->current_user_can(
1590
+				'ee_edit_registration',
1591
+				'edit-reg-questions-mbox',
1592
+				$this->_registration->ID()
1593
+			)
1594
+		) {
1595
+			add_meta_box(
1596
+				'edit-reg-questions-mbox',
1597
+				esc_html__('Registration Form Answers', 'event_espresso'),
1598
+				array($this, '_reg_questions_meta_box'),
1599
+				$this->wp_page_slug,
1600
+				'normal',
1601
+				'high'
1602
+			);
1603
+		}
1604
+		add_meta_box(
1605
+			'edit-reg-registrant-mbox',
1606
+			esc_html__('Contact Details', 'event_espresso'),
1607
+			array($this, '_reg_registrant_side_meta_box'),
1608
+			$this->wp_page_slug,
1609
+			'side',
1610
+			'high'
1611
+		);
1612
+		if ($this->_registration->group_size() > 1) {
1613
+			add_meta_box(
1614
+				'edit-reg-attendees-mbox',
1615
+				esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1616
+				array($this, '_reg_attendees_meta_box'),
1617
+				$this->wp_page_slug,
1618
+				'normal',
1619
+				'high'
1620
+			);
1621
+		}
1622
+	}
1623
+
1624
+
1625
+	/**
1626
+	 * set_reg_status_buttons_metabox
1627
+	 *
1628
+	 * @access protected
1629
+	 * @return string
1630
+	 * @throws \EE_Error
1631
+	 */
1632
+	public function set_reg_status_buttons_metabox()
1633
+	{
1634
+		$this->_set_registration_object();
1635
+		$change_reg_status_form = $this->_generate_reg_status_change_form();
1636
+		echo $change_reg_status_form->form_open(
1637
+			self::add_query_args_and_nonce(
1638
+				array(
1639
+					'action' => 'change_reg_status',
1640
+				),
1641
+				REG_ADMIN_URL
1642
+			)
1643
+		);
1644
+		echo $change_reg_status_form->get_html();
1645
+		echo $change_reg_status_form->form_close();
1646
+	}
1647
+
1648
+
1649
+
1650
+	/**
1651
+	 * @return EE_Form_Section_Proper
1652
+	 * @throws EE_Error
1653
+	 */
1654
+	protected function _generate_reg_status_change_form()
1655
+	{
1656
+		return new EE_Form_Section_Proper(array(
1657
+			'name'            => 'reg_status_change_form',
1658
+			'html_id'         => 'reg-status-change-form',
1659
+			'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1660
+			'subsections'     => array(
1661
+				'return'             => new EE_Hidden_Input(array(
1662
+					'name'    => 'return',
1663
+					'default' => 'view_registration',
1664
+				)),
1665
+				'REG_ID'             => new EE_Hidden_Input(array(
1666
+					'name'    => 'REG_ID',
1667
+					'default' => $this->_registration->ID(),
1668
+				)),
1669
+				'current_status'     => new EE_Form_Section_HTML(
1670
+					EEH_HTML::tr(
1671
+						EEH_HTML::th(
1672
+							EEH_HTML::label(
1673
+								EEH_HTML::strong(esc_html__('Current Registration Status', 'event_espresso')
1674
+								)
1675
+							)
1676
+						)
1677
+						. EEH_HTML::td(
1678
+							EEH_HTML::strong(
1679
+								$this->_registration->pretty_status(),
1680
+								'',
1681
+								'status-' . $this->_registration->status_ID(),
1682
+								'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1683
+							)
1684
+						)
1685
+					)
1686
+				),
1687
+				'reg_status'         => new EE_Select_Input(
1688
+					$this->_get_reg_statuses(),
1689
+					array(
1690
+						'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1691
+						'default'         => $this->_registration->status_ID(),
1692
+					)
1693
+				),
1694
+				'send_notifications' => new EE_Yes_No_Input(
1695
+					array(
1696
+						'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1697
+						'default'         => false,
1698
+						'html_help_text'  => esc_html__(
1699
+							'If set to "Yes", then the related messages will be sent to the registrant.',
1700
+							'event_espresso'
1701
+						),
1702
+					)
1703
+				),
1704
+				'submit'             => new EE_Submit_Input(
1705
+					array(
1706
+						'html_class'      => 'button-primary',
1707
+						'html_label_text' => '&nbsp;',
1708
+						'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1709
+					)
1710
+				),
1711
+			),
1712
+		));
1713
+	}
1714
+
1715
+
1716
+	/**
1717
+	 * Returns an array of all the buttons for the various statuses and switch status actions
1718
+	 *
1719
+	 * @return array
1720
+	 * @throws EE_Error
1721
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1722
+	 */
1723
+	protected function _get_reg_statuses()
1724
+	{
1725
+		$reg_status_array = EEM_Registration::instance()->reg_status_array();
1726
+		unset ($reg_status_array[EEM_Registration::status_id_incomplete]);
1727
+		// get current reg status
1728
+		$current_status = $this->_registration->status_ID();
1729
+		// is registration for free event? This will determine whether to display the pending payment option
1730
+		if (
1731
+			$current_status !== EEM_Registration::status_id_pending_payment
1732
+			&& $this->_registration->transaction()->is_free()
1733
+		) {
1734
+			unset($reg_status_array[EEM_Registration::status_id_pending_payment]);
1735
+		}
1736
+		return EEM_Status::instance()->localized_status($reg_status_array, false, 'sentence');
1737
+	}
1738
+
1739
+
1740
+
1741
+	/**
1742
+	 * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1743
+	 *
1744
+	 * @param bool $status REG status given for changing registrations to.
1745
+	 * @param bool $notify Whether to send messages notifications or not.
1746
+	 * @return array  (array with reg_id(s) updated and whether update was successful.
1747
+	 * @throws \EE_Error
1748
+	 */
1749
+	protected function _set_registration_status_from_request($status = false, $notify = false)
1750
+	{
1751
+		if (isset($this->_req_data['reg_status_change_form'])) {
1752
+			$REG_IDs = isset($this->_req_data['reg_status_change_form']['REG_ID'])
1753
+				? (array)$this->_req_data['reg_status_change_form']['REG_ID'] : array();
1754
+		} else {
1755
+			$REG_IDs = isset($this->_req_data['_REG_ID']) ? (array)$this->_req_data['_REG_ID'] : array();
1756
+		}
1757
+		$success = $this->_set_registration_status($REG_IDs, $status);
1758
+		//notify?
1759
+		if ($success
1760
+			&& $notify
1761
+			&& EE_Registry::instance()->CAP->current_user_can(
1762
+				'ee_send_message',
1763
+				'espresso_registrations_resend_registration'
1764
+			)
1765
+		) {
1766
+			$this->_process_resend_registration();
1767
+		}
1768
+		return $success;
1769
+	}
1770
+
1771
+
1772
+
1773
+	/**
1774
+	 * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1775
+	 * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1776
+	 *
1777
+	 * @param array $REG_IDs
1778
+	 * @param bool  $status
1779
+	 * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1780
+	 * @throws \RuntimeException
1781
+	 * @throws \EE_Error
1782
+	 *               the array of updated registrations).
1783
+	 * @throws EE_Error
1784
+	 * @throws RuntimeException
1785
+	 */
1786
+	protected function _set_registration_status($REG_IDs = array(), $status = false)
1787
+	{
1788
+		$success = false;
1789
+		// typecast $REG_IDs
1790
+		$REG_IDs = (array)$REG_IDs;
1791
+		if ( ! empty($REG_IDs)) {
1792
+			$success = true;
1793
+			// set default status if none is passed
1794
+			$status = $status ? $status : EEM_Registration::status_id_pending_payment;
1795
+			// sanitize $REG_IDs
1796
+			$REG_IDs = array_filter($REG_IDs, 'absint');
1797
+			//loop through REG_ID's and change status
1798
+			foreach ($REG_IDs as $REG_ID) {
1799
+				$registration = EEM_Registration::instance()->get_one_by_ID($REG_ID);
1800
+				if ($registration instanceof EE_Registration) {
1801
+					$registration->set_status($status);
1802
+					$result = $registration->save();
1803
+					// verifying explicit fails because update *may* just return 0 for 0 rows affected
1804
+					$success = $result !== false ? $success : false;
1805
+				}
1806
+			}
1807
+		}
1808
+		//reset _req_data['_REG_ID'] for any potential future messages notifications
1809
+		$this->_req_data['_REG_ID'] = $REG_IDs;
1810
+		//return $success and processed registrations
1811
+		return array('REG_ID' => $REG_IDs, 'success' => $success);
1812
+	}
1813
+
1814
+
1815
+	/**
1816
+	 * Common logic for setting up success message and redirecting to appropriate route
1817
+	 *
1818
+	 * @param  string $STS_ID status id for the registration changed to
1819
+	 * @param   bool  $notify indicates whether the _set_registration_status_from_request does notifications or not.
1820
+	 * @return void
1821
+	 */
1822
+	protected function _reg_status_change_return($STS_ID, $notify = false)
1823
+	{
1824
+		$result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1825
+			: array('success' => false);
1826
+		$success = isset($result['success']) && $result['success'];
1827
+		//setup success message
1828
+		if ($success) {
1829
+			if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1830
+				$msg = sprintf(esc_html__('Registration status has been set to %s', 'event_espresso'),
1831
+					EEH_Template::pretty_status($STS_ID, false, 'lower'));
1832
+			} else {
1833
+				$msg = sprintf(esc_html__('Registrations have been set to %s.', 'event_espresso'),
1834
+					EEH_Template::pretty_status($STS_ID, false, 'lower'));
1835
+			}
1836
+			EE_Error::add_success($msg);
1837
+		} else {
1838
+			EE_Error::add_error(
1839
+				esc_html__(
1840
+					'Something went wrong, and the status was not changed',
1841
+					'event_espresso'
1842
+				), __FILE__, __LINE__, __FUNCTION__
1843
+			);
1844
+		}
1845
+		if (isset($this->_req_data['return']) && $this->_req_data['return'] == 'view_registration') {
1846
+			$route = array('action' => 'view_registration', '_REG_ID' => reset($result['REG_ID']));
1847
+		} else {
1848
+			$route = array('action' => 'default');
1849
+		}
1850
+		//unset nonces
1851
+		foreach ($this->_req_data as $ref => $value) {
1852
+			if (strpos($ref, 'nonce') !== false) {
1853
+				unset($this->_req_data[$ref]);
1854
+				continue;
1855
+			}
1856
+			$value                 = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
1857
+			$this->_req_data[$ref] = $value;
1858
+		}
1859
+		//merge request vars so that the reloaded list table contains any existing filter query params
1860
+		$route = array_merge($this->_req_data, $route);
1861
+		$this->_redirect_after_action($success, '', '', $route, true);
1862
+	}
1863
+
1864
+
1865
+	/**
1866
+	 * incoming reg status change from reg details page.
1867
+	 *
1868
+	 * @return void
1869
+	 */
1870
+	protected function _change_reg_status()
1871
+	{
1872
+		$this->_req_data['return'] = 'view_registration';
1873
+		//set notify based on whether the send notifications toggle is set or not
1874
+		$notify = ! empty($this->_req_data['reg_status_change_form']['send_notifications']);
1875
+		//$notify = ! empty( $this->_req_data['txn_reg_status_change']['send_notifications'] );
1876
+		$this->_req_data['reg_status_change_form']['reg_status'] = isset($this->_req_data['reg_status_change_form']['reg_status'])
1877
+			? $this->_req_data['reg_status_change_form']['reg_status'] : '';
1878
+		switch ($this->_req_data['reg_status_change_form']['reg_status']) {
1879
+			case EEM_Registration::status_id_approved :
1880
+			case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence') :
1881
+				$this->approve_registration($notify);
1882
+				break;
1883
+			case EEM_Registration::status_id_pending_payment :
1884
+			case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence') :
1885
+				$this->pending_registration($notify);
1886
+				break;
1887
+			case EEM_Registration::status_id_not_approved :
1888
+			case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence') :
1889
+				$this->not_approve_registration($notify);
1890
+				break;
1891
+			case EEM_Registration::status_id_declined :
1892
+			case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence') :
1893
+				$this->decline_registration($notify);
1894
+				break;
1895
+			case EEM_Registration::status_id_cancelled :
1896
+			case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence') :
1897
+				$this->cancel_registration($notify);
1898
+				break;
1899
+			case EEM_Registration::status_id_wait_list :
1900
+			case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence') :
1901
+				$this->wait_list_registration($notify);
1902
+				break;
1903
+			case EEM_Registration::status_id_incomplete :
1904
+			default :
1905
+				$result['success'] = false;
1906
+				unset($this->_req_data['return']);
1907
+				$this->_reg_status_change_return('', false);
1908
+				break;
1909
+		}
1910
+	}
1911
+
1912
+
1913
+	/**
1914
+	 * Callback for bulk action routes.
1915
+	 * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1916
+	 * method was chosen so there is one central place all the registration status bulk actions are going through.
1917
+	 * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1918
+	 * when an action is happening on just a single registration).
1919
+	 * @param      $action
1920
+	 * @param bool $notify
1921
+	 */
1922
+	protected function bulk_action_on_registrations($action, $notify = false) {
1923
+		do_action(
1924
+			'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1925
+			$this,
1926
+			$action,
1927
+			$notify
1928
+		);
1929
+		$method = $action . '_registration';
1930
+		if (method_exists($this, $method)) {
1931
+			$this->$method($notify);
1932
+		}
1933
+	}
1934
+
1935
+
1936
+	/**
1937
+	 * approve_registration
1938
+	 *
1939
+	 * @access protected
1940
+	 * @param bool $notify whether or not to notify the registrant about their approval.
1941
+	 * @return void
1942
+	 */
1943
+	protected function approve_registration($notify = false)
1944
+	{
1945
+		$this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1946
+	}
1947
+
1948
+
1949
+	/**
1950
+	 *        decline_registration
1951
+	 *
1952
+	 * @access protected
1953
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1954
+	 * @return void
1955
+	 */
1956
+	protected function decline_registration($notify = false)
1957
+	{
1958
+		$this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1959
+	}
1960
+
1961
+
1962
+	/**
1963
+	 *        cancel_registration
1964
+	 *
1965
+	 * @access protected
1966
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1967
+	 * @return void
1968
+	 */
1969
+	protected function cancel_registration($notify = false)
1970
+	{
1971
+		$this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1972
+	}
1973
+
1974
+
1975
+	/**
1976
+	 *        not_approve_registration
1977
+	 *
1978
+	 * @access protected
1979
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1980
+	 * @return void
1981
+	 */
1982
+	protected function not_approve_registration($notify = false)
1983
+	{
1984
+		$this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1985
+	}
1986
+
1987
+
1988
+	/**
1989
+	 *        decline_registration
1990
+	 *
1991
+	 * @access protected
1992
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1993
+	 * @return void
1994
+	 */
1995
+	protected function pending_registration($notify = false)
1996
+	{
1997
+		$this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1998
+	}
1999
+
2000
+
2001
+	/**
2002
+	 * waitlist_registration
2003
+	 *
2004
+	 * @access protected
2005
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2006
+	 * @return void
2007
+	 */
2008
+	protected function wait_list_registration($notify = false)
2009
+	{
2010
+		$this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
2011
+	}
2012
+
2013
+
2014
+	/**
2015
+	 *        generates HTML for the Registration main meta box
2016
+	 *
2017
+	 * @access public
2018
+	 * @return void
2019
+	 * @throws DomainException
2020
+	 * @throws EE_Error
2021
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
2022
+	 */
2023
+	public function _reg_details_meta_box()
2024
+	{
2025
+		EEH_Autoloader::register_line_item_display_autoloaders();
2026
+		EEH_Autoloader::register_line_item_filter_autoloaders();
2027
+		EE_Registry::instance()->load_helper('Line_Item');
2028
+		$transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
2029
+			: EE_Transaction::new_instance();
2030
+		$this->_session = $transaction->session_data();
2031
+		$filters        = new EE_Line_Item_Filter_Collection();
2032
+		//$filters->add( new EE_Non_Zero_Line_Item_Filter() );
2033
+		$filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2034
+		$line_item_filter_processor              = new EE_Line_Item_Filter_Processor($filters,
2035
+			$transaction->total_line_item());
2036
+		$filtered_line_item_tree                 = $line_item_filter_processor->process();
2037
+		$line_item_display                       = new EE_Line_Item_Display('reg_admin_table',
2038
+			'EE_Admin_Table_Registration_Line_Item_Display_Strategy');
2039
+		$this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2040
+			$filtered_line_item_tree,
2041
+			array('EE_Registration' => $this->_registration)
2042
+		);
2043
+		$attendee                                = $this->_registration->attendee();
2044
+		if (EE_Registry::instance()->CAP->current_user_can(
2045
+			'ee_read_transaction',
2046
+			'espresso_transactions_view_transaction'
2047
+		)) {
2048
+			$this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2049
+				EE_Admin_Page::add_query_args_and_nonce(
2050
+					array(
2051
+						'action' => 'view_transaction',
2052
+						'TXN_ID' => $transaction->ID(),
2053
+					),
2054
+					TXN_ADMIN_URL
2055
+				),
2056
+				esc_html__(' View Transaction', 'event_espresso'),
2057
+				'button secondary-button right',
2058
+				'dashicons dashicons-cart'
2059
+			);
2060
+		} else {
2061
+			$this->_template_args['view_transaction_button'] = '';
2062
+		}
2063
+		if ($attendee instanceof EE_Attendee
2064
+			&& EE_Registry::instance()->CAP->current_user_can(
2065
+				'ee_send_message',
2066
+				'espresso_registrations_resend_registration'
2067
+			)
2068
+		) {
2069
+			$this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2070
+				EE_Admin_Page::add_query_args_and_nonce(
2071
+					array(
2072
+						'action'      => 'resend_registration',
2073
+						'_REG_ID'     => $this->_registration->ID(),
2074
+						'redirect_to' => 'view_registration',
2075
+					),
2076
+					REG_ADMIN_URL
2077
+				),
2078
+				esc_html__(' Resend Registration', 'event_espresso'),
2079
+				'button secondary-button right',
2080
+				'dashicons dashicons-email-alt'
2081
+			);
2082
+		} else {
2083
+			$this->_template_args['resend_registration_button'] = '';
2084
+		}
2085
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2086
+		$payment                               = $transaction->get_first_related('Payment');
2087
+		$payment                               = ! $payment instanceof EE_Payment
2088
+			? EE_Payment::new_instance()
2089
+			: $payment;
2090
+		$payment_method                        = $payment->get_first_related('Payment_Method');
2091
+		$payment_method                        = ! $payment_method instanceof EE_Payment_Method
2092
+			? EE_Payment_Method::new_instance()
2093
+			: $payment_method;
2094
+		$reg_details                           = array(
2095
+			'payment_method'       => $payment_method->name(),
2096
+			'response_msg'         => $payment->gateway_response(),
2097
+			'registration_id'      => $this->_registration->get('REG_code'),
2098
+			'registration_session' => $this->_registration->session_ID(),
2099
+			'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2100
+			'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2101
+		);
2102
+		if (isset($reg_details['registration_id'])) {
2103
+			$this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2104
+			$this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2105
+				'Registration ID',
2106
+				'event_espresso'
2107
+			);
2108
+			$this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2109
+		}
2110
+		if (isset($reg_details['payment_method'])) {
2111
+			$this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2112
+			$this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2113
+				'Most Recent Payment Method',
2114
+				'event_espresso'
2115
+			);
2116
+			$this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2117
+			$this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2118
+			$this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2119
+				'Payment method response',
2120
+				'event_espresso'
2121
+			);
2122
+			$this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2123
+		}
2124
+		$this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2125
+		$this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2126
+			'Registration Session',
2127
+			'event_espresso'
2128
+		);
2129
+		$this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2130
+		$this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2131
+		$this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2132
+			'Registration placed from IP',
2133
+			'event_espresso'
2134
+		);
2135
+		$this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2136
+		$this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2137
+		$this->_template_args['reg_details']['user_agent']['label']           = esc_html__('Registrant User Agent',
2138
+			'event_espresso');
2139
+		$this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2140
+		$this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2141
+			array(
2142
+				'action'   => 'default',
2143
+				'event_id' => $this->_registration->event_ID(),
2144
+			),
2145
+			REG_ADMIN_URL
2146
+		);
2147
+		$this->_template_args['REG_ID']                                       = $this->_registration->ID();
2148
+		$this->_template_args['event_id']                                     = $this->_registration->event_ID();
2149
+		$template_path                                                        =
2150
+			REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2151
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2152
+	}
2153
+
2154
+
2155
+	/**
2156
+	 * generates HTML for the Registration Questions meta box.
2157
+	 * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2158
+	 * otherwise uses new forms system
2159
+	 *
2160
+	 * @access public
2161
+	 * @return void
2162
+	 * @throws DomainException
2163
+	 * @throws EE_Error
2164
+	 */
2165
+	public function _reg_questions_meta_box()
2166
+	{
2167
+		//allow someone to override this method entirely
2168
+		if (apply_filters('FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default', true, $this,
2169
+			$this->_registration)) {
2170
+			$form                                              = $this->_get_reg_custom_questions_form(
2171
+				$this->_registration->ID()
2172
+			);
2173
+			$this->_template_args['att_questions']             = count($form->subforms()) > 0
2174
+				? $form->get_html_and_js()
2175
+				: '';
2176
+			$this->_template_args['reg_questions_form_action'] = 'edit_registration';
2177
+			$this->_template_args['REG_ID']                    = $this->_registration->ID();
2178
+			$template_path                                     =
2179
+				REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2180
+			echo EEH_Template::display_template($template_path, $this->_template_args, true);
2181
+		}
2182
+	}
2183
+
2184
+
2185
+	/**
2186
+	 * form_before_question_group
2187
+	 *
2188
+	 * @deprecated    as of 4.8.32.rc.000
2189
+	 * @access        public
2190
+	 * @param        string $output
2191
+	 * @return        string
2192
+	 */
2193
+	public function form_before_question_group($output)
2194
+	{
2195
+		EE_Error::doing_it_wrong(
2196
+			__CLASS__ . '::' . __FUNCTION__,
2197
+			esc_html__(
2198
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2199
+				'event_espresso'
2200
+			),
2201
+			'4.8.32.rc.000'
2202
+		);
2203
+		return '
2204 2204
 	<table class="form-table ee-width-100">
2205 2205
 		<tbody>
2206 2206
 			';
2207
-    }
2208
-
2209
-
2210
-    /**
2211
-     * form_after_question_group
2212
-     *
2213
-     * @deprecated    as of 4.8.32.rc.000
2214
-     * @access        public
2215
-     * @param        string $output
2216
-     * @return        string
2217
-     */
2218
-    public function form_after_question_group($output)
2219
-    {
2220
-        EE_Error::doing_it_wrong(
2221
-            __CLASS__ . '::' . __FUNCTION__,
2222
-            esc_html__(
2223
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2224
-                'event_espresso'
2225
-            ),
2226
-            '4.8.32.rc.000'
2227
-        );
2228
-        return '
2207
+	}
2208
+
2209
+
2210
+	/**
2211
+	 * form_after_question_group
2212
+	 *
2213
+	 * @deprecated    as of 4.8.32.rc.000
2214
+	 * @access        public
2215
+	 * @param        string $output
2216
+	 * @return        string
2217
+	 */
2218
+	public function form_after_question_group($output)
2219
+	{
2220
+		EE_Error::doing_it_wrong(
2221
+			__CLASS__ . '::' . __FUNCTION__,
2222
+			esc_html__(
2223
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2224
+				'event_espresso'
2225
+			),
2226
+			'4.8.32.rc.000'
2227
+		);
2228
+		return '
2229 2229
 			<tr class="hide-if-no-js">
2230 2230
 				<th> </th>
2231 2231
 				<td class="reg-admin-edit-attendee-question-td">
2232 2232
 					<a class="reg-admin-edit-attendee-question-lnk" href="#" title="'
2233
-               . esc_attr__('click to edit question', 'event_espresso')
2234
-               . '">
2233
+			   . esc_attr__('click to edit question', 'event_espresso')
2234
+			   . '">
2235 2235
 						<span class="reg-admin-edit-question-group-spn lt-grey-txt">'
2236
-               . esc_html__('edit the above question group', 'event_espresso')
2237
-               . '</span>
2236
+			   . esc_html__('edit the above question group', 'event_espresso')
2237
+			   . '</span>
2238 2238
 						<div class="dashicons dashicons-edit"></div>
2239 2239
 					</a>
2240 2240
 				</td>
@@ -2242,558 +2242,558 @@  discard block
 block discarded – undo
2242 2242
 		</tbody>
2243 2243
 	</table>
2244 2244
 ';
2245
-    }
2246
-
2247
-
2248
-    /**
2249
-     * form_form_field_label_wrap
2250
-     *
2251
-     * @deprecated    as of 4.8.32.rc.000
2252
-     * @access        public
2253
-     * @param        string $label
2254
-     * @return        string
2255
-     */
2256
-    public function form_form_field_label_wrap($label)
2257
-    {
2258
-        EE_Error::doing_it_wrong(
2259
-            __CLASS__ . '::' . __FUNCTION__,
2260
-            esc_html__(
2261
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2262
-                'event_espresso'
2263
-            ),
2264
-            '4.8.32.rc.000'
2265
-        );
2266
-        return '
2245
+	}
2246
+
2247
+
2248
+	/**
2249
+	 * form_form_field_label_wrap
2250
+	 *
2251
+	 * @deprecated    as of 4.8.32.rc.000
2252
+	 * @access        public
2253
+	 * @param        string $label
2254
+	 * @return        string
2255
+	 */
2256
+	public function form_form_field_label_wrap($label)
2257
+	{
2258
+		EE_Error::doing_it_wrong(
2259
+			__CLASS__ . '::' . __FUNCTION__,
2260
+			esc_html__(
2261
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2262
+				'event_espresso'
2263
+			),
2264
+			'4.8.32.rc.000'
2265
+		);
2266
+		return '
2267 2267
 			<tr>
2268 2268
 				<th>
2269 2269
 					' . $label . '
2270 2270
 				</th>';
2271
-    }
2272
-
2273
-
2274
-    /**
2275
-     * form_form_field_input__wrap
2276
-     *
2277
-     * @deprecated    as of 4.8.32.rc.000
2278
-     * @access        public
2279
-     * @param        string $input
2280
-     * @return        string
2281
-     */
2282
-    public function form_form_field_input__wrap($input)
2283
-    {
2284
-        EE_Error::doing_it_wrong(
2285
-            __CLASS__ . '::' . __FUNCTION__,
2286
-            esc_html__(
2287
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2288
-                'event_espresso'
2289
-            ),
2290
-            '4.8.32.rc.000'
2291
-        );
2292
-        return '
2271
+	}
2272
+
2273
+
2274
+	/**
2275
+	 * form_form_field_input__wrap
2276
+	 *
2277
+	 * @deprecated    as of 4.8.32.rc.000
2278
+	 * @access        public
2279
+	 * @param        string $input
2280
+	 * @return        string
2281
+	 */
2282
+	public function form_form_field_input__wrap($input)
2283
+	{
2284
+		EE_Error::doing_it_wrong(
2285
+			__CLASS__ . '::' . __FUNCTION__,
2286
+			esc_html__(
2287
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2288
+				'event_espresso'
2289
+			),
2290
+			'4.8.32.rc.000'
2291
+		);
2292
+		return '
2293 2293
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2294 2294
 					' . $input . '
2295 2295
 				</td>
2296 2296
 			</tr>';
2297
-    }
2298
-
2299
-
2300
-    /**
2301
-     * Updates the registration's custom questions according to the form info, if the form is submitted.
2302
-     * If it's not a post, the "view_registrations" route will be called next on the SAME request
2303
-     * to display the page
2304
-     *
2305
-     * @access protected
2306
-     * @return void
2307
-     * @throws EE_Error
2308
-     */
2309
-    protected function _update_attendee_registration_form()
2310
-    {
2311
-        do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2312
-        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
2313
-            $REG_ID  = isset($this->_req_data['_REG_ID']) ? absint($this->_req_data['_REG_ID']) : false;
2314
-            $success = $this->_save_reg_custom_questions_form($REG_ID);
2315
-            if ($success) {
2316
-                $what  = esc_html__('Registration Form', 'event_espresso');
2317
-                $route = $REG_ID ? array('action' => 'view_registration', '_REG_ID' => $REG_ID)
2318
-                    : array('action' => 'default');
2319
-                $this->_redirect_after_action($success, $what, esc_html__('updated', 'event_espresso'), $route);
2320
-            }
2321
-        }
2322
-    }
2323
-
2324
-
2325
-    /**
2326
-     * Gets the form for saving registrations custom questions (if done
2327
-     * previously retrieves the cached form object, which may have validation errors in it)
2328
-     *
2329
-     * @param int $REG_ID
2330
-     * @return EE_Registration_Custom_Questions_Form
2331
-     * @throws EE_Error
2332
-     */
2333
-    protected function _get_reg_custom_questions_form($REG_ID)
2334
-    {
2335
-        if ( ! $this->_reg_custom_questions_form) {
2336
-            require_once(REG_ADMIN . 'form_sections' . DS . 'EE_Registration_Custom_Questions_Form.form.php');
2337
-            $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2338
-                EEM_Registration::instance()->get_one_by_ID($REG_ID)
2339
-            );
2340
-            $this->_reg_custom_questions_form->_construct_finalize(null, null);
2341
-        }
2342
-        return $this->_reg_custom_questions_form;
2343
-    }
2344
-
2345
-
2346
-    /**
2347
-     * Saves
2348
-     *
2349
-     * @access private
2350
-     * @param bool $REG_ID
2351
-     * @return bool
2352
-     * @throws EE_Error
2353
-     */
2354
-    private function _save_reg_custom_questions_form($REG_ID = false)
2355
-    {
2356
-        if ( ! $REG_ID) {
2357
-            EE_Error::add_error(
2358
-                esc_html__(
2359
-                    'An error occurred. No registration ID was received.', 'event_espresso'),
2360
-                __FILE__, __FUNCTION__, __LINE__
2361
-            );
2362
-        }
2363
-        $form = $this->_get_reg_custom_questions_form($REG_ID);
2364
-        $form->receive_form_submission($this->_req_data);
2365
-        $success = false;
2366
-        if ($form->is_valid()) {
2367
-            foreach ($form->subforms() as $question_group_id => $question_group_form) {
2368
-                foreach ($question_group_form->inputs() as $question_id => $input) {
2369
-                    $where_conditions    = array(
2370
-                        'QST_ID' => $question_id,
2371
-                        'REG_ID' => $REG_ID,
2372
-                    );
2373
-                    $possibly_new_values = array(
2374
-                        'ANS_value' => $input->normalized_value(),
2375
-                    );
2376
-                    $answer              = EEM_Answer::instance()->get_one(array($where_conditions));
2377
-                    if ($answer instanceof EE_Answer) {
2378
-                        $success = $answer->save($possibly_new_values);
2379
-                    } else {
2380
-                        //insert it then
2381
-                        $cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2382
-                        $answer      = EE_Answer::new_instance($cols_n_vals);
2383
-                        $success     = $answer->save();
2384
-                    }
2385
-                }
2386
-            }
2387
-        } else {
2388
-            EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2389
-        }
2390
-        return $success;
2391
-    }
2392
-
2393
-
2394
-    /**
2395
-     *        generates HTML for the Registration main meta box
2396
-     *
2397
-     * @access public
2398
-     * @return void
2399
-     * @throws DomainException
2400
-     * @throws EE_Error
2401
-     */
2402
-    public function _reg_attendees_meta_box()
2403
-    {
2404
-        $REG = EEM_Registration::instance();
2405
-        //get all other registrations on this transaction, and cache
2406
-        //the attendees for them so we don't have to run another query using force_join
2407
-        $registrations                           = $REG->get_all(array(
2408
-            array(
2409
-                'TXN_ID' => $this->_registration->transaction_ID(),
2410
-                'REG_ID' => array('!=', $this->_registration->ID()),
2411
-            ),
2412
-            'force_join' => array('Attendee'),
2413
-        ));
2414
-        $this->_template_args['attendees']       = array();
2415
-        $this->_template_args['attendee_notice'] = '';
2416
-        if (empty($registrations)
2417
-            || (is_array($registrations)
2418
-                && ! EEH_Array::get_one_item_from_array($registrations))
2419
-        ) {
2420
-            EE_Error::add_error(
2421
-                esc_html__(
2422
-                    'There are no records attached to this registration. Something may have gone wrong with the registration',
2423
-                    'event_espresso'
2424
-                ), __FILE__, __FUNCTION__, __LINE__
2425
-            );
2426
-            $this->_template_args['attendee_notice'] = EE_Error::get_notices();
2427
-        } else {
2428
-            $att_nmbr = 1;
2429
-            foreach ($registrations as $registration) {
2430
-                /* @var $registration EE_Registration */
2431
-                $attendee                                                    = $registration->attendee()
2432
-                    ? $registration->attendee()
2433
-                    : EEM_Attendee::instance()
2434
-                                  ->create_default_object();
2435
-                $this->_template_args['attendees'][$att_nmbr]['STS_ID']      = $registration->status_ID();
2436
-                $this->_template_args['attendees'][$att_nmbr]['fname']       = $attendee->fname();
2437
-                $this->_template_args['attendees'][$att_nmbr]['lname']       = $attendee->lname();
2438
-                $this->_template_args['attendees'][$att_nmbr]['email']       = $attendee->email();
2439
-                $this->_template_args['attendees'][$att_nmbr]['final_price'] = $registration->final_price();
2440
-                $this->_template_args['attendees'][$att_nmbr]['address']     = implode(
2441
-                    ', ',
2442
-                    $attendee->full_address_as_array()
2443
-                );
2444
-                $this->_template_args['attendees'][$att_nmbr]['att_link']    = self::add_query_args_and_nonce(
2445
-                    array(
2446
-                        'action' => 'edit_attendee',
2447
-                        'post'   => $attendee->ID(),
2448
-                    ),
2449
-                    REG_ADMIN_URL
2450
-                );
2451
-                $this->_template_args['attendees'][$att_nmbr]['event_name']  = $registration->event_obj()->name();
2452
-                $att_nmbr++;
2453
-            }
2454
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2455
-        }
2456
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2457
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2458
-    }
2459
-
2460
-
2461
-    /**
2462
-     *        generates HTML for the Edit Registration side meta box
2463
-     *
2464
-     * @access public
2465
-     * @return void
2466
-     * @throws DomainException
2467
-     * @throws EE_Error
2468
-     */
2469
-    public function _reg_registrant_side_meta_box()
2470
-    {
2471
-        /*@var $attendee EE_Attendee */
2472
-        $att_check = $this->_registration->attendee();
2473
-        $attendee  = $att_check instanceof EE_Attendee ? $att_check : EEM_Attendee::instance()->create_default_object();
2474
-        //now let's determine if this is not the primary registration.  If it isn't then we set the
2475
-        //primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2476
-        //primary registration object (that way we know if we need to show create button or not)
2477
-        if ( ! $this->_registration->is_primary_registrant()) {
2478
-            $primary_registration = $this->_registration->get_primary_registration();
2479
-            $primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2480
-                : null;
2481
-            if ( ! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2482
-                //in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2483
-                //custom attendee object so let's not worry about the primary reg.
2484
-                $primary_registration = null;
2485
-            }
2486
-        } else {
2487
-            $primary_registration = null;
2488
-        }
2489
-        $this->_template_args['ATT_ID']            = $attendee->ID();
2490
-        $this->_template_args['fname']             = $attendee->fname();
2491
-        $this->_template_args['lname']             = $attendee->lname();
2492
-        $this->_template_args['email']             = $attendee->email();
2493
-        $this->_template_args['phone']             = $attendee->phone();
2494
-        $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2495
-        //edit link
2496
-        $this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(array(
2497
-            'action' => 'edit_attendee',
2498
-            'post'   => $attendee->ID(),
2499
-        ), REG_ADMIN_URL);
2500
-        $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2501
-        //create link
2502
-        $this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2503
-            ? EE_Admin_Page::add_query_args_and_nonce(array(
2504
-                'action'  => 'duplicate_attendee',
2505
-                '_REG_ID' => $this->_registration->ID(),
2506
-            ), REG_ADMIN_URL) : '';
2507
-        $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2508
-        $this->_template_args['att_check']    = $att_check;
2509
-        $template_path                        = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2510
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2511
-    }
2512
-
2513
-
2514
-    /**
2515
-     * trash or restore registrations
2516
-     *
2517
-     * @param  boolean $trash whether to archive or restore
2518
-     * @return void
2519
-     * @throws EE_Error
2520
-     * @throws RuntimeException
2521
-     * @access protected
2522
-     */
2523
-    protected function _trash_or_restore_registrations($trash = true)
2524
-    {
2525
-        //if empty _REG_ID then get out because there's nothing to do
2526
-        if (empty($this->_req_data['_REG_ID'])) {
2527
-            EE_Error::add_error(
2528
-                sprintf(
2529
-                    esc_html__(
2530
-                        'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2531
-                        'event_espresso'
2532
-                    ),
2533
-                    $trash ? 'trash' : 'restore'
2534
-                ),
2535
-                __FILE__, __LINE__, __FUNCTION__
2536
-            );
2537
-            $this->_redirect_after_action(false, '', '', array(), true);
2538
-        }
2539
-        $success = 0;
2540
-        $overwrite_msgs = false;
2541
-        //Checkboxes
2542
-        if ( ! is_array($this->_req_data['_REG_ID'])) {
2543
-            $this->_req_data['_REG_ID'] = array($this->_req_data['_REG_ID']);
2544
-        }
2545
-        $reg_count = count($this->_req_data['_REG_ID']);
2546
-        // cycle thru checkboxes
2547
-        foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2548
-            /** @var EE_Registration $REG */
2549
-            $REG = EEM_Registration::instance()->get_one_by_ID($REG_ID);
2550
-            $payments = $REG->registration_payments();
2551
-            if (! empty($payments)) {
2552
-                $name = $REG->attendee() instanceof EE_Attendee
2553
-                    ? $REG->attendee()->full_name()
2554
-                    : esc_html__('Unknown Attendee', 'event_espresso');
2555
-                $overwrite_msgs = true;
2556
-                EE_Error::add_error(
2557
-                    sprintf(
2558
-                        esc_html__(
2559
-                            'The registration for %s could not be trashed because it has payments attached to the related transaction.  If you wish to trash this registration you must first delete the payments on the related transaction.',
2560
-                            'event_espresso'
2561
-                        ),
2562
-                        $name
2563
-                    ),
2564
-                    __FILE__, __FUNCTION__, __LINE__
2565
-                );
2566
-                //can't trash this registration because it has payments.
2567
-                continue;
2568
-            }
2569
-            $updated = $trash ? $REG->delete() : $REG->restore();
2570
-            if ($updated) {
2571
-                $success++;
2572
-            }
2573
-        }
2574
-        $this->_redirect_after_action(
2575
-            $success === $reg_count, // were ALL registrations affected?
2576
-            $success > 1
2577
-                ? esc_html__('Registrations', 'event_espresso')
2578
-                : esc_html__('Registration', 'event_espresso'),
2579
-            $trash
2580
-                ? esc_html__('moved to the trash', 'event_espresso')
2581
-                : esc_html__('restored', 'event_espresso'),
2582
-            array('action' => 'default'),
2583
-            $overwrite_msgs
2584
-        );
2585
-    }
2586
-
2587
-
2588
-    /**
2589
-     * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2590
-     * registration but also.
2591
-     * 1. Removing relations to EE_Attendee
2592
-     * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2593
-     * ALSO trashed.
2594
-     * 3. Deleting permanently any related Line items but only if the above conditions are met.
2595
-     * 4. Removing relationships between all tickets and the related registrations
2596
-     * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2597
-     * 6. Deleting permanently any related Checkins.
2598
-     *
2599
-     * @return void
2600
-     * @throws EE_Error
2601
-     */
2602
-    protected function _delete_registrations()
2603
-    {
2604
-        $REG_MDL = EEM_Registration::instance();
2605
-        $success = 1;
2606
-        //Checkboxes
2607
-        if ( ! empty($this->_req_data['_REG_ID']) && is_array($this->_req_data['_REG_ID'])) {
2608
-            // if array has more than one element than success message should be plural
2609
-            $success = count($this->_req_data['_REG_ID']) > 1 ? 2 : 1;
2610
-            // cycle thru checkboxes
2611
-            while (list($ind, $REG_ID) = each($this->_req_data['_REG_ID'])) {
2612
-                $REG = $REG_MDL->get_one_by_ID($REG_ID);
2613
-                if ( ! $REG instanceof EE_Registration) {
2614
-                    continue;
2615
-                }
2616
-                $deleted = $this->_delete_registration($REG);
2617
-                if ( ! $deleted) {
2618
-                    $success = 0;
2619
-                }
2620
-            }
2621
-        } else {
2622
-            // grab single id and delete
2623
-            $REG_ID  = $this->_req_data['_REG_ID'];
2624
-            $REG     = $REG_MDL->get_one_by_ID($REG_ID);
2625
-            $deleted = $this->_delete_registration($REG);
2626
-            if ( ! $deleted) {
2627
-                $success = 0;
2628
-            }
2629
-        }
2630
-        $what        = $success > 1
2631
-            ? esc_html__('Registrations', 'event_espresso')
2632
-            : esc_html__('Registration', 'event_espresso');
2633
-        $action_desc = esc_html__('permanently deleted.', 'event_espresso');
2634
-        $this->_redirect_after_action(
2635
-            $success,
2636
-            $what,
2637
-            $action_desc,
2638
-            array('action' => 'default'),
2639
-            true
2640
-        );
2641
-    }
2642
-
2643
-
2644
-    /**
2645
-     * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2646
-     * models get affected.
2647
-     *
2648
-     * @param  EE_Registration $REG registration to be deleted permenantly
2649
-     * @return bool true = successful deletion, false = fail.
2650
-     * @throws EE_Error
2651
-     */
2652
-    protected function _delete_registration(EE_Registration $REG)
2653
-    {
2654
-        //first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2655
-        //registrations on the transaction that are NOT trashed.
2656
-        $TXN         = $REG->get_first_related('Transaction');
2657
-        $REGS        = $TXN->get_many_related('Registration');
2658
-        $all_trashed = true;
2659
-        foreach ($REGS as $registration) {
2660
-            if ( ! $registration->get('REG_deleted')) {
2661
-                $all_trashed = false;
2662
-            }
2663
-        }
2664
-        if ( ! $all_trashed) {
2665
-            EE_Error::add_error(
2666
-                esc_html__(
2667
-                    'Unable to permanently delete this registration. Before this registration can be permanently deleted, all registrations made in the same transaction must be trashed as well.  These registrations will be permanently deleted in the same action.',
2668
-                    'event_espresso'
2669
-                ),
2670
-                __FILE__, __FUNCTION__, __LINE__
2671
-            );
2672
-            return false;
2673
-        }
2674
-        //k made it here so that means we can delete all the related transactions and their answers (but let's do them
2675
-        //separately from THIS one).
2676
-        foreach ($REGS as $registration) {
2677
-            //delete related answers
2678
-            $registration->delete_related_permanently('Answer');
2679
-            //remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2680
-            $attendee = $registration->get_first_related('Attendee');
2681
-            if ($attendee instanceof EE_Attendee) {
2682
-                $registration->_remove_relation_to($attendee, 'Attendee');
2683
-            }
2684
-            //now remove relationships to tickets on this registration.
2685
-            $registration->_remove_relations('Ticket');
2686
-            //now delete permanently the checkins related to this registration.
2687
-            $registration->delete_related_permanently('Checkin');
2688
-            if ($registration->ID() === $REG->ID()) {
2689
-                continue;
2690
-            } //we don't want to delete permanently the existing registration just yet.
2691
-            //remove relation to transaction for these registrations if NOT the existing registrations
2692
-            $registration->_remove_relations('Transaction');
2693
-            //delete permanently any related messages.
2694
-            $registration->delete_related_permanently('Message');
2695
-            //now delete this registration permanently
2696
-            $registration->delete_permanently();
2697
-        }
2698
-        //now all related registrations on the transaction are handled.  So let's just handle this registration itself
2699
-        // (the transaction and line items should be all that's left).
2700
-        // delete the line items related to the transaction for this registration.
2701
-        $TXN->delete_related_permanently('Line_Item');
2702
-        //we need to remove all the relationships on the transaction
2703
-        $TXN->delete_related_permanently('Payment');
2704
-        $TXN->delete_related_permanently('Extra_Meta');
2705
-        $TXN->delete_related_permanently('Message');
2706
-        //now we can delete this REG permanently (and the transaction of course)
2707
-        $REG->delete_related_permanently('Transaction');
2708
-        return $REG->delete_permanently();
2709
-    }
2710
-
2711
-
2712
-    /**
2713
-     *    generates HTML for the Register New Attendee Admin page
2714
-     *
2715
-     * @access private
2716
-     * @throws DomainException
2717
-     * @throws EE_Error
2718
-     */
2719
-    public function new_registration()
2720
-    {
2721
-        if ( ! $this->_set_reg_event()) {
2722
-            throw new EE_Error(
2723
-                esc_html__(
2724
-                    'Unable to continue with registering because there is no Event ID in the request',
2725
-                    'event_espresso'
2726
-                )
2727
-            );
2728
-        }
2729
-        EE_Registry::instance()->REQ->set_espresso_page(true);
2730
-        // gotta start with a clean slate if we're not coming here via ajax
2731
-        if ( ! defined('DOING_AJAX')
2732
-             && ( ! isset($this->_req_data['processing_registration']) || isset($this->_req_data['step_error']))
2733
-        ) {
2734
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2735
-        }
2736
-        $this->_template_args['event_name'] = '';
2737
-        // event name
2738
-        if ($this->_reg_event) {
2739
-            $this->_template_args['event_name'] = $this->_reg_event->name();
2740
-            $edit_event_url                     = self::add_query_args_and_nonce(array(
2741
-                'action' => 'edit',
2742
-                'post'   => $this->_reg_event->ID(),
2743
-            ), EVENTS_ADMIN_URL);
2744
-            $edit_event_lnk                     = '<a href="'
2745
-                                                  . $edit_event_url
2746
-                                                  . '" title="'
2747
-                                                  . esc_attr__('Edit ', 'event_espresso')
2748
-                                                  . $this->_reg_event->name()
2749
-                                                  . '">'
2750
-                                                  . esc_html__('Edit Event', 'event_espresso')
2751
-                                                  . '</a>';
2752
-            $this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2753
-                                                   . $edit_event_lnk
2754
-                                                   . '</span>';
2755
-        }
2756
-        $this->_template_args['step_content'] = $this->_get_registration_step_content();
2757
-        if (defined('DOING_AJAX')) {
2758
-            $this->_return_json();
2759
-        }
2760
-        // grab header
2761
-        $template_path                              =
2762
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2763
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template($template_path,
2764
-            $this->_template_args, true);
2765
-        //$this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2766
-        // the details template wrapper
2767
-        $this->display_admin_page_with_sidebar();
2768
-    }
2769
-
2770
-
2771
-    /**
2772
-     * This returns the content for a registration step
2773
-     *
2774
-     * @access protected
2775
-     * @return string html
2776
-     * @throws DomainException
2777
-     * @throws EE_Error
2778
-     */
2779
-    protected function _get_registration_step_content()
2780
-    {
2781
-        if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2782
-            $warning_msg = sprintf(
2783
-                esc_html__(
2784
-                    '%2$sWARNING!!!%3$s%1$sPlease do not use the back button to return to this page for the purpose of adding another registration.%1$sThis can result in lost and/or corrupted data.%1$sIf you wish to add another registration, then please click the%1$s%7$s"Add Another New Registration to Event"%8$s button%1$son the Transaction details page, after you are redirected.%1$s%1$s%4$s redirecting in %5$s seconds %6$s',
2785
-                    'event_espresso'
2786
-                ),
2787
-                '<br />',
2788
-                '<h3 class="important-notice">',
2789
-                '</h3>',
2790
-                '<div class="float-right">',
2791
-                '<span id="redirect_timer" class="important-notice">30</span>',
2792
-                '</div>',
2793
-                '<b>',
2794
-                '</b>'
2795
-            );
2796
-            return '
2297
+	}
2298
+
2299
+
2300
+	/**
2301
+	 * Updates the registration's custom questions according to the form info, if the form is submitted.
2302
+	 * If it's not a post, the "view_registrations" route will be called next on the SAME request
2303
+	 * to display the page
2304
+	 *
2305
+	 * @access protected
2306
+	 * @return void
2307
+	 * @throws EE_Error
2308
+	 */
2309
+	protected function _update_attendee_registration_form()
2310
+	{
2311
+		do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2312
+		if ($_SERVER['REQUEST_METHOD'] == 'POST') {
2313
+			$REG_ID  = isset($this->_req_data['_REG_ID']) ? absint($this->_req_data['_REG_ID']) : false;
2314
+			$success = $this->_save_reg_custom_questions_form($REG_ID);
2315
+			if ($success) {
2316
+				$what  = esc_html__('Registration Form', 'event_espresso');
2317
+				$route = $REG_ID ? array('action' => 'view_registration', '_REG_ID' => $REG_ID)
2318
+					: array('action' => 'default');
2319
+				$this->_redirect_after_action($success, $what, esc_html__('updated', 'event_espresso'), $route);
2320
+			}
2321
+		}
2322
+	}
2323
+
2324
+
2325
+	/**
2326
+	 * Gets the form for saving registrations custom questions (if done
2327
+	 * previously retrieves the cached form object, which may have validation errors in it)
2328
+	 *
2329
+	 * @param int $REG_ID
2330
+	 * @return EE_Registration_Custom_Questions_Form
2331
+	 * @throws EE_Error
2332
+	 */
2333
+	protected function _get_reg_custom_questions_form($REG_ID)
2334
+	{
2335
+		if ( ! $this->_reg_custom_questions_form) {
2336
+			require_once(REG_ADMIN . 'form_sections' . DS . 'EE_Registration_Custom_Questions_Form.form.php');
2337
+			$this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2338
+				EEM_Registration::instance()->get_one_by_ID($REG_ID)
2339
+			);
2340
+			$this->_reg_custom_questions_form->_construct_finalize(null, null);
2341
+		}
2342
+		return $this->_reg_custom_questions_form;
2343
+	}
2344
+
2345
+
2346
+	/**
2347
+	 * Saves
2348
+	 *
2349
+	 * @access private
2350
+	 * @param bool $REG_ID
2351
+	 * @return bool
2352
+	 * @throws EE_Error
2353
+	 */
2354
+	private function _save_reg_custom_questions_form($REG_ID = false)
2355
+	{
2356
+		if ( ! $REG_ID) {
2357
+			EE_Error::add_error(
2358
+				esc_html__(
2359
+					'An error occurred. No registration ID was received.', 'event_espresso'),
2360
+				__FILE__, __FUNCTION__, __LINE__
2361
+			);
2362
+		}
2363
+		$form = $this->_get_reg_custom_questions_form($REG_ID);
2364
+		$form->receive_form_submission($this->_req_data);
2365
+		$success = false;
2366
+		if ($form->is_valid()) {
2367
+			foreach ($form->subforms() as $question_group_id => $question_group_form) {
2368
+				foreach ($question_group_form->inputs() as $question_id => $input) {
2369
+					$where_conditions    = array(
2370
+						'QST_ID' => $question_id,
2371
+						'REG_ID' => $REG_ID,
2372
+					);
2373
+					$possibly_new_values = array(
2374
+						'ANS_value' => $input->normalized_value(),
2375
+					);
2376
+					$answer              = EEM_Answer::instance()->get_one(array($where_conditions));
2377
+					if ($answer instanceof EE_Answer) {
2378
+						$success = $answer->save($possibly_new_values);
2379
+					} else {
2380
+						//insert it then
2381
+						$cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2382
+						$answer      = EE_Answer::new_instance($cols_n_vals);
2383
+						$success     = $answer->save();
2384
+					}
2385
+				}
2386
+			}
2387
+		} else {
2388
+			EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2389
+		}
2390
+		return $success;
2391
+	}
2392
+
2393
+
2394
+	/**
2395
+	 *        generates HTML for the Registration main meta box
2396
+	 *
2397
+	 * @access public
2398
+	 * @return void
2399
+	 * @throws DomainException
2400
+	 * @throws EE_Error
2401
+	 */
2402
+	public function _reg_attendees_meta_box()
2403
+	{
2404
+		$REG = EEM_Registration::instance();
2405
+		//get all other registrations on this transaction, and cache
2406
+		//the attendees for them so we don't have to run another query using force_join
2407
+		$registrations                           = $REG->get_all(array(
2408
+			array(
2409
+				'TXN_ID' => $this->_registration->transaction_ID(),
2410
+				'REG_ID' => array('!=', $this->_registration->ID()),
2411
+			),
2412
+			'force_join' => array('Attendee'),
2413
+		));
2414
+		$this->_template_args['attendees']       = array();
2415
+		$this->_template_args['attendee_notice'] = '';
2416
+		if (empty($registrations)
2417
+			|| (is_array($registrations)
2418
+				&& ! EEH_Array::get_one_item_from_array($registrations))
2419
+		) {
2420
+			EE_Error::add_error(
2421
+				esc_html__(
2422
+					'There are no records attached to this registration. Something may have gone wrong with the registration',
2423
+					'event_espresso'
2424
+				), __FILE__, __FUNCTION__, __LINE__
2425
+			);
2426
+			$this->_template_args['attendee_notice'] = EE_Error::get_notices();
2427
+		} else {
2428
+			$att_nmbr = 1;
2429
+			foreach ($registrations as $registration) {
2430
+				/* @var $registration EE_Registration */
2431
+				$attendee                                                    = $registration->attendee()
2432
+					? $registration->attendee()
2433
+					: EEM_Attendee::instance()
2434
+								  ->create_default_object();
2435
+				$this->_template_args['attendees'][$att_nmbr]['STS_ID']      = $registration->status_ID();
2436
+				$this->_template_args['attendees'][$att_nmbr]['fname']       = $attendee->fname();
2437
+				$this->_template_args['attendees'][$att_nmbr]['lname']       = $attendee->lname();
2438
+				$this->_template_args['attendees'][$att_nmbr]['email']       = $attendee->email();
2439
+				$this->_template_args['attendees'][$att_nmbr]['final_price'] = $registration->final_price();
2440
+				$this->_template_args['attendees'][$att_nmbr]['address']     = implode(
2441
+					', ',
2442
+					$attendee->full_address_as_array()
2443
+				);
2444
+				$this->_template_args['attendees'][$att_nmbr]['att_link']    = self::add_query_args_and_nonce(
2445
+					array(
2446
+						'action' => 'edit_attendee',
2447
+						'post'   => $attendee->ID(),
2448
+					),
2449
+					REG_ADMIN_URL
2450
+				);
2451
+				$this->_template_args['attendees'][$att_nmbr]['event_name']  = $registration->event_obj()->name();
2452
+				$att_nmbr++;
2453
+			}
2454
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2455
+		}
2456
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2457
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2458
+	}
2459
+
2460
+
2461
+	/**
2462
+	 *        generates HTML for the Edit Registration side meta box
2463
+	 *
2464
+	 * @access public
2465
+	 * @return void
2466
+	 * @throws DomainException
2467
+	 * @throws EE_Error
2468
+	 */
2469
+	public function _reg_registrant_side_meta_box()
2470
+	{
2471
+		/*@var $attendee EE_Attendee */
2472
+		$att_check = $this->_registration->attendee();
2473
+		$attendee  = $att_check instanceof EE_Attendee ? $att_check : EEM_Attendee::instance()->create_default_object();
2474
+		//now let's determine if this is not the primary registration.  If it isn't then we set the
2475
+		//primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2476
+		//primary registration object (that way we know if we need to show create button or not)
2477
+		if ( ! $this->_registration->is_primary_registrant()) {
2478
+			$primary_registration = $this->_registration->get_primary_registration();
2479
+			$primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2480
+				: null;
2481
+			if ( ! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2482
+				//in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2483
+				//custom attendee object so let's not worry about the primary reg.
2484
+				$primary_registration = null;
2485
+			}
2486
+		} else {
2487
+			$primary_registration = null;
2488
+		}
2489
+		$this->_template_args['ATT_ID']            = $attendee->ID();
2490
+		$this->_template_args['fname']             = $attendee->fname();
2491
+		$this->_template_args['lname']             = $attendee->lname();
2492
+		$this->_template_args['email']             = $attendee->email();
2493
+		$this->_template_args['phone']             = $attendee->phone();
2494
+		$this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2495
+		//edit link
2496
+		$this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(array(
2497
+			'action' => 'edit_attendee',
2498
+			'post'   => $attendee->ID(),
2499
+		), REG_ADMIN_URL);
2500
+		$this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2501
+		//create link
2502
+		$this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2503
+			? EE_Admin_Page::add_query_args_and_nonce(array(
2504
+				'action'  => 'duplicate_attendee',
2505
+				'_REG_ID' => $this->_registration->ID(),
2506
+			), REG_ADMIN_URL) : '';
2507
+		$this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2508
+		$this->_template_args['att_check']    = $att_check;
2509
+		$template_path                        = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2510
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2511
+	}
2512
+
2513
+
2514
+	/**
2515
+	 * trash or restore registrations
2516
+	 *
2517
+	 * @param  boolean $trash whether to archive or restore
2518
+	 * @return void
2519
+	 * @throws EE_Error
2520
+	 * @throws RuntimeException
2521
+	 * @access protected
2522
+	 */
2523
+	protected function _trash_or_restore_registrations($trash = true)
2524
+	{
2525
+		//if empty _REG_ID then get out because there's nothing to do
2526
+		if (empty($this->_req_data['_REG_ID'])) {
2527
+			EE_Error::add_error(
2528
+				sprintf(
2529
+					esc_html__(
2530
+						'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2531
+						'event_espresso'
2532
+					),
2533
+					$trash ? 'trash' : 'restore'
2534
+				),
2535
+				__FILE__, __LINE__, __FUNCTION__
2536
+			);
2537
+			$this->_redirect_after_action(false, '', '', array(), true);
2538
+		}
2539
+		$success = 0;
2540
+		$overwrite_msgs = false;
2541
+		//Checkboxes
2542
+		if ( ! is_array($this->_req_data['_REG_ID'])) {
2543
+			$this->_req_data['_REG_ID'] = array($this->_req_data['_REG_ID']);
2544
+		}
2545
+		$reg_count = count($this->_req_data['_REG_ID']);
2546
+		// cycle thru checkboxes
2547
+		foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2548
+			/** @var EE_Registration $REG */
2549
+			$REG = EEM_Registration::instance()->get_one_by_ID($REG_ID);
2550
+			$payments = $REG->registration_payments();
2551
+			if (! empty($payments)) {
2552
+				$name = $REG->attendee() instanceof EE_Attendee
2553
+					? $REG->attendee()->full_name()
2554
+					: esc_html__('Unknown Attendee', 'event_espresso');
2555
+				$overwrite_msgs = true;
2556
+				EE_Error::add_error(
2557
+					sprintf(
2558
+						esc_html__(
2559
+							'The registration for %s could not be trashed because it has payments attached to the related transaction.  If you wish to trash this registration you must first delete the payments on the related transaction.',
2560
+							'event_espresso'
2561
+						),
2562
+						$name
2563
+					),
2564
+					__FILE__, __FUNCTION__, __LINE__
2565
+				);
2566
+				//can't trash this registration because it has payments.
2567
+				continue;
2568
+			}
2569
+			$updated = $trash ? $REG->delete() : $REG->restore();
2570
+			if ($updated) {
2571
+				$success++;
2572
+			}
2573
+		}
2574
+		$this->_redirect_after_action(
2575
+			$success === $reg_count, // were ALL registrations affected?
2576
+			$success > 1
2577
+				? esc_html__('Registrations', 'event_espresso')
2578
+				: esc_html__('Registration', 'event_espresso'),
2579
+			$trash
2580
+				? esc_html__('moved to the trash', 'event_espresso')
2581
+				: esc_html__('restored', 'event_espresso'),
2582
+			array('action' => 'default'),
2583
+			$overwrite_msgs
2584
+		);
2585
+	}
2586
+
2587
+
2588
+	/**
2589
+	 * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2590
+	 * registration but also.
2591
+	 * 1. Removing relations to EE_Attendee
2592
+	 * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2593
+	 * ALSO trashed.
2594
+	 * 3. Deleting permanently any related Line items but only if the above conditions are met.
2595
+	 * 4. Removing relationships between all tickets and the related registrations
2596
+	 * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2597
+	 * 6. Deleting permanently any related Checkins.
2598
+	 *
2599
+	 * @return void
2600
+	 * @throws EE_Error
2601
+	 */
2602
+	protected function _delete_registrations()
2603
+	{
2604
+		$REG_MDL = EEM_Registration::instance();
2605
+		$success = 1;
2606
+		//Checkboxes
2607
+		if ( ! empty($this->_req_data['_REG_ID']) && is_array($this->_req_data['_REG_ID'])) {
2608
+			// if array has more than one element than success message should be plural
2609
+			$success = count($this->_req_data['_REG_ID']) > 1 ? 2 : 1;
2610
+			// cycle thru checkboxes
2611
+			while (list($ind, $REG_ID) = each($this->_req_data['_REG_ID'])) {
2612
+				$REG = $REG_MDL->get_one_by_ID($REG_ID);
2613
+				if ( ! $REG instanceof EE_Registration) {
2614
+					continue;
2615
+				}
2616
+				$deleted = $this->_delete_registration($REG);
2617
+				if ( ! $deleted) {
2618
+					$success = 0;
2619
+				}
2620
+			}
2621
+		} else {
2622
+			// grab single id and delete
2623
+			$REG_ID  = $this->_req_data['_REG_ID'];
2624
+			$REG     = $REG_MDL->get_one_by_ID($REG_ID);
2625
+			$deleted = $this->_delete_registration($REG);
2626
+			if ( ! $deleted) {
2627
+				$success = 0;
2628
+			}
2629
+		}
2630
+		$what        = $success > 1
2631
+			? esc_html__('Registrations', 'event_espresso')
2632
+			: esc_html__('Registration', 'event_espresso');
2633
+		$action_desc = esc_html__('permanently deleted.', 'event_espresso');
2634
+		$this->_redirect_after_action(
2635
+			$success,
2636
+			$what,
2637
+			$action_desc,
2638
+			array('action' => 'default'),
2639
+			true
2640
+		);
2641
+	}
2642
+
2643
+
2644
+	/**
2645
+	 * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2646
+	 * models get affected.
2647
+	 *
2648
+	 * @param  EE_Registration $REG registration to be deleted permenantly
2649
+	 * @return bool true = successful deletion, false = fail.
2650
+	 * @throws EE_Error
2651
+	 */
2652
+	protected function _delete_registration(EE_Registration $REG)
2653
+	{
2654
+		//first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2655
+		//registrations on the transaction that are NOT trashed.
2656
+		$TXN         = $REG->get_first_related('Transaction');
2657
+		$REGS        = $TXN->get_many_related('Registration');
2658
+		$all_trashed = true;
2659
+		foreach ($REGS as $registration) {
2660
+			if ( ! $registration->get('REG_deleted')) {
2661
+				$all_trashed = false;
2662
+			}
2663
+		}
2664
+		if ( ! $all_trashed) {
2665
+			EE_Error::add_error(
2666
+				esc_html__(
2667
+					'Unable to permanently delete this registration. Before this registration can be permanently deleted, all registrations made in the same transaction must be trashed as well.  These registrations will be permanently deleted in the same action.',
2668
+					'event_espresso'
2669
+				),
2670
+				__FILE__, __FUNCTION__, __LINE__
2671
+			);
2672
+			return false;
2673
+		}
2674
+		//k made it here so that means we can delete all the related transactions and their answers (but let's do them
2675
+		//separately from THIS one).
2676
+		foreach ($REGS as $registration) {
2677
+			//delete related answers
2678
+			$registration->delete_related_permanently('Answer');
2679
+			//remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2680
+			$attendee = $registration->get_first_related('Attendee');
2681
+			if ($attendee instanceof EE_Attendee) {
2682
+				$registration->_remove_relation_to($attendee, 'Attendee');
2683
+			}
2684
+			//now remove relationships to tickets on this registration.
2685
+			$registration->_remove_relations('Ticket');
2686
+			//now delete permanently the checkins related to this registration.
2687
+			$registration->delete_related_permanently('Checkin');
2688
+			if ($registration->ID() === $REG->ID()) {
2689
+				continue;
2690
+			} //we don't want to delete permanently the existing registration just yet.
2691
+			//remove relation to transaction for these registrations if NOT the existing registrations
2692
+			$registration->_remove_relations('Transaction');
2693
+			//delete permanently any related messages.
2694
+			$registration->delete_related_permanently('Message');
2695
+			//now delete this registration permanently
2696
+			$registration->delete_permanently();
2697
+		}
2698
+		//now all related registrations on the transaction are handled.  So let's just handle this registration itself
2699
+		// (the transaction and line items should be all that's left).
2700
+		// delete the line items related to the transaction for this registration.
2701
+		$TXN->delete_related_permanently('Line_Item');
2702
+		//we need to remove all the relationships on the transaction
2703
+		$TXN->delete_related_permanently('Payment');
2704
+		$TXN->delete_related_permanently('Extra_Meta');
2705
+		$TXN->delete_related_permanently('Message');
2706
+		//now we can delete this REG permanently (and the transaction of course)
2707
+		$REG->delete_related_permanently('Transaction');
2708
+		return $REG->delete_permanently();
2709
+	}
2710
+
2711
+
2712
+	/**
2713
+	 *    generates HTML for the Register New Attendee Admin page
2714
+	 *
2715
+	 * @access private
2716
+	 * @throws DomainException
2717
+	 * @throws EE_Error
2718
+	 */
2719
+	public function new_registration()
2720
+	{
2721
+		if ( ! $this->_set_reg_event()) {
2722
+			throw new EE_Error(
2723
+				esc_html__(
2724
+					'Unable to continue with registering because there is no Event ID in the request',
2725
+					'event_espresso'
2726
+				)
2727
+			);
2728
+		}
2729
+		EE_Registry::instance()->REQ->set_espresso_page(true);
2730
+		// gotta start with a clean slate if we're not coming here via ajax
2731
+		if ( ! defined('DOING_AJAX')
2732
+			 && ( ! isset($this->_req_data['processing_registration']) || isset($this->_req_data['step_error']))
2733
+		) {
2734
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2735
+		}
2736
+		$this->_template_args['event_name'] = '';
2737
+		// event name
2738
+		if ($this->_reg_event) {
2739
+			$this->_template_args['event_name'] = $this->_reg_event->name();
2740
+			$edit_event_url                     = self::add_query_args_and_nonce(array(
2741
+				'action' => 'edit',
2742
+				'post'   => $this->_reg_event->ID(),
2743
+			), EVENTS_ADMIN_URL);
2744
+			$edit_event_lnk                     = '<a href="'
2745
+												  . $edit_event_url
2746
+												  . '" title="'
2747
+												  . esc_attr__('Edit ', 'event_espresso')
2748
+												  . $this->_reg_event->name()
2749
+												  . '">'
2750
+												  . esc_html__('Edit Event', 'event_espresso')
2751
+												  . '</a>';
2752
+			$this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2753
+												   . $edit_event_lnk
2754
+												   . '</span>';
2755
+		}
2756
+		$this->_template_args['step_content'] = $this->_get_registration_step_content();
2757
+		if (defined('DOING_AJAX')) {
2758
+			$this->_return_json();
2759
+		}
2760
+		// grab header
2761
+		$template_path                              =
2762
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2763
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template($template_path,
2764
+			$this->_template_args, true);
2765
+		//$this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2766
+		// the details template wrapper
2767
+		$this->display_admin_page_with_sidebar();
2768
+	}
2769
+
2770
+
2771
+	/**
2772
+	 * This returns the content for a registration step
2773
+	 *
2774
+	 * @access protected
2775
+	 * @return string html
2776
+	 * @throws DomainException
2777
+	 * @throws EE_Error
2778
+	 */
2779
+	protected function _get_registration_step_content()
2780
+	{
2781
+		if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2782
+			$warning_msg = sprintf(
2783
+				esc_html__(
2784
+					'%2$sWARNING!!!%3$s%1$sPlease do not use the back button to return to this page for the purpose of adding another registration.%1$sThis can result in lost and/or corrupted data.%1$sIf you wish to add another registration, then please click the%1$s%7$s"Add Another New Registration to Event"%8$s button%1$son the Transaction details page, after you are redirected.%1$s%1$s%4$s redirecting in %5$s seconds %6$s',
2785
+					'event_espresso'
2786
+				),
2787
+				'<br />',
2788
+				'<h3 class="important-notice">',
2789
+				'</h3>',
2790
+				'<div class="float-right">',
2791
+				'<span id="redirect_timer" class="important-notice">30</span>',
2792
+				'</div>',
2793
+				'<b>',
2794
+				'</b>'
2795
+			);
2796
+			return '
2797 2797
 	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
2798 2798
 	<script >
2799 2799
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
@@ -2806,792 +2806,792 @@  discard block
 block discarded – undo
2806 2806
 	        }
2807 2807
 	    }, 800 );
2808 2808
 	</script >';
2809
-        }
2810
-        $template_args = array(
2811
-            'title'                    => '',
2812
-            'content'                  => '',
2813
-            'step_button_text'         => '',
2814
-            'show_notification_toggle' => false,
2815
-        );
2816
-        //to indicate we're processing a new registration
2817
-        $hidden_fields = array(
2818
-            'processing_registration' => array(
2819
-                'type'  => 'hidden',
2820
-                'value' => 0,
2821
-            ),
2822
-            'event_id'                => array(
2823
-                'type'  => 'hidden',
2824
-                'value' => $this->_reg_event->ID(),
2825
-            ),
2826
-        );
2827
-        //if the cart is empty then we know we're at step one so we'll display ticket selector
2828
-        $cart = EE_Registry::instance()->SSN->cart();
2829
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2830
-        switch ($step) {
2831
-            case 'ticket' :
2832
-                $hidden_fields['processing_registration']['value'] = 1;
2833
-                $template_args['title']                            = esc_html__(
2834
-                    'Step One: Select the Ticket for this registration',
2835
-                    'event_espresso'
2836
-                );
2837
-                $template_args['content']                          =
2838
-                    EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2839
-                $template_args['step_button_text']                 = esc_html__(
2840
-                    'Add Tickets and Continue to Registrant Details',
2841
-                    'event_espresso'
2842
-                );
2843
-                $template_args['show_notification_toggle']         = false;
2844
-                break;
2845
-            case 'questions' :
2846
-                $hidden_fields['processing_registration']['value'] = 2;
2847
-                $template_args['title']                            = esc_html__(
2848
-                    'Step Two: Add Registrant Details for this Registration',
2849
-                    'event_espresso'
2850
-                );
2851
-                //in theory we should be able to run EED_SPCO at this point because the cart should have been setup
2852
-                // properly by the first process_reg_step run.
2853
-                $template_args['content']                  =
2854
-                    EED_Single_Page_Checkout::registration_checkout_for_admin();
2855
-                $template_args['step_button_text']         = esc_html__(
2856
-                    'Save Registration and Continue to Details',
2857
-                    'event_espresso'
2858
-                );
2859
-                $template_args['show_notification_toggle'] = true;
2860
-                break;
2861
-        }
2862
-        //we come back to the process_registration_step route.
2863
-        $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2864
-        return EEH_Template::display_template(
2865
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2866
-            $template_args,
2867
-            true
2868
-        );
2869
-    }
2870
-
2871
-
2872
-    /**
2873
-     *        set_reg_event
2874
-     *
2875
-     * @access private
2876
-     * @return bool
2877
-     * @throws EE_Error
2878
-     */
2879
-    private function _set_reg_event()
2880
-    {
2881
-        if (is_object($this->_reg_event)) {
2882
-            return true;
2883
-        }
2884
-        $EVT_ID = (! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
2885
-        if ( ! $EVT_ID) {
2886
-            return false;
2887
-        }
2888
-        $this->_reg_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2889
-        return true;
2890
-    }
2891
-
2892
-
2893
-    /**
2894
-     * process_reg_step
2895
-     *
2896
-     * @access        public
2897
-     * @return string
2898
-     * @throws DomainException
2899
-     * @throws EE_Error
2900
-     * @throws RuntimeException
2901
-     */
2902
-    public function process_reg_step()
2903
-    {
2904
-        EE_System::do_not_cache();
2905
-        $this->_set_reg_event();
2906
-        EE_Registry::instance()->REQ->set_espresso_page(true);
2907
-        EE_Registry::instance()->REQ->set('uts', time());
2908
-        //what step are we on?
2909
-        $cart = EE_Registry::instance()->SSN->cart();
2910
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2911
-        //if doing ajax then we need to verify the nonce
2912
-        if (defined('DOING_AJAX')) {
2913
-            $nonce = isset($this->_req_data[$this->_req_nonce])
2914
-                ? sanitize_text_field($this->_req_data[$this->_req_nonce]) : '';
2915
-            $this->_verify_nonce($nonce, $this->_req_nonce);
2916
-        }
2917
-        switch ($step) {
2918
-            case 'ticket' :
2919
-                //process ticket selection
2920
-                $success = EED_Ticket_Selector::instance()->process_ticket_selections();
2921
-                if ($success) {
2922
-                    EE_Error::add_success(
2923
-                        esc_html__(
2924
-                            'Tickets Selected. Now complete the registration.',
2925
-                            'event_espresso'
2926
-                        )
2927
-                    );
2928
-                } else {
2929
-                    $query_args['step_error'] = $this->_req_data['step_error'] = true;
2930
-                }
2931
-                if (defined('DOING_AJAX')) {
2932
-                    $this->new_registration(); //display next step
2933
-                } else {
2934
-                    $query_args = array(
2935
-                        'action'                  => 'new_registration',
2936
-                        'processing_registration' => 1,
2937
-                        'event_id'                => $this->_reg_event->ID(),
2938
-                        'uts'                     => time(),
2939
-                    );
2940
-                    $this->_redirect_after_action(
2941
-                        false,
2942
-                        '',
2943
-                        '',
2944
-                        $query_args,
2945
-                        true
2946
-                    );
2947
-                }
2948
-                break;
2949
-            case 'questions' :
2950
-                if (! isset(
2951
-                    $this->_req_data['txn_reg_status_change'],
2952
-                    $this->_req_data['txn_reg_status_change']['send_notifications'])
2953
-                ) {
2954
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
2955
-                }
2956
-                //process registration
2957
-                $transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
2958
-                if ($cart instanceof EE_Cart) {
2959
-                    $grand_total = $cart->get_cart_grand_total();
2960
-                    if ($grand_total instanceof EE_Line_Item) {
2961
-                        $grand_total->save_this_and_descendants_to_txn();
2962
-                    }
2963
-                }
2964
-                if ( ! $transaction instanceof EE_Transaction) {
2965
-                    $query_args = array(
2966
-                        'action'                  => 'new_registration',
2967
-                        'processing_registration' => 2,
2968
-                        'event_id'                => $this->_reg_event->ID(),
2969
-                        'uts'                     => time(),
2970
-                    );
2971
-                    if (defined('DOING_AJAX')) {
2972
-                        //display registration form again because there are errors (maybe validation?)
2973
-                        $this->new_registration();
2974
-                        return;
2975
-                    } else {
2976
-                        $this->_redirect_after_action(
2977
-                            false,
2978
-                            '',
2979
-                            '',
2980
-                            $query_args,
2981
-                            true
2982
-                        );
2983
-                        return;
2984
-                    }
2985
-                }
2986
-                // maybe update status, and make sure to save transaction if not done already
2987
-                if ( ! $transaction->update_status_based_on_total_paid()) {
2988
-                    $transaction->save();
2989
-                }
2990
-                EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2991
-                $this->_req_data = array();
2992
-                $query_args      = array(
2993
-                    'action'        => 'redirect_to_txn',
2994
-                    'TXN_ID'        => $transaction->ID(),
2995
-                    'EVT_ID'        => $this->_reg_event->ID(),
2996
-                    'event_name'    => urlencode($this->_reg_event->name()),
2997
-                    'redirect_from' => 'new_registration',
2998
-                );
2999
-                $this->_redirect_after_action(false, '', '', $query_args, true);
3000
-                break;
3001
-        }
3002
-        //what are you looking here for?  Should be nothing to do at this point.
3003
-    }
3004
-
3005
-
3006
-    /**
3007
-     * redirect_to_txn
3008
-     *
3009
-     * @access public
3010
-     * @return void
3011
-     * @throws EE_Error
3012
-     */
3013
-    public function redirect_to_txn()
3014
-    {
3015
-        EE_System::do_not_cache();
3016
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3017
-        $query_args = array(
3018
-            'action' => 'view_transaction',
3019
-            'TXN_ID' => isset($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : 0,
3020
-            'page'   => 'espresso_transactions',
3021
-        );
3022
-        if (isset($this->_req_data['EVT_ID'], $this->_req_data['redirect_from'])) {
3023
-            $query_args['EVT_ID']        = $this->_req_data['EVT_ID'];
3024
-            $query_args['event_name']    = urlencode($this->_req_data['event_name']);
3025
-            $query_args['redirect_from'] = $this->_req_data['redirect_from'];
3026
-        }
3027
-        EE_Error::add_success(
3028
-            esc_html__(
3029
-                'Registration Created.  Please review the transaction and add any payments as necessary',
3030
-                'event_espresso'
3031
-            )
3032
-        );
3033
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3034
-    }
3035
-
3036
-
3037
-    /**
3038
-     *        generates HTML for the Attendee Contact List
3039
-     *
3040
-     * @access protected
3041
-     * @return void
3042
-     */
3043
-    protected function _attendee_contact_list_table()
3044
-    {
3045
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3046
-        $this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3047
-        $this->display_admin_list_table_page_with_no_sidebar();
3048
-    }
3049
-
3050
-
3051
-    /**
3052
-     *        get_attendees
3053
-     *
3054
-     * @param      $per_page
3055
-     * @param bool $count whether to return count or data.
3056
-     * @param bool $trash
3057
-     * @return array
3058
-     * @throws EE_Error
3059
-     * @access public
3060
-     */
3061
-    public function get_attendees($per_page, $count = false, $trash = false)
3062
-    {
3063
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3064
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3065
-        $ATT_MDL                    = EEM_Attendee::instance();
3066
-        $this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
3067
-        switch ($this->_req_data['orderby']) {
3068
-            case 'ATT_ID':
3069
-                $orderby = 'ATT_ID';
3070
-                break;
3071
-            case 'ATT_fname':
3072
-                $orderby = 'ATT_fname';
3073
-                break;
3074
-            case 'ATT_email':
3075
-                $orderby = 'ATT_email';
3076
-                break;
3077
-            case 'ATT_city':
3078
-                $orderby = 'ATT_city';
3079
-                break;
3080
-            case 'STA_ID':
3081
-                $orderby = 'STA_ID';
3082
-                break;
3083
-            case 'CNT_ID':
3084
-                $orderby = 'CNT_ID';
3085
-                break;
3086
-            default:
3087
-                $orderby = 'ATT_lname';
3088
-        }
3089
-        $sort         = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
3090
-            ? $this->_req_data['order']
3091
-            : 'ASC';
3092
-        $current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
3093
-            ? $this->_req_data['paged']
3094
-            : 1;
3095
-        $per_page     = isset($per_page) && ! empty($per_page) ? $per_page : 10;
3096
-        $per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
3097
-            ? $this->_req_data['perpage']
3098
-            : $per_page;
3099
-        $_where       = array();
3100
-        if ( ! empty($this->_req_data['s'])) {
3101
-            $sstr         = '%' . $this->_req_data['s'] . '%';
3102
-            $_where['OR'] = array(
3103
-                'Registration.Event.EVT_name'       => array('LIKE', $sstr),
3104
-                'Registration.Event.EVT_desc'       => array('LIKE', $sstr),
3105
-                'Registration.Event.EVT_short_desc' => array('LIKE', $sstr),
3106
-                'ATT_fname'                         => array('LIKE', $sstr),
3107
-                'ATT_lname'                         => array('LIKE', $sstr),
3108
-                'ATT_short_bio'                     => array('LIKE', $sstr),
3109
-                'ATT_email'                         => array('LIKE', $sstr),
3110
-                'ATT_address'                       => array('LIKE', $sstr),
3111
-                'ATT_address2'                      => array('LIKE', $sstr),
3112
-                'ATT_city'                          => array('LIKE', $sstr),
3113
-                'Country.CNT_name'                  => array('LIKE', $sstr),
3114
-                'State.STA_name'                    => array('LIKE', $sstr),
3115
-                'ATT_phone'                         => array('LIKE', $sstr),
3116
-                'Registration.REG_final_price'      => array('LIKE', $sstr),
3117
-                'Registration.REG_code'             => array('LIKE', $sstr),
3118
-                'Registration.REG_count'            => array('LIKE', $sstr),
3119
-                'Registration.REG_group_size'       => array('LIKE', $sstr),
3120
-            );
3121
-        }
3122
-        $offset = ($current_page - 1) * $per_page;
3123
-        $limit  = $count ? null : array($offset, $per_page);
3124
-        if ($trash) {
3125
-            $_where['status'] = array('!=', 'publish');
3126
-            $all_attendees    = $count
3127
-                ? $ATT_MDL->count(array(
3128
-                    $_where,
3129
-                    'order_by' => array($orderby => $sort),
3130
-                    'limit'    => $limit,
3131
-                ), 'ATT_ID', true)
3132
-                : $ATT_MDL->get_all(array(
3133
-                    $_where,
3134
-                    'order_by' => array($orderby => $sort),
3135
-                    'limit'    => $limit,
3136
-                ));
3137
-        } else {
3138
-            $_where['status'] = array('IN', array('publish'));
3139
-            $all_attendees    = $count
3140
-                ? $ATT_MDL->count(array(
3141
-                    $_where,
3142
-                    'order_by' => array($orderby => $sort),
3143
-                    'limit'    => $limit,
3144
-                ), 'ATT_ID', true)
3145
-                : $ATT_MDL->get_all(array(
3146
-                    $_where,
3147
-                    'order_by' => array($orderby => $sort),
3148
-                    'limit'    => $limit,
3149
-                ));
3150
-        }
3151
-        return $all_attendees;
3152
-    }
3153
-
3154
-
3155
-    /**
3156
-     * This is just taking care of resending the registration confirmation
3157
-     *
3158
-     * @access protected
3159
-     * @return void
3160
-     */
3161
-    protected function _resend_registration()
3162
-    {
3163
-        $this->_process_resend_registration();
3164
-        $query_args = isset($this->_req_data['redirect_to'])
3165
-            ? array('action' => $this->_req_data['redirect_to'], '_REG_ID' => $this->_req_data['_REG_ID'])
3166
-            : array('action' => 'default');
3167
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3168
-    }
3169
-
3170
-    /**
3171
-     * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3172
-     * to use when selecting registrations
3173
-     * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3174
-     *                                                     the query parameters from the request
3175
-     * @return void ends the request with a redirect or download
3176
-     */
3177
-    public function _registrations_report_base( $method_name_for_getting_query_params )
3178
-    {
3179
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3180
-            wp_redirect(EE_Admin_Page::add_query_args_and_nonce(
3181
-                array(
3182
-                    'page'        => 'espresso_batch',
3183
-                    'batch'       => 'file',
3184
-                    'EVT_ID'      => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3185
-                    'filters'     => urlencode(
3186
-                        serialize(
3187
-                            call_user_func(
3188
-                                array( $this, $method_name_for_getting_query_params ),
3189
-                                EEH_Array::is_set(
3190
-                                    $this->_req_data,
3191
-                                    'filters',
3192
-                                    array()
3193
-                                )
3194
-                            )
3195
-                        )
3196
-                ),
3197
-                'use_filters' => EEH_Array::is_set($this->_req_data, 'use_filters', false),
3198
-                'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3199
-                'return_url'  => urlencode($this->_req_data['return_url']),
3200
-            )));
3201
-        } else {
3202
-            $new_request_args = array(
3203
-                'export' => 'report',
3204
-                'action' => 'registrations_report_for_event',
3205
-                'EVT_ID' => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3206
-            );
3207
-            $this->_req_data = array_merge($this->_req_data, $new_request_args);
3208
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3209
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3210
-                $EE_Export = EE_Export::instance($this->_req_data);
3211
-                $EE_Export->export();
3212
-            }
3213
-        }
3214
-    }
3215
-
3216
-
3217
-
3218
-    /**
3219
-     * Creates a registration report using only query parameters in the request
3220
-     * @return void
3221
-     */
3222
-    public function _registrations_report()
3223
-    {
3224
-        $this->_registrations_report_base('_get_registration_query_parameters');
3225
-    }
3226
-
3227
-
3228
-    public function _contact_list_export()
3229
-    {
3230
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3231
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3232
-            $EE_Export = EE_Export::instance($this->_req_data);
3233
-            $EE_Export->export_attendees();
3234
-        }
3235
-    }
3236
-
3237
-
3238
-    public function _contact_list_report()
3239
-    {
3240
-        if ( ! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3241
-            wp_redirect(EE_Admin_Page::add_query_args_and_nonce(array(
3242
-                'page'        => 'espresso_batch',
3243
-                'batch'       => 'file',
3244
-                'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3245
-                'return_url'  => urlencode($this->_req_data['return_url']),
3246
-            )));
3247
-        } else {
3248
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3249
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3250
-                $EE_Export = EE_Export::instance($this->_req_data);
3251
-                $EE_Export->report_attendees();
3252
-            }
3253
-        }
3254
-    }
3255
-
3256
-
3257
-
3258
-
3259
-
3260
-    /***************************************        ATTENDEE DETAILS        ***************************************/
3261
-    /**
3262
-     * This duplicates the attendee object for the given incoming registration id and attendee_id.
3263
-     *
3264
-     * @return void
3265
-     * @throws EE_Error
3266
-     */
3267
-    protected function _duplicate_attendee()
3268
-    {
3269
-        $action = ! empty($this->_req_data['return']) ? $this->_req_data['return'] : 'default';
3270
-        //verify we have necessary info
3271
-        if (empty($this->_req_data['_REG_ID'])) {
3272
-            EE_Error::add_error(
3273
-                esc_html__(
3274
-                    'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3275
-                    'event_espresso'
3276
-                ), __FILE__, __LINE__, __FUNCTION__
3277
-            );
3278
-            $query_args = array('action' => $action);
3279
-            $this->_redirect_after_action('', '', '', $query_args, true);
3280
-        }
3281
-        //okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3282
-        $registration = EEM_Registration::instance()->get_one_by_ID($this->_req_data['_REG_ID']);
3283
-        $attendee     = $registration->attendee();
3284
-        //remove relation of existing attendee on registration
3285
-        $registration->_remove_relation_to($attendee, 'Attendee');
3286
-        //new attendee
3287
-        $new_attendee = clone $attendee;
3288
-        $new_attendee->set('ATT_ID', 0);
3289
-        $new_attendee->save();
3290
-        //add new attendee to reg
3291
-        $registration->_add_relation_to($new_attendee, 'Attendee');
3292
-        EE_Error::add_success(
3293
-            esc_html__(
3294
-                'New Contact record created.  Now make any edits you wish to make for this contact.',
3295
-                'event_espresso'
3296
-            )
3297
-        );
3298
-        //redirect to edit page for attendee
3299
-        $query_args = array('post' => $new_attendee->ID(), 'action' => 'edit_attendee');
3300
-        $this->_redirect_after_action('', '', '', $query_args, true);
3301
-    }
3302
-
3303
-
3304
-    //related to cpt routes
3305
-    protected function _insert_update_cpt_item($post_id, $post)
3306
-    {
3307
-        $success  = true;
3308
-        $attendee = EEM_Attendee::instance()->get_one_by_ID($post_id);
3309
-        //for attendee updates
3310
-        if ($post->post_type = 'espresso_attendees' && ! empty($attendee)) {
3311
-            //note we should only be UPDATING attendees at this point.
3312
-            $updated_fields = array(
3313
-                'ATT_fname'     => $this->_req_data['ATT_fname'],
3314
-                'ATT_lname'     => $this->_req_data['ATT_lname'],
3315
-                'ATT_full_name' => $this->_req_data['ATT_fname'] . ' ' . $this->_req_data['ATT_lname'],
3316
-                'ATT_address'   => isset($this->_req_data['ATT_address']) ? $this->_req_data['ATT_address'] : '',
3317
-                'ATT_address2'  => isset($this->_req_data['ATT_address2']) ? $this->_req_data['ATT_address2'] : '',
3318
-                'ATT_city'      => isset($this->_req_data['ATT_city']) ? $this->_req_data['ATT_city'] : '',
3319
-                'STA_ID'        => isset($this->_req_data['STA_ID']) ? $this->_req_data['STA_ID'] : '',
3320
-                'CNT_ISO'       => isset($this->_req_data['CNT_ISO']) ? $this->_req_data['CNT_ISO'] : '',
3321
-                'ATT_zip'       => isset($this->_req_data['ATT_zip']) ? $this->_req_data['ATT_zip'] : '',
3322
-                'ATT_email'     => isset($this->_req_data['ATT_email']) ? $this->_req_data['ATT_email'] : '',
3323
-                'ATT_phone'     => isset($this->_req_data['ATT_phone']) ? $this->_req_data['ATT_phone'] : '',
3324
-            );
3325
-            foreach ($updated_fields as $field => $value) {
3326
-                $attendee->set($field, $value);
3327
-            }
3328
-            $success                   = $attendee->save();
3329
-            $attendee_update_callbacks = apply_filters(
3330
-                'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3331
-                array()
3332
-            );
3333
-            foreach ($attendee_update_callbacks as $a_callback) {
3334
-                if (false === call_user_func_array($a_callback, array($attendee, $this->_req_data))) {
3335
-                    throw new EE_Error(
3336
-                        sprintf(
3337
-                            esc_html__(
3338
-                                'The %s callback given for the "FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update" filter is not a valid callback.  Please check the spelling.',
3339
-                                'event_espresso'
3340
-                            ),
3341
-                            $a_callback
3342
-                        )
3343
-                    );
3344
-                }
3345
-            }
3346
-        }
3347
-        if ($success === false) {
3348
-            EE_Error::add_error(
3349
-                esc_html__(
3350
-                    'Something went wrong with updating the meta table data for the registration.',
3351
-                    'event_espresso'
3352
-                ),
3353
-                __FILE__, __FUNCTION__, __LINE__
3354
-            );
3355
-        }
3356
-    }
3357
-
3358
-
3359
-    public function trash_cpt_item($post_id)
3360
-    {
3361
-    }
3362
-
3363
-
3364
-    public function delete_cpt_item($post_id)
3365
-    {
3366
-    }
3367
-
3368
-
3369
-    public function restore_cpt_item($post_id)
3370
-    {
3371
-    }
3372
-
3373
-
3374
-    protected function _restore_cpt_item($post_id, $revision_id)
3375
-    {
3376
-    }
3377
-
3378
-
3379
-    public function attendee_editor_metaboxes()
3380
-    {
3381
-        $this->verify_cpt_object();
3382
-        remove_meta_box(
3383
-            'postexcerpt',
3384
-            esc_html__('Excerpt', 'event_espresso'),
3385
-            'post_excerpt_meta_box',
3386
-            $this->_cpt_routes[$this->_req_action],
3387
-            'normal',
3388
-            'core'
3389
-        );
3390
-        remove_meta_box('commentstatusdiv', $this->_cpt_routes[$this->_req_action], 'normal', 'core');
3391
-        if (post_type_supports('espresso_attendees', 'excerpt')) {
3392
-            add_meta_box(
3393
-                'postexcerpt',
3394
-                esc_html__('Short Biography', 'event_espresso'),
3395
-                'post_excerpt_meta_box',
3396
-                $this->_cpt_routes[$this->_req_action],
3397
-                'normal'
3398
-            );
3399
-        }
3400
-        if (post_type_supports('espresso_attendees', 'comments')) {
3401
-            add_meta_box(
3402
-                'commentsdiv',
3403
-                esc_html__('Notes on the Contact', 'event_espresso'),
3404
-                'post_comment_meta_box',
3405
-                $this->_cpt_routes[$this->_req_action],
3406
-                'normal',
3407
-                'core'
3408
-            );
3409
-        }
3410
-        add_meta_box(
3411
-            'attendee_contact_info',
3412
-            esc_html__('Contact Info', 'event_espresso'),
3413
-            array($this, 'attendee_contact_info'),
3414
-            $this->_cpt_routes[$this->_req_action],
3415
-            'side',
3416
-            'core'
3417
-        );
3418
-        add_meta_box(
3419
-            'attendee_details_address',
3420
-            esc_html__('Address Details', 'event_espresso'),
3421
-            array($this, 'attendee_address_details'),
3422
-            $this->_cpt_routes[$this->_req_action],
3423
-            'normal',
3424
-            'core'
3425
-        );
3426
-        add_meta_box(
3427
-            'attendee_registrations',
3428
-            esc_html__('Registrations for this Contact', 'event_espresso'),
3429
-            array($this, 'attendee_registrations_meta_box'),
3430
-            $this->_cpt_routes[$this->_req_action],
3431
-            'normal',
3432
-            'high'
3433
-        );
3434
-    }
3435
-
3436
-
3437
-    /**
3438
-     * Metabox for attendee contact info
3439
-     *
3440
-     * @param  WP_Post $post wp post object
3441
-     * @return string attendee contact info ( and form )
3442
-     * @throws DomainException
3443
-     */
3444
-    public function attendee_contact_info($post)
3445
-    {
3446
-        //get attendee object ( should already have it )
3447
-        $this->_template_args['attendee'] = $this->_cpt_model_obj;
3448
-        $template                         = REG_TEMPLATE_PATH . 'attendee_contact_info_metabox_content.template.php';
3449
-        EEH_Template::display_template($template, $this->_template_args);
3450
-    }
3451
-
3452
-
3453
-    /**
3454
-     * Metabox for attendee details
3455
-     *
3456
-     * @param  WP_Post $post wp post object
3457
-     * @return string attendee address details (and form)
3458
-     * @throws DomainException
3459
-     */
3460
-    public function attendee_address_details($post)
3461
-    {
3462
-        //get attendee object (should already have it)
3463
-        $this->_template_args['attendee']     = $this->_cpt_model_obj;
3464
-        $this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3465
-            new EE_Question_Form_Input(
3466
-                EE_Question::new_instance(
3467
-                    array(
3468
-                        'QST_ID'           => 0,
3469
-                        'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3470
-                        'QST_system'       => 'admin-state',
3471
-                    )
3472
-                ),
3473
-                EE_Answer::new_instance(
3474
-                    array(
3475
-                        'ANS_ID'    => 0,
3476
-                        'ANS_value' => $this->_cpt_model_obj->state_ID(),
3477
-                    )
3478
-                ),
3479
-                array(
3480
-                    'input_id'       => 'STA_ID',
3481
-                    'input_name'     => 'STA_ID',
3482
-                    'input_prefix'   => '',
3483
-                    'append_qstn_id' => false,
3484
-                )
3485
-            )
3486
-        );
3487
-        $this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3488
-            new EE_Question_Form_Input(
3489
-                EE_Question::new_instance(
3490
-                    array(
3491
-                        'QST_ID'           => 0,
3492
-                        'QST_display_text' => esc_html__('Country', 'event_espresso'),
3493
-                        'QST_system'       => 'admin-country',
3494
-                    )
3495
-                ),
3496
-                EE_Answer::new_instance(
3497
-                    array(
3498
-                        'ANS_ID'    => 0,
3499
-                        'ANS_value' => $this->_cpt_model_obj->country_ID(),
3500
-                    )
3501
-                ),
3502
-                array(
3503
-                    'input_id'       => 'CNT_ISO',
3504
-                    'input_name'     => 'CNT_ISO',
3505
-                    'input_prefix'   => '',
3506
-                    'append_qstn_id' => false,
3507
-                )
3508
-            )
3509
-        );
3510
-        $template                             =
3511
-            REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3512
-        EEH_Template::display_template($template, $this->_template_args);
3513
-    }
3514
-
3515
-
3516
-    /**
3517
-     *        _attendee_details
3518
-     *
3519
-     * @access protected
3520
-     * @param $post
3521
-     * @return void
3522
-     * @throws DomainException
3523
-     * @throws EE_Error
3524
-     */
3525
-    public function attendee_registrations_meta_box($post)
3526
-    {
3527
-        $this->_template_args['attendee']      = $this->_cpt_model_obj;
3528
-        $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3529
-        $template                              =
3530
-            REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3531
-        EEH_Template::display_template($template, $this->_template_args);
3532
-    }
3533
-
3534
-
3535
-    /**
3536
-     * add in the form fields for the attendee edit
3537
-     *
3538
-     * @param  WP_Post $post wp post object
3539
-     * @return string html for new form.
3540
-     * @throws DomainException
3541
-     */
3542
-    public function after_title_form_fields($post)
3543
-    {
3544
-        if ($post->post_type == 'espresso_attendees') {
3545
-            $template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3546
-            $template_args['attendee'] = $this->_cpt_model_obj;
3547
-            EEH_Template::display_template($template, $template_args);
3548
-        }
3549
-    }
3550
-
3551
-
3552
-    /**
3553
-     *        _trash_or_restore_attendee
3554
-     *
3555
-     * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3556
-     * @return void
3557
-     * @throws EE_Error
3558
-     * @access protected
3559
-     */
3560
-    protected function _trash_or_restore_attendees($trash = true)
3561
-    {
3562
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3563
-        $ATT_MDL = EEM_Attendee::instance();
3564
-        $success = 1;
3565
-        //Checkboxes
3566
-        if ( ! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
3567
-            // if array has more than one element than success message should be plural
3568
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
3569
-            // cycle thru checkboxes
3570
-            while (list($ATT_ID, $value) = each($this->_req_data['checkbox'])) {
3571
-                $updated = $trash ? $ATT_MDL->update_by_ID(array('status' => 'trash'), $ATT_ID)
3572
-                    : $ATT_MDL->update_by_ID(array('status' => 'publish'), $ATT_ID);
3573
-                if ( ! $updated) {
3574
-                    $success = 0;
3575
-                }
3576
-            }
3577
-        } else {
3578
-            // grab single id and delete
3579
-            $ATT_ID = absint($this->_req_data['ATT_ID']);
3580
-            //get attendee
3581
-            $att     = $ATT_MDL->get_one_by_ID($ATT_ID);
3582
-            $updated = $trash ? $att->set_status('trash') : $att->set_status('publish');
3583
-            $updated = $att->save();
3584
-            if ( ! $updated) {
3585
-                $success = 0;
3586
-            }
3587
-        }
3588
-        $what        = $success > 1
3589
-            ? esc_html__('Contacts', 'event_espresso')
3590
-            : esc_html__('Contact', 'event_espresso');
3591
-        $action_desc = $trash
3592
-            ? esc_html__('moved to the trash', 'event_espresso')
3593
-            : esc_html__('restored', 'event_espresso');
3594
-        $this->_redirect_after_action($success, $what, $action_desc, array('action' => 'contact_list'));
3595
-    }
2809
+		}
2810
+		$template_args = array(
2811
+			'title'                    => '',
2812
+			'content'                  => '',
2813
+			'step_button_text'         => '',
2814
+			'show_notification_toggle' => false,
2815
+		);
2816
+		//to indicate we're processing a new registration
2817
+		$hidden_fields = array(
2818
+			'processing_registration' => array(
2819
+				'type'  => 'hidden',
2820
+				'value' => 0,
2821
+			),
2822
+			'event_id'                => array(
2823
+				'type'  => 'hidden',
2824
+				'value' => $this->_reg_event->ID(),
2825
+			),
2826
+		);
2827
+		//if the cart is empty then we know we're at step one so we'll display ticket selector
2828
+		$cart = EE_Registry::instance()->SSN->cart();
2829
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2830
+		switch ($step) {
2831
+			case 'ticket' :
2832
+				$hidden_fields['processing_registration']['value'] = 1;
2833
+				$template_args['title']                            = esc_html__(
2834
+					'Step One: Select the Ticket for this registration',
2835
+					'event_espresso'
2836
+				);
2837
+				$template_args['content']                          =
2838
+					EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2839
+				$template_args['step_button_text']                 = esc_html__(
2840
+					'Add Tickets and Continue to Registrant Details',
2841
+					'event_espresso'
2842
+				);
2843
+				$template_args['show_notification_toggle']         = false;
2844
+				break;
2845
+			case 'questions' :
2846
+				$hidden_fields['processing_registration']['value'] = 2;
2847
+				$template_args['title']                            = esc_html__(
2848
+					'Step Two: Add Registrant Details for this Registration',
2849
+					'event_espresso'
2850
+				);
2851
+				//in theory we should be able to run EED_SPCO at this point because the cart should have been setup
2852
+				// properly by the first process_reg_step run.
2853
+				$template_args['content']                  =
2854
+					EED_Single_Page_Checkout::registration_checkout_for_admin();
2855
+				$template_args['step_button_text']         = esc_html__(
2856
+					'Save Registration and Continue to Details',
2857
+					'event_espresso'
2858
+				);
2859
+				$template_args['show_notification_toggle'] = true;
2860
+				break;
2861
+		}
2862
+		//we come back to the process_registration_step route.
2863
+		$this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2864
+		return EEH_Template::display_template(
2865
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2866
+			$template_args,
2867
+			true
2868
+		);
2869
+	}
2870
+
2871
+
2872
+	/**
2873
+	 *        set_reg_event
2874
+	 *
2875
+	 * @access private
2876
+	 * @return bool
2877
+	 * @throws EE_Error
2878
+	 */
2879
+	private function _set_reg_event()
2880
+	{
2881
+		if (is_object($this->_reg_event)) {
2882
+			return true;
2883
+		}
2884
+		$EVT_ID = (! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
2885
+		if ( ! $EVT_ID) {
2886
+			return false;
2887
+		}
2888
+		$this->_reg_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2889
+		return true;
2890
+	}
2891
+
2892
+
2893
+	/**
2894
+	 * process_reg_step
2895
+	 *
2896
+	 * @access        public
2897
+	 * @return string
2898
+	 * @throws DomainException
2899
+	 * @throws EE_Error
2900
+	 * @throws RuntimeException
2901
+	 */
2902
+	public function process_reg_step()
2903
+	{
2904
+		EE_System::do_not_cache();
2905
+		$this->_set_reg_event();
2906
+		EE_Registry::instance()->REQ->set_espresso_page(true);
2907
+		EE_Registry::instance()->REQ->set('uts', time());
2908
+		//what step are we on?
2909
+		$cart = EE_Registry::instance()->SSN->cart();
2910
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2911
+		//if doing ajax then we need to verify the nonce
2912
+		if (defined('DOING_AJAX')) {
2913
+			$nonce = isset($this->_req_data[$this->_req_nonce])
2914
+				? sanitize_text_field($this->_req_data[$this->_req_nonce]) : '';
2915
+			$this->_verify_nonce($nonce, $this->_req_nonce);
2916
+		}
2917
+		switch ($step) {
2918
+			case 'ticket' :
2919
+				//process ticket selection
2920
+				$success = EED_Ticket_Selector::instance()->process_ticket_selections();
2921
+				if ($success) {
2922
+					EE_Error::add_success(
2923
+						esc_html__(
2924
+							'Tickets Selected. Now complete the registration.',
2925
+							'event_espresso'
2926
+						)
2927
+					);
2928
+				} else {
2929
+					$query_args['step_error'] = $this->_req_data['step_error'] = true;
2930
+				}
2931
+				if (defined('DOING_AJAX')) {
2932
+					$this->new_registration(); //display next step
2933
+				} else {
2934
+					$query_args = array(
2935
+						'action'                  => 'new_registration',
2936
+						'processing_registration' => 1,
2937
+						'event_id'                => $this->_reg_event->ID(),
2938
+						'uts'                     => time(),
2939
+					);
2940
+					$this->_redirect_after_action(
2941
+						false,
2942
+						'',
2943
+						'',
2944
+						$query_args,
2945
+						true
2946
+					);
2947
+				}
2948
+				break;
2949
+			case 'questions' :
2950
+				if (! isset(
2951
+					$this->_req_data['txn_reg_status_change'],
2952
+					$this->_req_data['txn_reg_status_change']['send_notifications'])
2953
+				) {
2954
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
2955
+				}
2956
+				//process registration
2957
+				$transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
2958
+				if ($cart instanceof EE_Cart) {
2959
+					$grand_total = $cart->get_cart_grand_total();
2960
+					if ($grand_total instanceof EE_Line_Item) {
2961
+						$grand_total->save_this_and_descendants_to_txn();
2962
+					}
2963
+				}
2964
+				if ( ! $transaction instanceof EE_Transaction) {
2965
+					$query_args = array(
2966
+						'action'                  => 'new_registration',
2967
+						'processing_registration' => 2,
2968
+						'event_id'                => $this->_reg_event->ID(),
2969
+						'uts'                     => time(),
2970
+					);
2971
+					if (defined('DOING_AJAX')) {
2972
+						//display registration form again because there are errors (maybe validation?)
2973
+						$this->new_registration();
2974
+						return;
2975
+					} else {
2976
+						$this->_redirect_after_action(
2977
+							false,
2978
+							'',
2979
+							'',
2980
+							$query_args,
2981
+							true
2982
+						);
2983
+						return;
2984
+					}
2985
+				}
2986
+				// maybe update status, and make sure to save transaction if not done already
2987
+				if ( ! $transaction->update_status_based_on_total_paid()) {
2988
+					$transaction->save();
2989
+				}
2990
+				EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2991
+				$this->_req_data = array();
2992
+				$query_args      = array(
2993
+					'action'        => 'redirect_to_txn',
2994
+					'TXN_ID'        => $transaction->ID(),
2995
+					'EVT_ID'        => $this->_reg_event->ID(),
2996
+					'event_name'    => urlencode($this->_reg_event->name()),
2997
+					'redirect_from' => 'new_registration',
2998
+				);
2999
+				$this->_redirect_after_action(false, '', '', $query_args, true);
3000
+				break;
3001
+		}
3002
+		//what are you looking here for?  Should be nothing to do at this point.
3003
+	}
3004
+
3005
+
3006
+	/**
3007
+	 * redirect_to_txn
3008
+	 *
3009
+	 * @access public
3010
+	 * @return void
3011
+	 * @throws EE_Error
3012
+	 */
3013
+	public function redirect_to_txn()
3014
+	{
3015
+		EE_System::do_not_cache();
3016
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3017
+		$query_args = array(
3018
+			'action' => 'view_transaction',
3019
+			'TXN_ID' => isset($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : 0,
3020
+			'page'   => 'espresso_transactions',
3021
+		);
3022
+		if (isset($this->_req_data['EVT_ID'], $this->_req_data['redirect_from'])) {
3023
+			$query_args['EVT_ID']        = $this->_req_data['EVT_ID'];
3024
+			$query_args['event_name']    = urlencode($this->_req_data['event_name']);
3025
+			$query_args['redirect_from'] = $this->_req_data['redirect_from'];
3026
+		}
3027
+		EE_Error::add_success(
3028
+			esc_html__(
3029
+				'Registration Created.  Please review the transaction and add any payments as necessary',
3030
+				'event_espresso'
3031
+			)
3032
+		);
3033
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3034
+	}
3035
+
3036
+
3037
+	/**
3038
+	 *        generates HTML for the Attendee Contact List
3039
+	 *
3040
+	 * @access protected
3041
+	 * @return void
3042
+	 */
3043
+	protected function _attendee_contact_list_table()
3044
+	{
3045
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3046
+		$this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3047
+		$this->display_admin_list_table_page_with_no_sidebar();
3048
+	}
3049
+
3050
+
3051
+	/**
3052
+	 *        get_attendees
3053
+	 *
3054
+	 * @param      $per_page
3055
+	 * @param bool $count whether to return count or data.
3056
+	 * @param bool $trash
3057
+	 * @return array
3058
+	 * @throws EE_Error
3059
+	 * @access public
3060
+	 */
3061
+	public function get_attendees($per_page, $count = false, $trash = false)
3062
+	{
3063
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3064
+		require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3065
+		$ATT_MDL                    = EEM_Attendee::instance();
3066
+		$this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
3067
+		switch ($this->_req_data['orderby']) {
3068
+			case 'ATT_ID':
3069
+				$orderby = 'ATT_ID';
3070
+				break;
3071
+			case 'ATT_fname':
3072
+				$orderby = 'ATT_fname';
3073
+				break;
3074
+			case 'ATT_email':
3075
+				$orderby = 'ATT_email';
3076
+				break;
3077
+			case 'ATT_city':
3078
+				$orderby = 'ATT_city';
3079
+				break;
3080
+			case 'STA_ID':
3081
+				$orderby = 'STA_ID';
3082
+				break;
3083
+			case 'CNT_ID':
3084
+				$orderby = 'CNT_ID';
3085
+				break;
3086
+			default:
3087
+				$orderby = 'ATT_lname';
3088
+		}
3089
+		$sort         = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
3090
+			? $this->_req_data['order']
3091
+			: 'ASC';
3092
+		$current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
3093
+			? $this->_req_data['paged']
3094
+			: 1;
3095
+		$per_page     = isset($per_page) && ! empty($per_page) ? $per_page : 10;
3096
+		$per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
3097
+			? $this->_req_data['perpage']
3098
+			: $per_page;
3099
+		$_where       = array();
3100
+		if ( ! empty($this->_req_data['s'])) {
3101
+			$sstr         = '%' . $this->_req_data['s'] . '%';
3102
+			$_where['OR'] = array(
3103
+				'Registration.Event.EVT_name'       => array('LIKE', $sstr),
3104
+				'Registration.Event.EVT_desc'       => array('LIKE', $sstr),
3105
+				'Registration.Event.EVT_short_desc' => array('LIKE', $sstr),
3106
+				'ATT_fname'                         => array('LIKE', $sstr),
3107
+				'ATT_lname'                         => array('LIKE', $sstr),
3108
+				'ATT_short_bio'                     => array('LIKE', $sstr),
3109
+				'ATT_email'                         => array('LIKE', $sstr),
3110
+				'ATT_address'                       => array('LIKE', $sstr),
3111
+				'ATT_address2'                      => array('LIKE', $sstr),
3112
+				'ATT_city'                          => array('LIKE', $sstr),
3113
+				'Country.CNT_name'                  => array('LIKE', $sstr),
3114
+				'State.STA_name'                    => array('LIKE', $sstr),
3115
+				'ATT_phone'                         => array('LIKE', $sstr),
3116
+				'Registration.REG_final_price'      => array('LIKE', $sstr),
3117
+				'Registration.REG_code'             => array('LIKE', $sstr),
3118
+				'Registration.REG_count'            => array('LIKE', $sstr),
3119
+				'Registration.REG_group_size'       => array('LIKE', $sstr),
3120
+			);
3121
+		}
3122
+		$offset = ($current_page - 1) * $per_page;
3123
+		$limit  = $count ? null : array($offset, $per_page);
3124
+		if ($trash) {
3125
+			$_where['status'] = array('!=', 'publish');
3126
+			$all_attendees    = $count
3127
+				? $ATT_MDL->count(array(
3128
+					$_where,
3129
+					'order_by' => array($orderby => $sort),
3130
+					'limit'    => $limit,
3131
+				), 'ATT_ID', true)
3132
+				: $ATT_MDL->get_all(array(
3133
+					$_where,
3134
+					'order_by' => array($orderby => $sort),
3135
+					'limit'    => $limit,
3136
+				));
3137
+		} else {
3138
+			$_where['status'] = array('IN', array('publish'));
3139
+			$all_attendees    = $count
3140
+				? $ATT_MDL->count(array(
3141
+					$_where,
3142
+					'order_by' => array($orderby => $sort),
3143
+					'limit'    => $limit,
3144
+				), 'ATT_ID', true)
3145
+				: $ATT_MDL->get_all(array(
3146
+					$_where,
3147
+					'order_by' => array($orderby => $sort),
3148
+					'limit'    => $limit,
3149
+				));
3150
+		}
3151
+		return $all_attendees;
3152
+	}
3153
+
3154
+
3155
+	/**
3156
+	 * This is just taking care of resending the registration confirmation
3157
+	 *
3158
+	 * @access protected
3159
+	 * @return void
3160
+	 */
3161
+	protected function _resend_registration()
3162
+	{
3163
+		$this->_process_resend_registration();
3164
+		$query_args = isset($this->_req_data['redirect_to'])
3165
+			? array('action' => $this->_req_data['redirect_to'], '_REG_ID' => $this->_req_data['_REG_ID'])
3166
+			: array('action' => 'default');
3167
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3168
+	}
3169
+
3170
+	/**
3171
+	 * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3172
+	 * to use when selecting registrations
3173
+	 * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3174
+	 *                                                     the query parameters from the request
3175
+	 * @return void ends the request with a redirect or download
3176
+	 */
3177
+	public function _registrations_report_base( $method_name_for_getting_query_params )
3178
+	{
3179
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3180
+			wp_redirect(EE_Admin_Page::add_query_args_and_nonce(
3181
+				array(
3182
+					'page'        => 'espresso_batch',
3183
+					'batch'       => 'file',
3184
+					'EVT_ID'      => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3185
+					'filters'     => urlencode(
3186
+						serialize(
3187
+							call_user_func(
3188
+								array( $this, $method_name_for_getting_query_params ),
3189
+								EEH_Array::is_set(
3190
+									$this->_req_data,
3191
+									'filters',
3192
+									array()
3193
+								)
3194
+							)
3195
+						)
3196
+				),
3197
+				'use_filters' => EEH_Array::is_set($this->_req_data, 'use_filters', false),
3198
+				'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3199
+				'return_url'  => urlencode($this->_req_data['return_url']),
3200
+			)));
3201
+		} else {
3202
+			$new_request_args = array(
3203
+				'export' => 'report',
3204
+				'action' => 'registrations_report_for_event',
3205
+				'EVT_ID' => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3206
+			);
3207
+			$this->_req_data = array_merge($this->_req_data, $new_request_args);
3208
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3209
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3210
+				$EE_Export = EE_Export::instance($this->_req_data);
3211
+				$EE_Export->export();
3212
+			}
3213
+		}
3214
+	}
3215
+
3216
+
3217
+
3218
+	/**
3219
+	 * Creates a registration report using only query parameters in the request
3220
+	 * @return void
3221
+	 */
3222
+	public function _registrations_report()
3223
+	{
3224
+		$this->_registrations_report_base('_get_registration_query_parameters');
3225
+	}
3226
+
3227
+
3228
+	public function _contact_list_export()
3229
+	{
3230
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3231
+			require_once(EE_CLASSES . 'EE_Export.class.php');
3232
+			$EE_Export = EE_Export::instance($this->_req_data);
3233
+			$EE_Export->export_attendees();
3234
+		}
3235
+	}
3236
+
3237
+
3238
+	public function _contact_list_report()
3239
+	{
3240
+		if ( ! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3241
+			wp_redirect(EE_Admin_Page::add_query_args_and_nonce(array(
3242
+				'page'        => 'espresso_batch',
3243
+				'batch'       => 'file',
3244
+				'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3245
+				'return_url'  => urlencode($this->_req_data['return_url']),
3246
+			)));
3247
+		} else {
3248
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3249
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3250
+				$EE_Export = EE_Export::instance($this->_req_data);
3251
+				$EE_Export->report_attendees();
3252
+			}
3253
+		}
3254
+	}
3255
+
3256
+
3257
+
3258
+
3259
+
3260
+	/***************************************        ATTENDEE DETAILS        ***************************************/
3261
+	/**
3262
+	 * This duplicates the attendee object for the given incoming registration id and attendee_id.
3263
+	 *
3264
+	 * @return void
3265
+	 * @throws EE_Error
3266
+	 */
3267
+	protected function _duplicate_attendee()
3268
+	{
3269
+		$action = ! empty($this->_req_data['return']) ? $this->_req_data['return'] : 'default';
3270
+		//verify we have necessary info
3271
+		if (empty($this->_req_data['_REG_ID'])) {
3272
+			EE_Error::add_error(
3273
+				esc_html__(
3274
+					'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3275
+					'event_espresso'
3276
+				), __FILE__, __LINE__, __FUNCTION__
3277
+			);
3278
+			$query_args = array('action' => $action);
3279
+			$this->_redirect_after_action('', '', '', $query_args, true);
3280
+		}
3281
+		//okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3282
+		$registration = EEM_Registration::instance()->get_one_by_ID($this->_req_data['_REG_ID']);
3283
+		$attendee     = $registration->attendee();
3284
+		//remove relation of existing attendee on registration
3285
+		$registration->_remove_relation_to($attendee, 'Attendee');
3286
+		//new attendee
3287
+		$new_attendee = clone $attendee;
3288
+		$new_attendee->set('ATT_ID', 0);
3289
+		$new_attendee->save();
3290
+		//add new attendee to reg
3291
+		$registration->_add_relation_to($new_attendee, 'Attendee');
3292
+		EE_Error::add_success(
3293
+			esc_html__(
3294
+				'New Contact record created.  Now make any edits you wish to make for this contact.',
3295
+				'event_espresso'
3296
+			)
3297
+		);
3298
+		//redirect to edit page for attendee
3299
+		$query_args = array('post' => $new_attendee->ID(), 'action' => 'edit_attendee');
3300
+		$this->_redirect_after_action('', '', '', $query_args, true);
3301
+	}
3302
+
3303
+
3304
+	//related to cpt routes
3305
+	protected function _insert_update_cpt_item($post_id, $post)
3306
+	{
3307
+		$success  = true;
3308
+		$attendee = EEM_Attendee::instance()->get_one_by_ID($post_id);
3309
+		//for attendee updates
3310
+		if ($post->post_type = 'espresso_attendees' && ! empty($attendee)) {
3311
+			//note we should only be UPDATING attendees at this point.
3312
+			$updated_fields = array(
3313
+				'ATT_fname'     => $this->_req_data['ATT_fname'],
3314
+				'ATT_lname'     => $this->_req_data['ATT_lname'],
3315
+				'ATT_full_name' => $this->_req_data['ATT_fname'] . ' ' . $this->_req_data['ATT_lname'],
3316
+				'ATT_address'   => isset($this->_req_data['ATT_address']) ? $this->_req_data['ATT_address'] : '',
3317
+				'ATT_address2'  => isset($this->_req_data['ATT_address2']) ? $this->_req_data['ATT_address2'] : '',
3318
+				'ATT_city'      => isset($this->_req_data['ATT_city']) ? $this->_req_data['ATT_city'] : '',
3319
+				'STA_ID'        => isset($this->_req_data['STA_ID']) ? $this->_req_data['STA_ID'] : '',
3320
+				'CNT_ISO'       => isset($this->_req_data['CNT_ISO']) ? $this->_req_data['CNT_ISO'] : '',
3321
+				'ATT_zip'       => isset($this->_req_data['ATT_zip']) ? $this->_req_data['ATT_zip'] : '',
3322
+				'ATT_email'     => isset($this->_req_data['ATT_email']) ? $this->_req_data['ATT_email'] : '',
3323
+				'ATT_phone'     => isset($this->_req_data['ATT_phone']) ? $this->_req_data['ATT_phone'] : '',
3324
+			);
3325
+			foreach ($updated_fields as $field => $value) {
3326
+				$attendee->set($field, $value);
3327
+			}
3328
+			$success                   = $attendee->save();
3329
+			$attendee_update_callbacks = apply_filters(
3330
+				'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3331
+				array()
3332
+			);
3333
+			foreach ($attendee_update_callbacks as $a_callback) {
3334
+				if (false === call_user_func_array($a_callback, array($attendee, $this->_req_data))) {
3335
+					throw new EE_Error(
3336
+						sprintf(
3337
+							esc_html__(
3338
+								'The %s callback given for the "FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update" filter is not a valid callback.  Please check the spelling.',
3339
+								'event_espresso'
3340
+							),
3341
+							$a_callback
3342
+						)
3343
+					);
3344
+				}
3345
+			}
3346
+		}
3347
+		if ($success === false) {
3348
+			EE_Error::add_error(
3349
+				esc_html__(
3350
+					'Something went wrong with updating the meta table data for the registration.',
3351
+					'event_espresso'
3352
+				),
3353
+				__FILE__, __FUNCTION__, __LINE__
3354
+			);
3355
+		}
3356
+	}
3357
+
3358
+
3359
+	public function trash_cpt_item($post_id)
3360
+	{
3361
+	}
3362
+
3363
+
3364
+	public function delete_cpt_item($post_id)
3365
+	{
3366
+	}
3367
+
3368
+
3369
+	public function restore_cpt_item($post_id)
3370
+	{
3371
+	}
3372
+
3373
+
3374
+	protected function _restore_cpt_item($post_id, $revision_id)
3375
+	{
3376
+	}
3377
+
3378
+
3379
+	public function attendee_editor_metaboxes()
3380
+	{
3381
+		$this->verify_cpt_object();
3382
+		remove_meta_box(
3383
+			'postexcerpt',
3384
+			esc_html__('Excerpt', 'event_espresso'),
3385
+			'post_excerpt_meta_box',
3386
+			$this->_cpt_routes[$this->_req_action],
3387
+			'normal',
3388
+			'core'
3389
+		);
3390
+		remove_meta_box('commentstatusdiv', $this->_cpt_routes[$this->_req_action], 'normal', 'core');
3391
+		if (post_type_supports('espresso_attendees', 'excerpt')) {
3392
+			add_meta_box(
3393
+				'postexcerpt',
3394
+				esc_html__('Short Biography', 'event_espresso'),
3395
+				'post_excerpt_meta_box',
3396
+				$this->_cpt_routes[$this->_req_action],
3397
+				'normal'
3398
+			);
3399
+		}
3400
+		if (post_type_supports('espresso_attendees', 'comments')) {
3401
+			add_meta_box(
3402
+				'commentsdiv',
3403
+				esc_html__('Notes on the Contact', 'event_espresso'),
3404
+				'post_comment_meta_box',
3405
+				$this->_cpt_routes[$this->_req_action],
3406
+				'normal',
3407
+				'core'
3408
+			);
3409
+		}
3410
+		add_meta_box(
3411
+			'attendee_contact_info',
3412
+			esc_html__('Contact Info', 'event_espresso'),
3413
+			array($this, 'attendee_contact_info'),
3414
+			$this->_cpt_routes[$this->_req_action],
3415
+			'side',
3416
+			'core'
3417
+		);
3418
+		add_meta_box(
3419
+			'attendee_details_address',
3420
+			esc_html__('Address Details', 'event_espresso'),
3421
+			array($this, 'attendee_address_details'),
3422
+			$this->_cpt_routes[$this->_req_action],
3423
+			'normal',
3424
+			'core'
3425
+		);
3426
+		add_meta_box(
3427
+			'attendee_registrations',
3428
+			esc_html__('Registrations for this Contact', 'event_espresso'),
3429
+			array($this, 'attendee_registrations_meta_box'),
3430
+			$this->_cpt_routes[$this->_req_action],
3431
+			'normal',
3432
+			'high'
3433
+		);
3434
+	}
3435
+
3436
+
3437
+	/**
3438
+	 * Metabox for attendee contact info
3439
+	 *
3440
+	 * @param  WP_Post $post wp post object
3441
+	 * @return string attendee contact info ( and form )
3442
+	 * @throws DomainException
3443
+	 */
3444
+	public function attendee_contact_info($post)
3445
+	{
3446
+		//get attendee object ( should already have it )
3447
+		$this->_template_args['attendee'] = $this->_cpt_model_obj;
3448
+		$template                         = REG_TEMPLATE_PATH . 'attendee_contact_info_metabox_content.template.php';
3449
+		EEH_Template::display_template($template, $this->_template_args);
3450
+	}
3451
+
3452
+
3453
+	/**
3454
+	 * Metabox for attendee details
3455
+	 *
3456
+	 * @param  WP_Post $post wp post object
3457
+	 * @return string attendee address details (and form)
3458
+	 * @throws DomainException
3459
+	 */
3460
+	public function attendee_address_details($post)
3461
+	{
3462
+		//get attendee object (should already have it)
3463
+		$this->_template_args['attendee']     = $this->_cpt_model_obj;
3464
+		$this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3465
+			new EE_Question_Form_Input(
3466
+				EE_Question::new_instance(
3467
+					array(
3468
+						'QST_ID'           => 0,
3469
+						'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3470
+						'QST_system'       => 'admin-state',
3471
+					)
3472
+				),
3473
+				EE_Answer::new_instance(
3474
+					array(
3475
+						'ANS_ID'    => 0,
3476
+						'ANS_value' => $this->_cpt_model_obj->state_ID(),
3477
+					)
3478
+				),
3479
+				array(
3480
+					'input_id'       => 'STA_ID',
3481
+					'input_name'     => 'STA_ID',
3482
+					'input_prefix'   => '',
3483
+					'append_qstn_id' => false,
3484
+				)
3485
+			)
3486
+		);
3487
+		$this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3488
+			new EE_Question_Form_Input(
3489
+				EE_Question::new_instance(
3490
+					array(
3491
+						'QST_ID'           => 0,
3492
+						'QST_display_text' => esc_html__('Country', 'event_espresso'),
3493
+						'QST_system'       => 'admin-country',
3494
+					)
3495
+				),
3496
+				EE_Answer::new_instance(
3497
+					array(
3498
+						'ANS_ID'    => 0,
3499
+						'ANS_value' => $this->_cpt_model_obj->country_ID(),
3500
+					)
3501
+				),
3502
+				array(
3503
+					'input_id'       => 'CNT_ISO',
3504
+					'input_name'     => 'CNT_ISO',
3505
+					'input_prefix'   => '',
3506
+					'append_qstn_id' => false,
3507
+				)
3508
+			)
3509
+		);
3510
+		$template                             =
3511
+			REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3512
+		EEH_Template::display_template($template, $this->_template_args);
3513
+	}
3514
+
3515
+
3516
+	/**
3517
+	 *        _attendee_details
3518
+	 *
3519
+	 * @access protected
3520
+	 * @param $post
3521
+	 * @return void
3522
+	 * @throws DomainException
3523
+	 * @throws EE_Error
3524
+	 */
3525
+	public function attendee_registrations_meta_box($post)
3526
+	{
3527
+		$this->_template_args['attendee']      = $this->_cpt_model_obj;
3528
+		$this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3529
+		$template                              =
3530
+			REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3531
+		EEH_Template::display_template($template, $this->_template_args);
3532
+	}
3533
+
3534
+
3535
+	/**
3536
+	 * add in the form fields for the attendee edit
3537
+	 *
3538
+	 * @param  WP_Post $post wp post object
3539
+	 * @return string html for new form.
3540
+	 * @throws DomainException
3541
+	 */
3542
+	public function after_title_form_fields($post)
3543
+	{
3544
+		if ($post->post_type == 'espresso_attendees') {
3545
+			$template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3546
+			$template_args['attendee'] = $this->_cpt_model_obj;
3547
+			EEH_Template::display_template($template, $template_args);
3548
+		}
3549
+	}
3550
+
3551
+
3552
+	/**
3553
+	 *        _trash_or_restore_attendee
3554
+	 *
3555
+	 * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3556
+	 * @return void
3557
+	 * @throws EE_Error
3558
+	 * @access protected
3559
+	 */
3560
+	protected function _trash_or_restore_attendees($trash = true)
3561
+	{
3562
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3563
+		$ATT_MDL = EEM_Attendee::instance();
3564
+		$success = 1;
3565
+		//Checkboxes
3566
+		if ( ! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
3567
+			// if array has more than one element than success message should be plural
3568
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
3569
+			// cycle thru checkboxes
3570
+			while (list($ATT_ID, $value) = each($this->_req_data['checkbox'])) {
3571
+				$updated = $trash ? $ATT_MDL->update_by_ID(array('status' => 'trash'), $ATT_ID)
3572
+					: $ATT_MDL->update_by_ID(array('status' => 'publish'), $ATT_ID);
3573
+				if ( ! $updated) {
3574
+					$success = 0;
3575
+				}
3576
+			}
3577
+		} else {
3578
+			// grab single id and delete
3579
+			$ATT_ID = absint($this->_req_data['ATT_ID']);
3580
+			//get attendee
3581
+			$att     = $ATT_MDL->get_one_by_ID($ATT_ID);
3582
+			$updated = $trash ? $att->set_status('trash') : $att->set_status('publish');
3583
+			$updated = $att->save();
3584
+			if ( ! $updated) {
3585
+				$success = 0;
3586
+			}
3587
+		}
3588
+		$what        = $success > 1
3589
+			? esc_html__('Contacts', 'event_espresso')
3590
+			: esc_html__('Contact', 'event_espresso');
3591
+		$action_desc = $trash
3592
+			? esc_html__('moved to the trash', 'event_espresso')
3593
+			: esc_html__('restored', 'event_espresso');
3594
+		$this->_redirect_after_action($success, $what, $action_desc, array('action' => 'contact_list'));
3595
+	}
3596 3596
 
3597 3597
 }
Please login to merge, or discard this patch.
core/libraries/shortcodes/EE_Venue_Shortcodes.lib.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -176,7 +176,7 @@
 block discarded – undo
176 176
     /**
177 177
      * This retrieves the EE_Venue from the available data object.
178 178
      *
179
-     * @return EE_Venue|null
179
+     * @return EE_Base_Class|null
180 180
      * @throws EE_Error
181 181
      * @throws EntityNotFoundException
182 182
      */
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -90,7 +90,7 @@  discard block
 block discarded – undo
90 90
     {
91 91
         $this->_venue = $this->_get_venue();
92 92
         //If there is no venue object by now then get out.
93
-        if (! $this->_venue instanceof EE_Venue) {
93
+        if ( ! $this->_venue instanceof EE_Venue) {
94 94
             return '';
95 95
         }
96 96
 
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
 
189 189
         //if no event, then let's see if there is a reg_obj.  If there IS, then we'll try and grab the event from the
190 190
         // reg_obj instead.
191
-        if (! $this->_event instanceof EE_Event) {
191
+        if ( ! $this->_event instanceof EE_Event) {
192 192
             $aee = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null;
193 193
             $aee = $this->_extra_data instanceof EE_Messages_Addressee ? $this->_extra_data : $aee;
194 194
 
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
 
206 206
             //if STILL empty event, let's try to get the first event in the list of events via EE_Messages_Addressee
207 207
             // and use that.
208
-            $this->_event       = ! $this->_event instanceof EE_Event && $aee instanceof EE_Messages_Addressee
208
+            $this->_event = ! $this->_event instanceof EE_Event && $aee instanceof EE_Messages_Addressee
209 209
                 ? reset($aee->events)
210 210
                 : $this->_event;
211 211
         }
@@ -229,7 +229,7 @@  discard block
 block discarded – undo
229 229
     private function _venue($field)
230 230
     {
231 231
 
232
-        if (! $this->_venue instanceof EE_Venue) {
232
+        if ( ! $this->_venue instanceof EE_Venue) {
233 233
             return '';
234 234
         } //no venue so get out.
235 235
 
@@ -252,11 +252,11 @@  discard block
 block discarded – undo
252 252
                 break;
253 253
 
254 254
             case 'image':
255
-                return '<img src="' . $this->_venue->feature_image_url(array(200, 200,))
256
-                       . '" alt="' . sprintf(
255
+                return '<img src="'.$this->_venue->feature_image_url(array(200, 200,))
256
+                       . '" alt="'.sprintf(
257 257
                            esc_attr__('%s Feature Image', 'event_espresso'),
258 258
                            $this->_venue->get('VNU_name')
259
-                       ) . '" />';
259
+                       ).'" />';
260 260
                 break;
261 261
 
262 262
             case 'phone':
Please login to merge, or discard this patch.
Indentation   +313 added lines, -313 removed lines patch added patch discarded remove patch
@@ -19,317 +19,317 @@
 block discarded – undo
19 19
 {
20 20
 
21 21
 
22
-    /**
23
-     * Will hold the EE_Event if available
24
-     *
25
-     * @var EE_Event
26
-     */
27
-    protected $_event;
28
-
29
-    /**
30
-     * Will hold the EE_Venue if available
31
-     *
32
-     * @var EE_Venue
33
-     */
34
-    protected $_venue;
35
-
36
-
37
-    /**
38
-     * Initialize properties
39
-     */
40
-    protected function _init_props()
41
-    {
42
-        $this->label       = esc_html__('Venue Shortcodes', 'event_espresso');
43
-        $this->description = esc_html__('All shortcodes specific to venue related data', 'event_espresso');
44
-        $this->_shortcodes = array(
45
-            '[VENUE_TITLE]'             => esc_html__('The title for the event venue', 'event_espresso'),
46
-            '[VENUE_DESCRIPTION]'       => esc_html__('The description for the event venue', 'event_espresso'),
47
-            '[VENUE_URL]'               => esc_html__('A url to a webpage for the venue', 'event_espresso'),
48
-            '[VENUE_DETAILS_URL]'       => sprintf(
49
-                esc_html__(
50
-                    'This shortcode outputs the url or website address to the venue details page on this website. This differs from %s which outputs what is entered in the "url" field in the venue details page.',
51
-                    'event_espresso'
52
-                ),
53
-                '[VENUE_URL]'
54
-            ),
55
-            '[VENUE_IMAGE]'             => esc_html__('An image representing the event venue', 'event_espresso'),
56
-            '[VENUE_PHONE]'             => esc_html__('The phone number for the venue', 'event_espresso'),
57
-            '[VENUE_ADDRESS]'           => esc_html__('The address for the venue', 'event_espresso'),
58
-            '[VENUE_ADDRESS2]'          => esc_html__('Address 2 for the venue', 'event_espresso'),
59
-            '[VENUE_CITY]'              => esc_html__('The city the venue is in', 'event_espresso'),
60
-            '[VENUE_STATE]'             => esc_html__('The state the venue is located in', 'event_espresso'),
61
-            '[VENUE_COUNTRY]'           => esc_html__('The country the venue is located in', 'event_espresso'),
62
-            '[VENUE_FORMATTED_ADDRESS]' => esc_html__(
63
-                'This just outputs the venue address in a semantic address format.',
64
-                'event_espresso'
65
-            ),
66
-            '[VENUE_ZIP]'               => esc_html__('The zip code for the venue address', 'event_espresso'),
67
-            '[VENUE_META_*]'            => esc_html__(
68
-                'This is a special dynamic shortcode. After the "*", add the exact name for your custom field, if there is a value set for that custom field within the venue then it will be output in place of this shortcode.',
69
-                'event_espresso'
70
-            ),
71
-            '[GOOGLE_MAP_URL]'          => esc_html__(
72
-                'URL for the google map associated with the venue.',
73
-                'event_espresso'
74
-            ),
75
-            '[GOOGLE_MAP_LINK]'         => esc_html__('Link to a google map for the venue', 'event_espresso'),
76
-            '[GOOGLE_MAP_IMAGE]'        => esc_html__('Google map for venue wrapped in image tags', 'event_espresso'),
77
-        );
78
-    }
79
-
80
-
81
-    /**
82
-     * Parse incoming shortcode
83
-     *
84
-     * @param string $shortcode
85
-     * @return string
86
-     * @throws EE_Error
87
-     * @throws EntityNotFoundException
88
-     */
89
-    protected function _parser($shortcode)
90
-    {
91
-        $this->_venue = $this->_get_venue();
92
-        //If there is no venue object by now then get out.
93
-        if (! $this->_venue instanceof EE_Venue) {
94
-            return '';
95
-        }
96
-
97
-        switch ($shortcode) {
98
-            case '[VENUE_TITLE]':
99
-                return $this->_venue('title');
100
-                break;
101
-
102
-            case '[VENUE_DESCRIPTION]':
103
-                return $this->_venue('description');
104
-                break;
105
-
106
-            case '[VENUE_URL]':
107
-                return $this->_venue('url');
108
-                break;
109
-
110
-            case '[VENUE_IMAGE]':
111
-                return $this->_venue('image');
112
-                break;
113
-
114
-            case '[VENUE_PHONE]':
115
-                return $this->_venue('phone');
116
-                break;
117
-
118
-            case '[VENUE_ADDRESS]':
119
-                return $this->_venue('address');
120
-                break;
121
-
122
-            case '[VENUE_ADDRESS2]':
123
-                return $this->_venue('address2');
124
-                break;
125
-
126
-            case '[VENUE_CITY]':
127
-                return $this->_venue('city');
128
-                break;
129
-
130
-            case '[VENUE_COUNTRY]':
131
-                return $this->_venue('country');
132
-                break;
133
-
134
-            case '[VENUE_STATE]':
135
-                return $this->_venue('state');
136
-                break;
137
-
138
-            case '[VENUE_ZIP]':
139
-                return $this->_venue('zip');
140
-                break;
141
-
142
-            case '[VENUE_FORMATTED_ADDRESS]':
143
-                return $this->_venue('formatted_address');
144
-                break;
145
-
146
-            case '[GOOGLE_MAP_URL]':
147
-                return $this->_venue('gmap_url');
148
-                break;
149
-
150
-            case '[GOOGLE_MAP_LINK]':
151
-                return $this->_venue('gmap_link');
152
-                break;
153
-
154
-            case '[GOOGLE_MAP_IMAGE]':
155
-                return $this->_venue('gmap_link_img');
156
-                break;
157
-
158
-            case '[VENUE_DETAILS_URL]':
159
-                return $this->_venue('permalink');
160
-                break;
161
-
162
-        }
163
-
164
-        if (strpos($shortcode, '[VENUE_META_*') !== false) {
165
-            $shortcode = str_replace('[VENUE_META_*', '', $shortcode);
166
-            $shortcode = trim(str_replace(']', '', $shortcode));
167
-
168
-            //pull the meta value from the venue post
169
-            $venue_meta = $this->_venue->get_post_meta($shortcode, true);
170
-
171
-            return ! empty($venue_meta) ? $venue_meta : '';
172
-
173
-        }
174
-    }
175
-
176
-    /**
177
-     * This retrieves the EE_Venue from the available data object.
178
-     *
179
-     * @return EE_Venue|null
180
-     * @throws EE_Error
181
-     * @throws EntityNotFoundException
182
-     */
183
-    private function _get_venue()
184
-    {
185
-
186
-        //we need the EE_Event object to get the venue.
187
-        $this->_event = $this->_data instanceof EE_Event ? $this->_data : null;
188
-
189
-        //if no event, then let's see if there is a reg_obj.  If there IS, then we'll try and grab the event from the
190
-        // reg_obj instead.
191
-        if (! $this->_event instanceof EE_Event) {
192
-            $aee = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null;
193
-            $aee = $this->_extra_data instanceof EE_Messages_Addressee ? $this->_extra_data : $aee;
194
-
195
-            $this->_event = $aee instanceof EE_Messages_Addressee && $aee->reg_obj instanceof EE_Registration
196
-                ? $aee->reg_obj->event()
197
-                : null;
198
-
199
-            //if still empty do we have a ticket data item?
200
-            $this->_event = ! $this->_event instanceof EE_Event
201
-                            && $this->_data instanceof EE_Ticket
202
-                            && $this->_extra_data['data'] instanceof EE_Messages_Addressee
203
-                ? $this->_extra_data['data']->tickets[$this->_data->ID()]['EE_Event']
204
-                : $this->_event;
205
-
206
-            //if STILL empty event, let's try to get the first event in the list of events via EE_Messages_Addressee
207
-            // and use that.
208
-            $this->_event       = ! $this->_event instanceof EE_Event && $aee instanceof EE_Messages_Addressee
209
-                ? reset($aee->events)
210
-                : $this->_event;
211
-        }
212
-
213
-        //If we have an event object use it to pull the venue.
214
-        if ($this->_event instanceof EE_Event) {
215
-            return $this->_event->get_first_related('Venue');
216
-        }
217
-
218
-        return null;
219
-    }
220
-
221
-    /**
222
-     * This retrieves the specified venue information
223
-     *
224
-     * @param string $field What Venue field to retrieve
225
-     * @return string What was retrieved!
226
-     * @throws EE_Error
227
-     * @throws EntityNotFoundException
228
-     */
229
-    private function _venue($field)
230
-    {
231
-
232
-        if (! $this->_venue instanceof EE_Venue) {
233
-            return '';
234
-        } //no venue so get out.
235
-
236
-        switch ($field) {
237
-            case 'title':
238
-                return $this->_venue->get('VNU_name');
239
-                break;
240
-
241
-            case 'description':
242
-                return $this->_venue->get('VNU_desc');
243
-                break;
244
-
245
-            case 'url':
246
-                $url = $this->_venue->get('VNU_url');
247
-                return empty($url) ? $this->_venue->get_permalink() : $url;
248
-                break;
249
-
250
-            case 'permalink':
251
-                return $this->_venue->get_permalink();
252
-                break;
253
-
254
-            case 'image':
255
-                return '<img src="' . $this->_venue->feature_image_url(array(200, 200,))
256
-                       . '" alt="' . sprintf(
257
-                           esc_attr__('%s Feature Image', 'event_espresso'),
258
-                           $this->_venue->get('VNU_name')
259
-                       ) . '" />';
260
-                break;
261
-
262
-            case 'phone':
263
-                return $this->_venue->get('VNU_phone');
264
-                break;
265
-
266
-            case 'address':
267
-                return $this->_venue->get('VNU_address');
268
-                break;
269
-
270
-            case 'address2':
271
-                return $this->_venue->get('VNU_address2');
272
-                break;
273
-
274
-            case 'city':
275
-                return $this->_venue->get('VNU_city');
276
-                break;
277
-
278
-            case 'state':
279
-                $state = $this->_venue->state_obj();
280
-                return is_object($state) ? $state->get('STA_name') : '';
281
-                break;
282
-
283
-            case 'country':
284
-                $country = $this->_venue->country_obj();
285
-                return is_object($country) ? $country->get('CNT_name') : '';
286
-                break;
287
-
288
-            case 'zip':
289
-                return $this->_venue->get('VNU_zip');
290
-                break;
291
-
292
-            case 'formatted_address':
293
-                return EEH_Address::format($this->_venue);
294
-                break;
295
-
296
-            case 'gmap_link':
297
-            case 'gmap_url':
298
-            case 'gmap_link_img':
299
-                $atts = $this->get_map_attributes($this->_venue, $field);
300
-                return EEH_Maps::google_map_link($atts);
301
-                break;
302
-        }
303
-        return '';
304
-    }
305
-
306
-
307
-    /**
308
-     * Generates the attributes for retrieving a google_map artifact.
309
-     *
310
-     * @param EE_Venue $venue
311
-     * @param string   $field
312
-     * @return array
313
-     * @throws EE_Error
314
-     */
315
-    protected function get_map_attributes(EE_Venue $venue, $field = 'gmap_link')
316
-    {
317
-        $state   = $venue->state_obj();
318
-        $country = $venue->country_obj();
319
-        $atts    = array(
320
-            'id'      => $venue->ID(),
321
-            'address' => $venue->get('VNU_address'),
322
-            'city'    => $venue->get('VNU_city'),
323
-            'state'   => is_object($state) ? $state->get('STA_name') : '',
324
-            'zip'     => $venue->get('VNU_zip'),
325
-            'country' => is_object($country) ? $country->get('CNT_name') : '',
326
-            'type'    => $field === 'gmap_link' ? 'url' : 'map',
327
-            'map_w'   => 200,
328
-            'map_h'   => 200,
329
-        );
330
-        if ($field === 'gmap_url') {
331
-            $atts['type'] = 'url_only';
332
-        }
333
-        return $atts;
334
-    }
22
+	/**
23
+	 * Will hold the EE_Event if available
24
+	 *
25
+	 * @var EE_Event
26
+	 */
27
+	protected $_event;
28
+
29
+	/**
30
+	 * Will hold the EE_Venue if available
31
+	 *
32
+	 * @var EE_Venue
33
+	 */
34
+	protected $_venue;
35
+
36
+
37
+	/**
38
+	 * Initialize properties
39
+	 */
40
+	protected function _init_props()
41
+	{
42
+		$this->label       = esc_html__('Venue Shortcodes', 'event_espresso');
43
+		$this->description = esc_html__('All shortcodes specific to venue related data', 'event_espresso');
44
+		$this->_shortcodes = array(
45
+			'[VENUE_TITLE]'             => esc_html__('The title for the event venue', 'event_espresso'),
46
+			'[VENUE_DESCRIPTION]'       => esc_html__('The description for the event venue', 'event_espresso'),
47
+			'[VENUE_URL]'               => esc_html__('A url to a webpage for the venue', 'event_espresso'),
48
+			'[VENUE_DETAILS_URL]'       => sprintf(
49
+				esc_html__(
50
+					'This shortcode outputs the url or website address to the venue details page on this website. This differs from %s which outputs what is entered in the "url" field in the venue details page.',
51
+					'event_espresso'
52
+				),
53
+				'[VENUE_URL]'
54
+			),
55
+			'[VENUE_IMAGE]'             => esc_html__('An image representing the event venue', 'event_espresso'),
56
+			'[VENUE_PHONE]'             => esc_html__('The phone number for the venue', 'event_espresso'),
57
+			'[VENUE_ADDRESS]'           => esc_html__('The address for the venue', 'event_espresso'),
58
+			'[VENUE_ADDRESS2]'          => esc_html__('Address 2 for the venue', 'event_espresso'),
59
+			'[VENUE_CITY]'              => esc_html__('The city the venue is in', 'event_espresso'),
60
+			'[VENUE_STATE]'             => esc_html__('The state the venue is located in', 'event_espresso'),
61
+			'[VENUE_COUNTRY]'           => esc_html__('The country the venue is located in', 'event_espresso'),
62
+			'[VENUE_FORMATTED_ADDRESS]' => esc_html__(
63
+				'This just outputs the venue address in a semantic address format.',
64
+				'event_espresso'
65
+			),
66
+			'[VENUE_ZIP]'               => esc_html__('The zip code for the venue address', 'event_espresso'),
67
+			'[VENUE_META_*]'            => esc_html__(
68
+				'This is a special dynamic shortcode. After the "*", add the exact name for your custom field, if there is a value set for that custom field within the venue then it will be output in place of this shortcode.',
69
+				'event_espresso'
70
+			),
71
+			'[GOOGLE_MAP_URL]'          => esc_html__(
72
+				'URL for the google map associated with the venue.',
73
+				'event_espresso'
74
+			),
75
+			'[GOOGLE_MAP_LINK]'         => esc_html__('Link to a google map for the venue', 'event_espresso'),
76
+			'[GOOGLE_MAP_IMAGE]'        => esc_html__('Google map for venue wrapped in image tags', 'event_espresso'),
77
+		);
78
+	}
79
+
80
+
81
+	/**
82
+	 * Parse incoming shortcode
83
+	 *
84
+	 * @param string $shortcode
85
+	 * @return string
86
+	 * @throws EE_Error
87
+	 * @throws EntityNotFoundException
88
+	 */
89
+	protected function _parser($shortcode)
90
+	{
91
+		$this->_venue = $this->_get_venue();
92
+		//If there is no venue object by now then get out.
93
+		if (! $this->_venue instanceof EE_Venue) {
94
+			return '';
95
+		}
96
+
97
+		switch ($shortcode) {
98
+			case '[VENUE_TITLE]':
99
+				return $this->_venue('title');
100
+				break;
101
+
102
+			case '[VENUE_DESCRIPTION]':
103
+				return $this->_venue('description');
104
+				break;
105
+
106
+			case '[VENUE_URL]':
107
+				return $this->_venue('url');
108
+				break;
109
+
110
+			case '[VENUE_IMAGE]':
111
+				return $this->_venue('image');
112
+				break;
113
+
114
+			case '[VENUE_PHONE]':
115
+				return $this->_venue('phone');
116
+				break;
117
+
118
+			case '[VENUE_ADDRESS]':
119
+				return $this->_venue('address');
120
+				break;
121
+
122
+			case '[VENUE_ADDRESS2]':
123
+				return $this->_venue('address2');
124
+				break;
125
+
126
+			case '[VENUE_CITY]':
127
+				return $this->_venue('city');
128
+				break;
129
+
130
+			case '[VENUE_COUNTRY]':
131
+				return $this->_venue('country');
132
+				break;
133
+
134
+			case '[VENUE_STATE]':
135
+				return $this->_venue('state');
136
+				break;
137
+
138
+			case '[VENUE_ZIP]':
139
+				return $this->_venue('zip');
140
+				break;
141
+
142
+			case '[VENUE_FORMATTED_ADDRESS]':
143
+				return $this->_venue('formatted_address');
144
+				break;
145
+
146
+			case '[GOOGLE_MAP_URL]':
147
+				return $this->_venue('gmap_url');
148
+				break;
149
+
150
+			case '[GOOGLE_MAP_LINK]':
151
+				return $this->_venue('gmap_link');
152
+				break;
153
+
154
+			case '[GOOGLE_MAP_IMAGE]':
155
+				return $this->_venue('gmap_link_img');
156
+				break;
157
+
158
+			case '[VENUE_DETAILS_URL]':
159
+				return $this->_venue('permalink');
160
+				break;
161
+
162
+		}
163
+
164
+		if (strpos($shortcode, '[VENUE_META_*') !== false) {
165
+			$shortcode = str_replace('[VENUE_META_*', '', $shortcode);
166
+			$shortcode = trim(str_replace(']', '', $shortcode));
167
+
168
+			//pull the meta value from the venue post
169
+			$venue_meta = $this->_venue->get_post_meta($shortcode, true);
170
+
171
+			return ! empty($venue_meta) ? $venue_meta : '';
172
+
173
+		}
174
+	}
175
+
176
+	/**
177
+	 * This retrieves the EE_Venue from the available data object.
178
+	 *
179
+	 * @return EE_Venue|null
180
+	 * @throws EE_Error
181
+	 * @throws EntityNotFoundException
182
+	 */
183
+	private function _get_venue()
184
+	{
185
+
186
+		//we need the EE_Event object to get the venue.
187
+		$this->_event = $this->_data instanceof EE_Event ? $this->_data : null;
188
+
189
+		//if no event, then let's see if there is a reg_obj.  If there IS, then we'll try and grab the event from the
190
+		// reg_obj instead.
191
+		if (! $this->_event instanceof EE_Event) {
192
+			$aee = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null;
193
+			$aee = $this->_extra_data instanceof EE_Messages_Addressee ? $this->_extra_data : $aee;
194
+
195
+			$this->_event = $aee instanceof EE_Messages_Addressee && $aee->reg_obj instanceof EE_Registration
196
+				? $aee->reg_obj->event()
197
+				: null;
198
+
199
+			//if still empty do we have a ticket data item?
200
+			$this->_event = ! $this->_event instanceof EE_Event
201
+							&& $this->_data instanceof EE_Ticket
202
+							&& $this->_extra_data['data'] instanceof EE_Messages_Addressee
203
+				? $this->_extra_data['data']->tickets[$this->_data->ID()]['EE_Event']
204
+				: $this->_event;
205
+
206
+			//if STILL empty event, let's try to get the first event in the list of events via EE_Messages_Addressee
207
+			// and use that.
208
+			$this->_event       = ! $this->_event instanceof EE_Event && $aee instanceof EE_Messages_Addressee
209
+				? reset($aee->events)
210
+				: $this->_event;
211
+		}
212
+
213
+		//If we have an event object use it to pull the venue.
214
+		if ($this->_event instanceof EE_Event) {
215
+			return $this->_event->get_first_related('Venue');
216
+		}
217
+
218
+		return null;
219
+	}
220
+
221
+	/**
222
+	 * This retrieves the specified venue information
223
+	 *
224
+	 * @param string $field What Venue field to retrieve
225
+	 * @return string What was retrieved!
226
+	 * @throws EE_Error
227
+	 * @throws EntityNotFoundException
228
+	 */
229
+	private function _venue($field)
230
+	{
231
+
232
+		if (! $this->_venue instanceof EE_Venue) {
233
+			return '';
234
+		} //no venue so get out.
235
+
236
+		switch ($field) {
237
+			case 'title':
238
+				return $this->_venue->get('VNU_name');
239
+				break;
240
+
241
+			case 'description':
242
+				return $this->_venue->get('VNU_desc');
243
+				break;
244
+
245
+			case 'url':
246
+				$url = $this->_venue->get('VNU_url');
247
+				return empty($url) ? $this->_venue->get_permalink() : $url;
248
+				break;
249
+
250
+			case 'permalink':
251
+				return $this->_venue->get_permalink();
252
+				break;
253
+
254
+			case 'image':
255
+				return '<img src="' . $this->_venue->feature_image_url(array(200, 200,))
256
+					   . '" alt="' . sprintf(
257
+						   esc_attr__('%s Feature Image', 'event_espresso'),
258
+						   $this->_venue->get('VNU_name')
259
+					   ) . '" />';
260
+				break;
261
+
262
+			case 'phone':
263
+				return $this->_venue->get('VNU_phone');
264
+				break;
265
+
266
+			case 'address':
267
+				return $this->_venue->get('VNU_address');
268
+				break;
269
+
270
+			case 'address2':
271
+				return $this->_venue->get('VNU_address2');
272
+				break;
273
+
274
+			case 'city':
275
+				return $this->_venue->get('VNU_city');
276
+				break;
277
+
278
+			case 'state':
279
+				$state = $this->_venue->state_obj();
280
+				return is_object($state) ? $state->get('STA_name') : '';
281
+				break;
282
+
283
+			case 'country':
284
+				$country = $this->_venue->country_obj();
285
+				return is_object($country) ? $country->get('CNT_name') : '';
286
+				break;
287
+
288
+			case 'zip':
289
+				return $this->_venue->get('VNU_zip');
290
+				break;
291
+
292
+			case 'formatted_address':
293
+				return EEH_Address::format($this->_venue);
294
+				break;
295
+
296
+			case 'gmap_link':
297
+			case 'gmap_url':
298
+			case 'gmap_link_img':
299
+				$atts = $this->get_map_attributes($this->_venue, $field);
300
+				return EEH_Maps::google_map_link($atts);
301
+				break;
302
+		}
303
+		return '';
304
+	}
305
+
306
+
307
+	/**
308
+	 * Generates the attributes for retrieving a google_map artifact.
309
+	 *
310
+	 * @param EE_Venue $venue
311
+	 * @param string   $field
312
+	 * @return array
313
+	 * @throws EE_Error
314
+	 */
315
+	protected function get_map_attributes(EE_Venue $venue, $field = 'gmap_link')
316
+	{
317
+		$state   = $venue->state_obj();
318
+		$country = $venue->country_obj();
319
+		$atts    = array(
320
+			'id'      => $venue->ID(),
321
+			'address' => $venue->get('VNU_address'),
322
+			'city'    => $venue->get('VNU_city'),
323
+			'state'   => is_object($state) ? $state->get('STA_name') : '',
324
+			'zip'     => $venue->get('VNU_zip'),
325
+			'country' => is_object($country) ? $country->get('CNT_name') : '',
326
+			'type'    => $field === 'gmap_link' ? 'url' : 'map',
327
+			'map_w'   => 200,
328
+			'map_h'   => 200,
329
+		);
330
+		if ($field === 'gmap_url') {
331
+			$atts['type'] = 'url_only';
332
+		}
333
+		return $atts;
334
+	}
335 335
 }
Please login to merge, or discard this patch.
core/EE_Maintenance_Mode.core.php 1 patch
Indentation   +317 added lines, -317 removed lines patch added patch discarded remove patch
@@ -17,362 +17,362 @@
 block discarded – undo
17 17
 class EE_Maintenance_Mode implements ResettableInterface
18 18
 {
19 19
 
20
-    /**
21
-     * constants available to client code for interpreting the values of EE_Maintenance_Mode::level().
22
-     * level_0_not_in_maintenance means the site is NOT in maintenance mode (so everything's normal)
23
-     */
24
-    const level_0_not_in_maintenance = 0;
25
-
26
-    /**
27
-     * level_1_frontend_only_maintenance means that the site's frontend EE code should be completely disabled
28
-     * but the admin backend should be running as normal. Maybe an admin can view the frontend though
29
-     */
30
-    const level_1_frontend_only_maintenance = 1;
31
-
32
-    /**
33
-     * level_2_complete_maintenance means the frontend AND EE backend code are disabled. The only system running
34
-     * is the maintenance mode stuff, which will require users to update all addons, and then finish running all
35
-     * migration scripts before taking the site out of maintenance mode
36
-     */
37
-    const level_2_complete_maintenance = 2;
38
-
39
-    /**
40
-     * the name of the option which stores the current level of maintenance mode
41
-     */
42
-    const option_name_maintenance_mode = 'ee_maintenance_mode';
43
-
44
-
45
-    /**
46
-     * @var EE_Maintenance_Mode $_instance
47
-     */
48
-    private static $_instance;
49
-
50
-    /**
51
-     * @var EE_Registry $EE
52
-     */
53
-    protected $EE;
54
-
55
-
56
-
57
-    /**
58
-     * @singleton method used to instantiate class object
59
-     * @return EE_Maintenance_Mode
60
-     */
61
-    public static function instance()
62
-    {
63
-        // check if class object is instantiated
64
-        if (! self::$_instance instanceof EE_Maintenance_Mode) {
65
-            self::$_instance = new self();
66
-        }
67
-        return self::$_instance;
68
-    }
69
-
70
-
71
-
72
-    /**
73
-     * Resets maintenance mode (mostly just re-checks whether or not we should be in maintenance mode)
74
-     *
75
-     * @return EE_Maintenance_Mode
76
-     */
77
-    public static function reset()
78
-    {
79
-        self::instance()->set_maintenance_mode_if_db_old();
80
-        return self::instance();
81
-    }
82
-
83
-
84
-
85
-    /**
86
-     *private constructor to prevent direct creation
87
-     */
88
-    private function __construct()
89
-    {
90
-        // if M-Mode level 2 is engaged, we still need basic assets loaded
91
-        add_action('wp_enqueue_scripts', array($this, 'load_assets_required_for_m_mode'));
92
-        // shut 'er down down for maintenance ?
93
-        add_filter('the_content', array($this, 'the_content'), 2);
94
-        // add powered by EE msg
95
-        add_action('shutdown', array($this, 'display_maintenance_mode_notice'), 10);
96
-    }
97
-
98
-
99
-
100
-    /**
101
-     * retrieves the maintenance mode option value from the db
102
-     *
103
-     * @return int
104
-     */
105
-    public function real_level()
106
-    {
107
-        return (int) get_option(self::option_name_maintenance_mode, EE_Maintenance_Mode::level_0_not_in_maintenance);
108
-    }
109
-
110
-
111
-
112
-    /**
113
-     * Returns whether or not the models reportedly are able to run queries or not
114
-     * (ie, if the system thinks their tables are present and up-to-date).
115
-     *
116
-     * @return boolean
117
-     */
118
-    public function models_can_query()
119
-    {
120
-        return $this->real_level() !== EE_Maintenance_Mode::level_2_complete_maintenance;
121
-    }
122
-
123
-
124
-
125
-    /**
126
-     * Determines whether or not we're in maintenance mode and what level. However, while the site
127
-     * is in level 1 maintenance, and an admin visits the frontend, this function makes it appear
128
-     * to them as if teh site isn't in maintenance mode.
129
-     * EE_Maintenance_Mode::level_0_not_in_maintenance => not in maintenance mode (in normal mode)
130
-     * EE_Maintenance_Mode::level_1_frontend_only_maintenance=> frontend-only maintenance mode
131
-     * EE_Maintenance_Mode::level_2_complete_maintenance => frontend and backend maintenance mode
132
-     *
133
-     * @return int
134
-     */
135
-    public function level()
136
-    {
137
-        $maintenance_mode_level = $this->real_level();
138
-        // if this is an admin request, we'll be honest... except if it's ajax, because that might be from the frontend
139
-        if (
140
-            $maintenance_mode_level === EE_Maintenance_Mode::level_1_frontend_only_maintenance// we're in level 1
141
-            && ((defined('DOING_AJAX') && DOING_AJAX) || ! is_admin()) // on non-ajax frontend requests
142
-            && current_user_can('administrator') // when the user is an admin
143
-        ) {
144
-            $maintenance_mode_level = EE_Maintenance_Mode::level_0_not_in_maintenance;
145
-        }
146
-        return $maintenance_mode_level;
147
-    }
148
-
149
-
150
-
151
-    /**
152
-     * Determines if we need to put EE in maintenance mode because the database needs updating
153
-     *
154
-     * @return boolean true if DB is old and maintenance mode was triggered; false otherwise
155
-     */
156
-    public function set_maintenance_mode_if_db_old()
157
-    {
158
-        EE_Registry::instance()->load_core('Data_Migration_Manager');
159
-        if (EE_Data_Migration_Manager::instance()->check_for_applicable_data_migration_scripts()) {
160
-            update_option(self::option_name_maintenance_mode, self::level_2_complete_maintenance);
161
-            return true;
162
-        }
163
-        if ($this->level() === self::level_2_complete_maintenance) {
164
-            //we also want to handle the opposite: if the site is mm2, but there aren't any migrations to run
165
-            //then we shouldn't be in mm2. (Maybe an addon got deactivated?)
166
-            update_option(self::option_name_maintenance_mode, self::level_0_not_in_maintenance);
167
-            return false;
168
-        }
169
-        return false;
170
-    }
171
-
172
-
173
-
174
-    /**
175
-     * Updates the maintenance level on the site
176
-     *
177
-     * @param int $level
178
-     * @return void
179
-     */
180
-    public function set_maintenance_level($level)
181
-    {
182
-        do_action('AHEE__EE_Maintenance_Mode__set_maintenance_level', $level);
183
-        update_option(self::option_name_maintenance_mode, (int)$level);
184
-    }
185
-
186
-
187
-
188
-    /**
189
-     * returns TRUE if M-Mode is engaged and the current request is not for the admin
190
-     *
191
-     * @return    string
192
-     */
193
-    public static function disable_frontend_for_maintenance()
194
-    {
195
-        return (! is_admin() && EE_Maintenance_Mode::instance()->level());
196
-    }
197
-
198
-
199
-
200
-    /**
201
-     * @return void
202
-     */
203
-    public function load_assets_required_for_m_mode()
204
-    {
205
-        if (
206
-            $this->real_level() === EE_Maintenance_Mode::level_2_complete_maintenance
207
-            && ! wp_script_is('espresso_core')
208
-        ) {
209
-            wp_register_style(
210
-                'espresso_default',
211
-                EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
212
-                array('dashicons'),
213
-                EVENT_ESPRESSO_VERSION
214
-            );
215
-            wp_enqueue_style('espresso_default');
216
-            wp_register_script(
217
-                'espresso_core',
218
-                EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
219
-                array('jquery'),
220
-                EVENT_ESPRESSO_VERSION,
221
-                true
222
-            );
223
-            wp_enqueue_script('espresso_core');
224
-        }
225
-    }
226
-
227
-
228
-
229
-    /**
230
-     * replacement EE CPT template that displays message notifying site visitors
231
-     * that EE has been temporarily placed into maintenance mode
232
-     * does NOT get called on non-EE-CPT requests
233
-     *
234
-     * @return    string
235
-     */
236
-    public static function template_include()
237
-    {
238
-        // shut 'er down down for maintenance ? then don't use any of our templates for our endpoints
239
-        return get_template_directory() . '/index.php';
240
-    }
241
-
242
-
243
-
244
-    /**
245
-     * displays message notifying site visitors that EE has been temporarily
246
-     * placed into maintenance mode when post_type != EE CPT
247
-     *
248
-     * @param string $the_content
249
-     * @return string
250
-     */
251
-    public function the_content($the_content)
252
-    {
253
-        // check if M-mode is engaged and for EE shortcode
254
-        if ($this->level() && strpos($the_content, '[ESPRESSO_') !== false) {
255
-            // this can eventually be moved to a template, or edited via admin. But for now...
256
-            $the_content = sprintf(
257
-                esc_html__(
258
-                    '%sMaintenance Mode%sEvent Registration has been temporarily closed while system maintenance is being performed. We\'re sorry for any inconveniences this may have caused. Please try back again later.%s',
259
-                    'event_espresso'
260
-                ),
261
-                '<h3>',
262
-                '</h3><p>',
263
-                '</p>'
264
-            );
265
-        }
266
-        return $the_content;
267
-    }
20
+	/**
21
+	 * constants available to client code for interpreting the values of EE_Maintenance_Mode::level().
22
+	 * level_0_not_in_maintenance means the site is NOT in maintenance mode (so everything's normal)
23
+	 */
24
+	const level_0_not_in_maintenance = 0;
25
+
26
+	/**
27
+	 * level_1_frontend_only_maintenance means that the site's frontend EE code should be completely disabled
28
+	 * but the admin backend should be running as normal. Maybe an admin can view the frontend though
29
+	 */
30
+	const level_1_frontend_only_maintenance = 1;
31
+
32
+	/**
33
+	 * level_2_complete_maintenance means the frontend AND EE backend code are disabled. The only system running
34
+	 * is the maintenance mode stuff, which will require users to update all addons, and then finish running all
35
+	 * migration scripts before taking the site out of maintenance mode
36
+	 */
37
+	const level_2_complete_maintenance = 2;
38
+
39
+	/**
40
+	 * the name of the option which stores the current level of maintenance mode
41
+	 */
42
+	const option_name_maintenance_mode = 'ee_maintenance_mode';
43
+
44
+
45
+	/**
46
+	 * @var EE_Maintenance_Mode $_instance
47
+	 */
48
+	private static $_instance;
49
+
50
+	/**
51
+	 * @var EE_Registry $EE
52
+	 */
53
+	protected $EE;
54
+
55
+
56
+
57
+	/**
58
+	 * @singleton method used to instantiate class object
59
+	 * @return EE_Maintenance_Mode
60
+	 */
61
+	public static function instance()
62
+	{
63
+		// check if class object is instantiated
64
+		if (! self::$_instance instanceof EE_Maintenance_Mode) {
65
+			self::$_instance = new self();
66
+		}
67
+		return self::$_instance;
68
+	}
69
+
70
+
71
+
72
+	/**
73
+	 * Resets maintenance mode (mostly just re-checks whether or not we should be in maintenance mode)
74
+	 *
75
+	 * @return EE_Maintenance_Mode
76
+	 */
77
+	public static function reset()
78
+	{
79
+		self::instance()->set_maintenance_mode_if_db_old();
80
+		return self::instance();
81
+	}
82
+
83
+
84
+
85
+	/**
86
+	 *private constructor to prevent direct creation
87
+	 */
88
+	private function __construct()
89
+	{
90
+		// if M-Mode level 2 is engaged, we still need basic assets loaded
91
+		add_action('wp_enqueue_scripts', array($this, 'load_assets_required_for_m_mode'));
92
+		// shut 'er down down for maintenance ?
93
+		add_filter('the_content', array($this, 'the_content'), 2);
94
+		// add powered by EE msg
95
+		add_action('shutdown', array($this, 'display_maintenance_mode_notice'), 10);
96
+	}
97
+
98
+
99
+
100
+	/**
101
+	 * retrieves the maintenance mode option value from the db
102
+	 *
103
+	 * @return int
104
+	 */
105
+	public function real_level()
106
+	{
107
+		return (int) get_option(self::option_name_maintenance_mode, EE_Maintenance_Mode::level_0_not_in_maintenance);
108
+	}
109
+
110
+
111
+
112
+	/**
113
+	 * Returns whether or not the models reportedly are able to run queries or not
114
+	 * (ie, if the system thinks their tables are present and up-to-date).
115
+	 *
116
+	 * @return boolean
117
+	 */
118
+	public function models_can_query()
119
+	{
120
+		return $this->real_level() !== EE_Maintenance_Mode::level_2_complete_maintenance;
121
+	}
122
+
123
+
124
+
125
+	/**
126
+	 * Determines whether or not we're in maintenance mode and what level. However, while the site
127
+	 * is in level 1 maintenance, and an admin visits the frontend, this function makes it appear
128
+	 * to them as if teh site isn't in maintenance mode.
129
+	 * EE_Maintenance_Mode::level_0_not_in_maintenance => not in maintenance mode (in normal mode)
130
+	 * EE_Maintenance_Mode::level_1_frontend_only_maintenance=> frontend-only maintenance mode
131
+	 * EE_Maintenance_Mode::level_2_complete_maintenance => frontend and backend maintenance mode
132
+	 *
133
+	 * @return int
134
+	 */
135
+	public function level()
136
+	{
137
+		$maintenance_mode_level = $this->real_level();
138
+		// if this is an admin request, we'll be honest... except if it's ajax, because that might be from the frontend
139
+		if (
140
+			$maintenance_mode_level === EE_Maintenance_Mode::level_1_frontend_only_maintenance// we're in level 1
141
+			&& ((defined('DOING_AJAX') && DOING_AJAX) || ! is_admin()) // on non-ajax frontend requests
142
+			&& current_user_can('administrator') // when the user is an admin
143
+		) {
144
+			$maintenance_mode_level = EE_Maintenance_Mode::level_0_not_in_maintenance;
145
+		}
146
+		return $maintenance_mode_level;
147
+	}
148
+
149
+
150
+
151
+	/**
152
+	 * Determines if we need to put EE in maintenance mode because the database needs updating
153
+	 *
154
+	 * @return boolean true if DB is old and maintenance mode was triggered; false otherwise
155
+	 */
156
+	public function set_maintenance_mode_if_db_old()
157
+	{
158
+		EE_Registry::instance()->load_core('Data_Migration_Manager');
159
+		if (EE_Data_Migration_Manager::instance()->check_for_applicable_data_migration_scripts()) {
160
+			update_option(self::option_name_maintenance_mode, self::level_2_complete_maintenance);
161
+			return true;
162
+		}
163
+		if ($this->level() === self::level_2_complete_maintenance) {
164
+			//we also want to handle the opposite: if the site is mm2, but there aren't any migrations to run
165
+			//then we shouldn't be in mm2. (Maybe an addon got deactivated?)
166
+			update_option(self::option_name_maintenance_mode, self::level_0_not_in_maintenance);
167
+			return false;
168
+		}
169
+		return false;
170
+	}
171
+
172
+
173
+
174
+	/**
175
+	 * Updates the maintenance level on the site
176
+	 *
177
+	 * @param int $level
178
+	 * @return void
179
+	 */
180
+	public function set_maintenance_level($level)
181
+	{
182
+		do_action('AHEE__EE_Maintenance_Mode__set_maintenance_level', $level);
183
+		update_option(self::option_name_maintenance_mode, (int)$level);
184
+	}
185
+
186
+
187
+
188
+	/**
189
+	 * returns TRUE if M-Mode is engaged and the current request is not for the admin
190
+	 *
191
+	 * @return    string
192
+	 */
193
+	public static function disable_frontend_for_maintenance()
194
+	{
195
+		return (! is_admin() && EE_Maintenance_Mode::instance()->level());
196
+	}
197
+
198
+
199
+
200
+	/**
201
+	 * @return void
202
+	 */
203
+	public function load_assets_required_for_m_mode()
204
+	{
205
+		if (
206
+			$this->real_level() === EE_Maintenance_Mode::level_2_complete_maintenance
207
+			&& ! wp_script_is('espresso_core')
208
+		) {
209
+			wp_register_style(
210
+				'espresso_default',
211
+				EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
212
+				array('dashicons'),
213
+				EVENT_ESPRESSO_VERSION
214
+			);
215
+			wp_enqueue_style('espresso_default');
216
+			wp_register_script(
217
+				'espresso_core',
218
+				EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
219
+				array('jquery'),
220
+				EVENT_ESPRESSO_VERSION,
221
+				true
222
+			);
223
+			wp_enqueue_script('espresso_core');
224
+		}
225
+	}
226
+
227
+
228
+
229
+	/**
230
+	 * replacement EE CPT template that displays message notifying site visitors
231
+	 * that EE has been temporarily placed into maintenance mode
232
+	 * does NOT get called on non-EE-CPT requests
233
+	 *
234
+	 * @return    string
235
+	 */
236
+	public static function template_include()
237
+	{
238
+		// shut 'er down down for maintenance ? then don't use any of our templates for our endpoints
239
+		return get_template_directory() . '/index.php';
240
+	}
241
+
242
+
243
+
244
+	/**
245
+	 * displays message notifying site visitors that EE has been temporarily
246
+	 * placed into maintenance mode when post_type != EE CPT
247
+	 *
248
+	 * @param string $the_content
249
+	 * @return string
250
+	 */
251
+	public function the_content($the_content)
252
+	{
253
+		// check if M-mode is engaged and for EE shortcode
254
+		if ($this->level() && strpos($the_content, '[ESPRESSO_') !== false) {
255
+			// this can eventually be moved to a template, or edited via admin. But for now...
256
+			$the_content = sprintf(
257
+				esc_html__(
258
+					'%sMaintenance Mode%sEvent Registration has been temporarily closed while system maintenance is being performed. We\'re sorry for any inconveniences this may have caused. Please try back again later.%s',
259
+					'event_espresso'
260
+				),
261
+				'<h3>',
262
+				'</h3><p>',
263
+				'</p>'
264
+			);
265
+		}
266
+		return $the_content;
267
+	}
268 268
 
269 269
 
270 270
 
271
-    /**
272
-     * displays message on frontend of site notifying admin that EE has been temporarily placed into maintenance mode
273
-     */
274
-    public function display_maintenance_mode_notice()
275
-    {
276
-        // check if M-mode is engaged and for EE shortcode
277
-        if (
278
-            ! (defined('DOING_AJAX') && DOING_AJAX)
279
-            && $this->real_level()
280
-            && ! is_admin()
281
-            && current_user_can('administrator')
282
-            && EE_Registry::instance()->REQ->is_espresso_page()
283
-        ) {
284
-            printf(
285
-                esc_html__(
286
-                    '%sclose%sEvent Registration is currently disabled because Event Espresso has been placed into Maintenance Mode. To change Maintenance Mode settings, click here %sEE Maintenance Mode Admin Page%s',
287
-                    'event_espresso'
288
-                ),
289
-                '<div id="ee-m-mode-admin-notice-dv" class="ee-really-important-notice-dv"><a class="close-espresso-notice" title="',
290
-                '"><span class="dashicons dashicons-no"></span></a><p>',
291
-                ' &raquo; <a href="' . add_query_arg(
292
-                    array('page' => 'espresso_maintenance_settings'), admin_url('admin.php')
293
-                ) . '">',
294
-                '</a></p></div>'
295
-            );
296
-        }
297
-    }
298
-    // espresso-notices important-notice ee-attention
271
+	/**
272
+	 * displays message on frontend of site notifying admin that EE has been temporarily placed into maintenance mode
273
+	 */
274
+	public function display_maintenance_mode_notice()
275
+	{
276
+		// check if M-mode is engaged and for EE shortcode
277
+		if (
278
+			! (defined('DOING_AJAX') && DOING_AJAX)
279
+			&& $this->real_level()
280
+			&& ! is_admin()
281
+			&& current_user_can('administrator')
282
+			&& EE_Registry::instance()->REQ->is_espresso_page()
283
+		) {
284
+			printf(
285
+				esc_html__(
286
+					'%sclose%sEvent Registration is currently disabled because Event Espresso has been placed into Maintenance Mode. To change Maintenance Mode settings, click here %sEE Maintenance Mode Admin Page%s',
287
+					'event_espresso'
288
+				),
289
+				'<div id="ee-m-mode-admin-notice-dv" class="ee-really-important-notice-dv"><a class="close-espresso-notice" title="',
290
+				'"><span class="dashicons dashicons-no"></span></a><p>',
291
+				' &raquo; <a href="' . add_query_arg(
292
+					array('page' => 'espresso_maintenance_settings'), admin_url('admin.php')
293
+				) . '">',
294
+				'</a></p></div>'
295
+			);
296
+		}
297
+	}
298
+	// espresso-notices important-notice ee-attention
299 299
 
300 300
 
301 301
 
302
-    /**
303
-     * override magic methods
304
-     */
305
-    final public function __destruct()
306
-    {
307
-    }
302
+	/**
303
+	 * override magic methods
304
+	 */
305
+	final public function __destruct()
306
+	{
307
+	}
308 308
 
309 309
 
310 310
 
311
-    final public function __call($a, $b)
312
-    {
313
-    }
311
+	final public function __call($a, $b)
312
+	{
313
+	}
314 314
 
315 315
 
316 316
 
317
-    final public function __get($a)
318
-    {
319
-    }
317
+	final public function __get($a)
318
+	{
319
+	}
320 320
 
321 321
 
322 322
 
323
-    final public function __set($a, $b)
324
-    {
325
-    }
323
+	final public function __set($a, $b)
324
+	{
325
+	}
326 326
 
327 327
 
328 328
 
329
-    final public function __isset($a)
330
-    {
331
-    }
329
+	final public function __isset($a)
330
+	{
331
+	}
332 332
 
333 333
 
334 334
 
335
-    final public function __unset($a)
336
-    {
337
-    }
335
+	final public function __unset($a)
336
+	{
337
+	}
338 338
 
339 339
 
340 340
 
341
-    final public function __sleep()
342
-    {
343
-        return array();
344
-    }
341
+	final public function __sleep()
342
+	{
343
+		return array();
344
+	}
345 345
 
346 346
 
347 347
 
348
-    final public function __wakeup()
349
-    {
350
-    }
348
+	final public function __wakeup()
349
+	{
350
+	}
351 351
 
352 352
 
353 353
 
354
-    final public function __invoke()
355
-    {
356
-    }
354
+	final public function __invoke()
355
+	{
356
+	}
357 357
 
358 358
 
359 359
 
360
-    final public static function __set_state($a = null)
361
-    {
362
-        return EE_Maintenance_Mode::instance();
363
-    }
360
+	final public static function __set_state($a = null)
361
+	{
362
+		return EE_Maintenance_Mode::instance();
363
+	}
364 364
 
365 365
 
366 366
 
367
-    final public function __clone()
368
-    {
369
-    }
367
+	final public function __clone()
368
+	{
369
+	}
370 370
 
371 371
 
372 372
 
373
-    final public static function __callStatic($a, $b)
374
-    {
375
-    }
373
+	final public static function __callStatic($a, $b)
374
+	{
375
+	}
376 376
 
377 377
 }
378 378
 // End of file EE_Maintenance_Mode.core.php
Please login to merge, or discard this patch.
modules/add_new_state/EED_Add_New_State.module.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -698,7 +698,7 @@
 block discarded – undo
698 698
 
699 699
     /**
700 700
      * @param EE_State[] $state_options
701
-     * @return array
701
+     * @return EE_State[]
702 702
      * @throws EE_Error
703 703
      * @throws InvalidArgumentException
704 704
      * @throws InvalidDataTypeException
Please login to merge, or discard this patch.
Indentation   +724 added lines, -724 removed lines patch added patch discarded remove patch
@@ -19,730 +19,730 @@
 block discarded – undo
19 19
 
20 20
 
21 21
 
22
-    /**
23
-     * @return EED_Module|EED_Add_New_State
24
-     */
25
-    public static function instance()
26
-    {
27
-        return parent::get_instance(__CLASS__);
28
-    }
29
-
30
-
31
-
32
-    /**
33
-     * set_hooks - for hooking into EE Core, other modules, etc
34
-     *
35
-     * @return void
36
-     */
37
-    public static function set_hooks()
38
-    {
39
-        add_action('wp_loaded', array('EED_Add_New_State', 'set_definitions'), 2);
40
-        add_action('wp_enqueue_scripts', array('EED_Add_New_State', 'translate_js_strings'), 0);
41
-        add_action('wp_enqueue_scripts', array('EED_Add_New_State', 'wp_enqueue_scripts'), 10);
42
-        add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
43
-            array('EED_Add_New_State', 'display_add_new_state_micro_form'), 1, 1);
44
-        add_filter('FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
45
-            array('EED_Add_New_State', 'display_add_new_state_micro_form'), 1, 1);
46
-        add_filter('FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
47
-            array('EED_Add_New_State', 'unset_new_state_request_params'), 10, 1);
48
-        add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
49
-            array('EED_Add_New_State', 'inject_new_reg_state_into_options'), 10, 5);
50
-        add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
51
-            array('EED_Add_New_State', 'inject_new_reg_country_into_options'), 10, 5);
52
-        add_filter('FHEE__EE_State_Select_Input____construct__state_options',
53
-            array('EED_Add_New_State', 'state_options'), 10, 1);
54
-        add_filter('FHEE__EE_Country_Select_Input____construct__country_options',
55
-            array('EED_Add_New_State', 'country_options'), 10, 1);
56
-    }
57
-
58
-
59
-
60
-    /**
61
-     * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
62
-     *
63
-     * @return void
64
-     */
65
-    public static function set_hooks_admin()
66
-    {
67
-        add_action('wp_loaded', array('EED_Add_New_State', 'set_definitions'), 2);
68
-        add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
69
-            array('EED_Add_New_State', 'display_add_new_state_micro_form'), 1, 1);
70
-        add_filter('FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
71
-            array('EED_Add_New_State', 'display_add_new_state_micro_form'), 1, 1);
72
-        add_action('wp_ajax_espresso_add_new_state', array('EED_Add_New_State', 'add_new_state'));
73
-        add_action('wp_ajax_nopriv_espresso_add_new_state', array('EED_Add_New_State', 'add_new_state'));
74
-        add_filter('FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
75
-            array('EED_Add_New_State', 'unset_new_state_request_params'), 10, 1);
76
-        add_action('AHEE__General_Settings_Admin_Page__update_country_settings__state_saved',
77
-            array('EED_Add_New_State', 'update_country_settings'), 10, 3);
78
-        add_action('AHEE__General_Settings_Admin_Page__delete_state__state_deleted',
79
-            array('EED_Add_New_State', 'update_country_settings'), 10, 3);
80
-        add_filter('FHEE__EE_State_Select_Input____construct__state_options',
81
-            array('EED_Add_New_State', 'state_options'), 10, 1);
82
-        add_filter('FHEE__EE_Country_Select_Input____construct__country_options',
83
-            array('EED_Add_New_State', 'country_options'), 10, 1);
84
-        add_filter('FHEE__EE_Form_Section_Proper__receive_form_submission__request_data',
85
-            array('EED_Add_New_State', 'filter_checkout_request_params'), 10, 1);
86
-        add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
87
-            array('EED_Add_New_State', 'inject_new_reg_state_into_options'), 10, 5);
88
-        add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
89
-            array('EED_Add_New_State', 'inject_new_reg_country_into_options'), 10, 5);
90
-    }
91
-
92
-
93
-
94
-    /**
95
-     * @return void
96
-     */
97
-    public static function set_definitions()
98
-    {
99
-        define('ANS_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets' . DS);
100
-        define('ANS_TEMPLATES_PATH', str_replace(
101
-                                         '\\',
102
-                                         DS,
103
-                                         plugin_dir_path(__FILE__)) . 'templates' . DS
104
-        );
105
-    }
106
-
107
-
108
-
109
-    /**
110
-     * @param WP $WP
111
-     * @return void
112
-     */
113
-    public function run($WP)
114
-    {
115
-    }
116
-
117
-
118
-
119
-    /**
120
-     * @return void
121
-     */
122
-    public static function translate_js_strings()
123
-    {
124
-        EE_Registry::$i18n_js_strings['ans_no_country']        = esc_html__(
125
-            'In order to proceed, you need to select the Country that your State/Province belongs to.',
126
-            'event_espresso'
127
-        );
128
-        EE_Registry::$i18n_js_strings['ans_no_name']           = esc_html__(
129
-            'In order to proceed, you need to enter the name of your State/Province.',
130
-            'event_espresso'
131
-        );
132
-        EE_Registry::$i18n_js_strings['ans_no_abbreviation']   = esc_html__(
133
-            'In order to proceed, you need to enter an abbreviation for the name of your State/Province.',
134
-            'event_espresso'
135
-        );
136
-        EE_Registry::$i18n_js_strings['ans_save_success']      = esc_html__(
137
-            'The new state was successfully saved to the database.',
138
-            'event_espresso'
139
-        );
140
-        EE_Registry::$i18n_js_strings['ans_server_save_error'] = esc_html__(
141
-            'An unknown error has occurred on the server while saving the new state to the database.',
142
-            'event_espresso'
143
-        );
144
-    }
145
-
146
-
147
-
148
-    /**
149
-     * @return void
150
-     */
151
-    public static function wp_enqueue_scripts()
152
-    {
153
-        if (apply_filters('EED_Single_Page_Checkout__SPCO_active', false)) {
154
-            wp_register_script('add_new_state', ANS_ASSETS_URL . 'add_new_state.js',
155
-                array('espresso_core', 'single_page_checkout'), EVENT_ESPRESSO_VERSION, true);
156
-            wp_enqueue_script('add_new_state');
157
-        }
158
-    }
159
-
160
-
161
-
162
-    /**
163
-     * display_add_new_state_micro_form
164
-     *
165
-     * @param EE_Form_Section_Proper $question_group_reg_form
166
-     * @return string
167
-     * @throws EE_Error
168
-     * @throws InvalidArgumentException
169
-     * @throws InvalidDataTypeException
170
-     * @throws InvalidInterfaceException
171
-     */
172
-    //	public static function display_add_new_state_micro_form( $html, EE_Form_Input_With_Options_Base $input ){
173
-    public static function display_add_new_state_micro_form(EE_Form_Section_Proper $question_group_reg_form)
174
-    {
175
-        // only add the 'new_state_micro_form' when displaying reg forms,
176
-        // not during processing since we process the 'new_state_micro_form' in it's own AJAX request
177
-        $action = EE_Registry::instance()->REQ->get('action', '');
178
-        // is the "state" question in this form section?
179
-        $input = $question_group_reg_form->get_subsection('state');
180
-        if ($action === 'process_reg_step' || $action === 'update_reg_step') {
181
-            //ok then all we need to do is make sure the input's HTML name is consistent
182
-            //by forcing it to set it now, like it did while getting the form for display
183
-            if ($input instanceof EE_State_Select_Input) {
184
-                $input->html_name();
185
-            }
186
-            return $question_group_reg_form;
187
-        }
188
-        // we're only doing this for state select inputs
189
-        if ($input instanceof EE_State_Select_Input) {
190
-            // grab any set values from the request
191
-            $country_name        = str_replace('state', 'nsmf_new_state_country', $input->html_name());
192
-            $state_name          = str_replace('state', 'nsmf_new_state_name', $input->html_name());
193
-            $abbrv_name          = str_replace('state', 'nsmf_new_state_abbrv', $input->html_name());
194
-            $new_state_submit_id = str_replace('state', 'new_state', $input->html_id());
195
-            $country_options     = array();
196
-            $countries           = EEM_Country::instance()->get_all_countries();
197
-            if (! empty($countries)) {
198
-                foreach ($countries as $country) {
199
-                    if ($country instanceof EE_Country) {
200
-                        $country_options[$country->ID()] = $country->name();
201
-                    }
202
-                }
203
-            }
204
-            $new_state_micro_form = new EE_Form_Section_Proper(
205
-                array(
206
-                    'name'            => 'new_state_micro_form',
207
-                    'html_id'         => 'new_state_micro_form',
208
-                    'layout_strategy' => new EE_Div_Per_Section_Layout(),
209
-                    'subsections'     => array(
210
-                        // add hidden input to indicate that a new state is being added
211
-                        'add_new_state'               => new EE_Hidden_Input(
212
-                            array(
213
-                                'html_name' => str_replace(
214
-                                    'state',
215
-                                    'nsmf_add_new_state',
216
-                                    $input->html_name()
217
-                                ),
218
-                                'html_id'   => str_replace(
219
-                                    'state',
220
-                                    'nsmf_add_new_state',
221
-                                    $input->html_id()
222
-                                ),
223
-                                'default'   => 0,
224
-                            )
225
-                        ),
226
-                        // add link for displaying hidden container
227
-                        'click_here_link'             => new EE_Form_Section_HTML(
228
-                            apply_filters(
229
-                                'FHEE__EED_Add_New_State__display_add_new_state_micro_form__click_here_link',
230
-                                EEH_HTML::link(
231
-                                    '',
232
-                                    esc_html__('click here to add a new state/province', 'event_espresso'),
233
-                                    '',
234
-                                    'display-' . $input->html_id(),
235
-                                    'ee-form-add-new-state-lnk display-the-hidden smaller-text hide-if-no-js',
236
-                                    '',
237
-                                    'data-target="' . $input->html_id() . '"'
238
-                                )
239
-                            )
240
-                        ),
241
-                        // add initial html for hidden container
242
-                        'add_new_state_micro_form'    => new EE_Form_Section_HTML(
243
-                            apply_filters(
244
-                                'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_micro_form',
245
-                                EEH_HTML::div('', $input->html_id() . '-dv', 'ee-form-add-new-state-dv',
246
-                                    'display: none;') .
247
-                                EEH_HTML::h6(
248
-                                    esc_html__(
249
-                                        'Is your state/province missing from the dropdown menu above? You can add it by completing the following steps:',
250
-                                        'event_espresso'
251
-                                    )
252
-                                ) .
253
-                                EEH_HTML::ul() .
254
-                                EEH_HTML::li(
255
-                                    esc_html__(
256
-                                        'first select the Country that your State/Province belongs to',
257
-                                        'event_espresso'
258
-                                    )
259
-                                ) .
260
-                                EEH_HTML::li(
261
-                                    esc_html__('enter the name of your State/Province', 'event_espresso')
262
-                                ) .
263
-                                EEH_HTML::li(
264
-                                    esc_html__(
265
-                                        'enter a two to six letter abbreviation for the name of your State/Province',
266
-                                        'event_espresso'
267
-                                    )
268
-                                ) .
269
-                                EEH_HTML::li(esc_html__('click the ADD button', 'event_espresso')) .
270
-                                EEH_HTML::ulx()
271
-                            )
272
-                        ),
273
-                        // NEW STATE COUNTRY
274
-                        'new_state_country'           => new EE_Country_Select_Input(
275
-                            $country_options,
276
-                            array(
277
-                                'html_name'       => $country_name,
278
-                                'html_id'         => str_replace(
279
-                                    'state',
280
-                                    'nsmf_new_state_country', $input->html_id()
281
-                                ),
282
-                                'html_class'      => $input->html_class() . ' new-state-country',
283
-                                'html_label_text' => esc_html__('New State/Province Country', 'event_espresso'),
284
-                                'default'         => EE_Registry::instance()->REQ->get($country_name, ''),
285
-                                'required'        => false,
286
-                            )
287
-                        ),
288
-                        // NEW STATE NAME
289
-                        'new_state_name'              => new EE_Text_Input(
290
-                            array(
291
-                                'html_name'       => $state_name,
292
-                                'html_id'         => str_replace(
293
-                                    'state',
294
-                                    'nsmf_new_state_name', $input->html_id()
295
-                                ),
296
-                                'html_class'      => $input->html_class() . ' new-state-state',
297
-                                'html_label_text' => esc_html__('New State/Province Name',
298
-                                    'event_espresso'),
299
-                                'default'         => EE_Registry::instance()->REQ->get($state_name, ''),
300
-                                'required'        => false,
301
-                            )
302
-                        ),
303
-                        'spacer'                      => new EE_Form_Section_HTML(EEH_HTML::br()),
304
-                        // NEW STATE NAME
305
-                        'new_state_abbrv'             => new EE_Text_Input(
306
-                            array(
307
-                                'html_name'             => $abbrv_name,
308
-                                'html_id'               => str_replace('state', 'nsmf_new_state_abbrv',
309
-                                    $input->html_id()),
310
-                                'html_class'            => $input->html_class() . ' new-state-abbrv',
311
-                                'html_label_text'       => esc_html__(
312
-                                                               'New State/Province Abbreviation',
313
-                                                               'event_espresso'
314
-                                                           ) . ' *',
315
-                                'html_other_attributes' => 'size="24"',
316
-                                'default'               => EE_Registry::instance()->REQ->get($abbrv_name, ''),
317
-                                'required'              => false,
318
-                            )
319
-                        ),
320
-                        // "submit" button
321
-                        'add_new_state_submit_button' => new EE_Form_Section_HTML(
322
-                            apply_filters(
323
-                                'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_submit_button',
324
-                                EEH_HTML::nbsp(3) .
325
-                                EEH_HTML::link(
326
-                                    '',
327
-                                    esc_html__('ADD', 'event_espresso'),
328
-                                    '',
329
-                                    'submit-' . $new_state_submit_id,
330
-                                    'ee-form-add-new-state-submit button button-secondary',
331
-                                    '',
332
-                                    'data-target="' . $new_state_submit_id . '"'
333
-                                )
334
-                            )
335
-                        ),
336
-                        // extra info
337
-                        'add_new_state_extra'         => new EE_Form_Section_HTML(
338
-                            apply_filters(
339
-                                'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_extra',
340
-                                EEH_HTML::br(2)
341
-                                .
342
-                                EEH_HTML::div('', '', 'small-text')
343
-                                .
344
-                                EEH_HTML::strong(
345
-                                    '* ' .
346
-                                    esc_html__(
347
-                                        'Don\'t know your State/Province Abbreviation?',
348
-                                        'event_espresso'
349
-                                    )
350
-                                )
351
-                                .
352
-                                EEH_HTML::br()
353
-                                .
354
-                                sprintf(
355
-                                    esc_html__(
356
-                                        'You can look here: %s, for a list of Countries and links to their State/Province Abbreviations ("Subdivisions assigned codes" column).',
357
-                                        'event_espresso'
358
-                                    ),
359
-                                    EEH_HTML::link(
360
-                                        'http://en.wikipedia.org/wiki/ISO_3166-2',
361
-                                        'http://en.wikipedia.org/wiki/ISO_3166-2',
362
-                                        '',
363
-                                        '',
364
-                                        'ee-form-add-new-state-wiki-lnk',
365
-                                        '',
366
-                                        'target="_blank"'
367
-                                    )
368
-                                )
369
-                                .
370
-                                EEH_HTML::divx()
371
-                                .
372
-                                EEH_HTML::br()
373
-                                .
374
-                                EEH_HTML::link(
375
-                                    '',
376
-                                    esc_html__('cancel new State/Province', 'event_espresso'),
377
-                                    '',
378
-                                    'hide-' . $input->html_id(),
379
-                                    'ee-form-cancel-new-state-lnk smaller-text',
380
-                                    '',
381
-                                    'data-target="' . $input->html_id() . '"'
382
-                                )
383
-                                .
384
-                                EEH_HTML::divx()
385
-                                .
386
-                                EEH_HTML::br()
387
-                            )
388
-                        ),
389
-                    ),
390
-                )
391
-            );
392
-            $question_group_reg_form->add_subsections(
393
-                array('new_state_micro_form' => $new_state_micro_form),
394
-                'state',
395
-                false
396
-            );
397
-        }
398
-        return $question_group_reg_form;
399
-    }
400
-
401
-
402
-
403
-    /**
404
-     * set_new_state_input_width
405
-     *
406
-     * @return int|string
407
-     * @throws EE_Error
408
-     * @throws InvalidArgumentException
409
-     * @throws InvalidDataTypeException
410
-     * @throws InvalidInterfaceException
411
-     * @throws ReflectionException
412
-     */
413
-    public static function add_new_state()
414
-    {
415
-        $REQ = EE_Registry::instance()->load_core('Request_Handler');
416
-        if (absint($REQ->get('nsmf_add_new_state')) === 1) {
417
-            EE_Registry::instance()->load_model('State');
418
-            // grab country ISO code, new state name, and new state abbreviation
419
-            $state_country = $REQ->is_set('nsmf_new_state_country')
420
-                ? sanitize_text_field($REQ->get('nsmf_new_state_country'))
421
-                : false;
422
-            $state_name    = $REQ->is_set('nsmf_new_state_name')
423
-                ? sanitize_text_field($REQ->get('nsmf_new_state_name'))
424
-                : false;
425
-            $state_abbr    = $REQ->is_set('nsmf_new_state_abbrv')
426
-                ? sanitize_text_field($REQ->get('nsmf_new_state_abbrv'))
427
-                : false;
428
-            if ($state_country && $state_name && $state_abbr) {
429
-                $new_state = EED_Add_New_State::save_new_state_to_db(array(
430
-                    'CNT_ISO'    => strtoupper($state_country),
431
-                    'STA_abbrev' => strtoupper($state_abbr),
432
-                    'STA_name'   => ucwords($state_name),
433
-                    'STA_active' => false,
434
-                ));
435
-                if ($new_state instanceof EE_State) {
436
-                    // clean house
437
-                    EE_Registry::instance()->REQ->un_set('nsmf_add_new_state');
438
-                    EE_Registry::instance()->REQ->un_set('nsmf_new_state_country');
439
-                    EE_Registry::instance()->REQ->un_set('nsmf_new_state_name');
440
-                    EE_Registry::instance()->REQ->un_set('nsmf_new_state_abbrv');
441
-                    // get any existing new states
442
-                    $new_states                   = EE_Registry::instance()->SSN->get_session_data(
443
-                        'nsmf_new_states'
444
-                    );
445
-                    $new_states[$new_state->ID()] = $new_state;
446
-                    EE_Registry::instance()->SSN->set_session_data(
447
-                        array('nsmf_new_states' => $new_states)
448
-                    );
449
-                    if (EE_Registry::instance()->REQ->ajax) {
450
-                        echo wp_json_encode(array(
451
-                            'success'      => true,
452
-                            'id'           => $new_state->ID(),
453
-                            'name'         => $new_state->name(),
454
-                            'abbrev'       => $new_state->abbrev(),
455
-                            'country_iso'  => $new_state->country_iso(),
456
-                            'country_name' => $new_state->country()->name(),
457
-                        ));
458
-                        exit();
459
-                    }
460
-                    return $new_state->ID();
461
-                }
462
-            } else {
463
-                $error = esc_html__(
464
-                    'A new State/Province could not be added because invalid or missing data was received.',
465
-                    'event_espresso'
466
-                );
467
-                if (EE_Registry::instance()->REQ->ajax) {
468
-                    echo wp_json_encode(array('error' => $error));
469
-                    exit();
470
-                }
471
-                EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
472
-            }
473
-        }
474
-        return false;
475
-    }
476
-
477
-
478
-
479
-    /**
480
-     * recursively drills down through request params to remove any that were added by this module
481
-     *
482
-     * @param array $request_params
483
-     * @return array
484
-     */
485
-    public static function filter_checkout_request_params($request_params)
486
-    {
487
-        foreach ($request_params as $form_section) {
488
-            if (is_array($form_section)) {
489
-                EED_Add_New_State::unset_new_state_request_params($form_section);
490
-                EED_Add_New_State::filter_checkout_request_params($form_section);
491
-            }
492
-        }
493
-        return $request_params;
494
-    }
495
-
496
-
497
-
498
-    /**
499
-     * @param array $request_params
500
-     * @return array
501
-     */
502
-    public static function unset_new_state_request_params($request_params)
503
-    {
504
-        unset(
505
-            $request_params['new_state_micro_form'],
506
-            $request_params['new_state_micro_add_new_state'],
507
-            $request_params['new_state_micro_new_state_country'],
508
-            $request_params['new_state_micro_new_state_name'],
509
-            $request_params['new_state_micro_new_state_abbrv']
510
-        );
511
-        return $request_params;
512
-    }
513
-
514
-
515
-
516
-    /**
517
-     * @param array $props_n_values
518
-     * @return bool
519
-     * @throws EE_Error
520
-     * @throws InvalidArgumentException
521
-     * @throws InvalidDataTypeException
522
-     * @throws InvalidInterfaceException
523
-     */
524
-    public static function save_new_state_to_db($props_n_values = array())
525
-    {
526
-        $existing_state = EEM_State::instance()->get_all(array($props_n_values, 'limit' => 1));
527
-        if (! empty($existing_state)) {
528
-            return array_pop($existing_state);
529
-        }
530
-        $new_state = EE_State::new_instance($props_n_values);
531
-        if ($new_state instanceof EE_State) {
532
-            // if not non-ajax admin
533
-            $new_state_key    = 'new-state-added-' . $new_state->country_iso() . '-' . $new_state->abbrev();
534
-            $new_state_notice = sprintf(
535
-                esc_html__(
536
-                    'A new State named "%1$s (%2$s)" was dynamically added from an Event Espresso form for the Country of "%3$s".%5$sTo verify, edit, and/or delete this new State, please go to the %4$s and update the States / Provinces section.%5$sCheck "Yes" to have this new State added to dropdown select lists in forms.',
537
-                    'event_espresso'
538
-                ),
539
-                '<b>' . $new_state->name() . '</b>',
540
-                '<b>' . $new_state->abbrev() . '</b>',
541
-                '<b>' . $new_state->country()->name() . '</b>',
542
-                '<a href="' . add_query_arg(array(
543
-                    'page'    => 'espresso_general_settings',
544
-                    'action'  => 'country_settings',
545
-                    'country' => $new_state->country_iso(),
546
-                ), admin_url('admin.php')) . '">' . esc_html__('Event Espresso - General Settings > Countries Tab',
547
-                    'event_espresso') . '</a>',
548
-                '<br />'
549
-            );
550
-            EE_Error::add_persistent_admin_notice($new_state_key, $new_state_notice);
551
-            $new_state->save();
552
-            EEM_State::instance()->reset_cached_states();
553
-            return $new_state;
554
-        }
555
-        return false;
556
-    }
557
-
558
-
559
-
560
-    /**
561
-     * @param string $CNT_ISO
562
-     * @param string $STA_ID
563
-     * @param array  $cols_n_values
564
-     * @return void
565
-     * @throws EE_Error
566
-     * @throws InvalidArgumentException
567
-     * @throws InvalidDataTypeException
568
-     * @throws InvalidInterfaceException
569
-     */
570
-    public static function update_country_settings($CNT_ISO = '', $STA_ID = '', $cols_n_values = array())
571
-    {
572
-        if (! $CNT_ISO) {
573
-            EE_Error::add_error(
574
-                esc_html__('An invalid or missing Country ISO Code was received.', 'event_espresso'),
575
-                __FILE__,
576
-                __FUNCTION__,
577
-                __LINE__
578
-            );
579
-        }
580
-        $STA_abbrev = is_array($cols_n_values) && isset($cols_n_values['STA_abbrev']) ? $cols_n_values['STA_abbrev']
581
-            : false;
582
-        if (! $STA_abbrev && ! empty($STA_ID)) {
583
-            $state = EEM_State::instance()->get_one_by_ID($STA_ID);
584
-            if ($state instanceof EE_State) {
585
-                $STA_abbrev = $state->abbrev();
586
-            }
587
-        }
588
-        if (! $STA_abbrev) {
589
-            EE_Error::add_error(
590
-                esc_html__('An invalid or missing State Abbreviation was received.', 'event_espresso'),
591
-                __FILE__,
592
-                __FUNCTION__,
593
-                __LINE__
594
-            );
595
-        }
596
-        EE_Error::dismiss_persistent_admin_notice($CNT_ISO . '-' . $STA_abbrev, true, true);
597
-    }
598
-
599
-
600
-
601
-    /**
602
-     * @param EE_State[]                            $state_options
603
-     * @param EE_SPCO_Reg_Step_Attendee_Information $reg_step
604
-     * @param EE_Registration                       $registration
605
-     * @param EE_Question                           $question
606
-     * @param                                       $answer
607
-     * @return array
608
-     * @throws EE_Error
609
-     * @throws InvalidArgumentException
610
-     * @throws InvalidDataTypeException
611
-     * @throws InvalidInterfaceException
612
-     */
613
-    public static function inject_new_reg_state_into_options(
614
-        $state_options = array(),
615
-        EE_SPCO_Reg_Step_Attendee_Information $reg_step,
616
-        EE_Registration $registration,
617
-        EE_Question $question,
618
-        $answer
619
-    ) {
620
-        if ($answer instanceof EE_Answer && $question instanceof EE_Question
621
-            && $question->type() === EEM_Question::QST_type_state
622
-        ) {
623
-            $STA_ID = $answer->value();
624
-            if (! empty($STA_ID)) {
625
-                $state = EEM_State::instance()->get_one_by_ID($STA_ID);
626
-                if ($state instanceof EE_State) {
627
-                    $country = $state->country();
628
-                    if ($country instanceof EE_Country) {
629
-                        if (! isset($state_options[$country->name()])) {
630
-                            $state_options[$country->name()] = array();
631
-                        }
632
-                        if (! isset($state_options[$country->name()][$STA_ID])) {
633
-                            $state_options[$country->name()][$STA_ID] = $state->name();
634
-                        }
635
-                    }
636
-                }
637
-            }
638
-        }
639
-        return $state_options;
640
-    }
641
-
642
-
643
-
644
-    /**
645
-     * @param EE_Country[]                          $country_options
646
-     * @param EE_SPCO_Reg_Step_Attendee_Information $reg_step
647
-     * @param EE_Registration                       $registration
648
-     * @param EE_Question                           $question
649
-     * @param                                       $answer
650
-     * @return array
651
-     * @throws EE_Error
652
-     * @throws InvalidArgumentException
653
-     * @throws InvalidDataTypeException
654
-     * @throws InvalidInterfaceException
655
-     */
656
-    public static function inject_new_reg_country_into_options(
657
-        $country_options = array(),
658
-        EE_SPCO_Reg_Step_Attendee_Information $reg_step,
659
-        EE_Registration $registration,
660
-        EE_Question $question,
661
-        $answer
662
-    ) {
663
-        if ($answer instanceof EE_Answer && $question instanceof EE_Question
664
-            && $question->type()
665
-               === EEM_Question::QST_type_country
666
-        ) {
667
-            $CNT_ISO = $answer->value();
668
-            if (! empty($CNT_ISO)) {
669
-                $country = EEM_Country::instance()->get_one_by_ID($CNT_ISO);
670
-                if ($country instanceof EE_Country) {
671
-                    if (! isset($country_options[$CNT_ISO])) {
672
-                        $country_options[$CNT_ISO] = $country->name();
673
-                    }
674
-                }
675
-            }
676
-        }
677
-        return $country_options;
678
-    }
679
-
680
-
681
-
682
-    /**
683
-     * @param EE_State[] $state_options
684
-     * @return array
685
-     * @throws EE_Error
686
-     * @throws InvalidArgumentException
687
-     * @throws InvalidDataTypeException
688
-     * @throws InvalidInterfaceException
689
-     */
690
-    public static function state_options($state_options = array())
691
-    {
692
-        $new_states = EED_Add_New_State::_get_new_states();
693
-        foreach ($new_states as $new_state) {
694
-            if (
695
-                $new_state instanceof EE_State
696
-                && $new_state->country() instanceof EE_Country
697
-            ) {
698
-                $state_options[$new_state->country()->name()][$new_state->ID()] = $new_state->name();
699
-            }
700
-        }
701
-        return $state_options;
702
-    }
703
-
704
-
705
-
706
-    /**
707
-     * @return array
708
-     * @throws InvalidArgumentException
709
-     * @throws InvalidDataTypeException
710
-     * @throws InvalidInterfaceException
711
-     */
712
-    protected static function _get_new_states()
713
-    {
714
-        $new_states = array();
715
-        if (EE_Registry::instance()->SSN instanceof EE_Session) {
716
-            $new_states = EE_Registry::instance()->SSN->get_session_data(
717
-                'nsmf_new_states'
718
-            );
719
-        }
720
-        return is_array($new_states) ? $new_states : array();
721
-    }
722
-
723
-
724
-
725
-    /**
726
-     * @param EE_Country[] $country_options
727
-     * @return array
728
-     * @throws EE_Error
729
-     * @throws InvalidArgumentException
730
-     * @throws InvalidDataTypeException
731
-     * @throws InvalidInterfaceException
732
-     */
733
-    public static function country_options($country_options = array())
734
-    {
735
-        $new_states = EED_Add_New_State::_get_new_states();
736
-        foreach ($new_states as $new_state) {
737
-            if (
738
-                $new_state instanceof EE_State
739
-                && $new_state->country() instanceof EE_Country
740
-            ) {
741
-                $country_options[$new_state->country()->ID()] = $new_state->country()->name();
742
-            }
743
-        }
744
-        return $country_options;
745
-    }
22
+	/**
23
+	 * @return EED_Module|EED_Add_New_State
24
+	 */
25
+	public static function instance()
26
+	{
27
+		return parent::get_instance(__CLASS__);
28
+	}
29
+
30
+
31
+
32
+	/**
33
+	 * set_hooks - for hooking into EE Core, other modules, etc
34
+	 *
35
+	 * @return void
36
+	 */
37
+	public static function set_hooks()
38
+	{
39
+		add_action('wp_loaded', array('EED_Add_New_State', 'set_definitions'), 2);
40
+		add_action('wp_enqueue_scripts', array('EED_Add_New_State', 'translate_js_strings'), 0);
41
+		add_action('wp_enqueue_scripts', array('EED_Add_New_State', 'wp_enqueue_scripts'), 10);
42
+		add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
43
+			array('EED_Add_New_State', 'display_add_new_state_micro_form'), 1, 1);
44
+		add_filter('FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
45
+			array('EED_Add_New_State', 'display_add_new_state_micro_form'), 1, 1);
46
+		add_filter('FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
47
+			array('EED_Add_New_State', 'unset_new_state_request_params'), 10, 1);
48
+		add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
49
+			array('EED_Add_New_State', 'inject_new_reg_state_into_options'), 10, 5);
50
+		add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
51
+			array('EED_Add_New_State', 'inject_new_reg_country_into_options'), 10, 5);
52
+		add_filter('FHEE__EE_State_Select_Input____construct__state_options',
53
+			array('EED_Add_New_State', 'state_options'), 10, 1);
54
+		add_filter('FHEE__EE_Country_Select_Input____construct__country_options',
55
+			array('EED_Add_New_State', 'country_options'), 10, 1);
56
+	}
57
+
58
+
59
+
60
+	/**
61
+	 * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
62
+	 *
63
+	 * @return void
64
+	 */
65
+	public static function set_hooks_admin()
66
+	{
67
+		add_action('wp_loaded', array('EED_Add_New_State', 'set_definitions'), 2);
68
+		add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
69
+			array('EED_Add_New_State', 'display_add_new_state_micro_form'), 1, 1);
70
+		add_filter('FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
71
+			array('EED_Add_New_State', 'display_add_new_state_micro_form'), 1, 1);
72
+		add_action('wp_ajax_espresso_add_new_state', array('EED_Add_New_State', 'add_new_state'));
73
+		add_action('wp_ajax_nopriv_espresso_add_new_state', array('EED_Add_New_State', 'add_new_state'));
74
+		add_filter('FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
75
+			array('EED_Add_New_State', 'unset_new_state_request_params'), 10, 1);
76
+		add_action('AHEE__General_Settings_Admin_Page__update_country_settings__state_saved',
77
+			array('EED_Add_New_State', 'update_country_settings'), 10, 3);
78
+		add_action('AHEE__General_Settings_Admin_Page__delete_state__state_deleted',
79
+			array('EED_Add_New_State', 'update_country_settings'), 10, 3);
80
+		add_filter('FHEE__EE_State_Select_Input____construct__state_options',
81
+			array('EED_Add_New_State', 'state_options'), 10, 1);
82
+		add_filter('FHEE__EE_Country_Select_Input____construct__country_options',
83
+			array('EED_Add_New_State', 'country_options'), 10, 1);
84
+		add_filter('FHEE__EE_Form_Section_Proper__receive_form_submission__request_data',
85
+			array('EED_Add_New_State', 'filter_checkout_request_params'), 10, 1);
86
+		add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
87
+			array('EED_Add_New_State', 'inject_new_reg_state_into_options'), 10, 5);
88
+		add_filter('FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
89
+			array('EED_Add_New_State', 'inject_new_reg_country_into_options'), 10, 5);
90
+	}
91
+
92
+
93
+
94
+	/**
95
+	 * @return void
96
+	 */
97
+	public static function set_definitions()
98
+	{
99
+		define('ANS_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets' . DS);
100
+		define('ANS_TEMPLATES_PATH', str_replace(
101
+										 '\\',
102
+										 DS,
103
+										 plugin_dir_path(__FILE__)) . 'templates' . DS
104
+		);
105
+	}
106
+
107
+
108
+
109
+	/**
110
+	 * @param WP $WP
111
+	 * @return void
112
+	 */
113
+	public function run($WP)
114
+	{
115
+	}
116
+
117
+
118
+
119
+	/**
120
+	 * @return void
121
+	 */
122
+	public static function translate_js_strings()
123
+	{
124
+		EE_Registry::$i18n_js_strings['ans_no_country']        = esc_html__(
125
+			'In order to proceed, you need to select the Country that your State/Province belongs to.',
126
+			'event_espresso'
127
+		);
128
+		EE_Registry::$i18n_js_strings['ans_no_name']           = esc_html__(
129
+			'In order to proceed, you need to enter the name of your State/Province.',
130
+			'event_espresso'
131
+		);
132
+		EE_Registry::$i18n_js_strings['ans_no_abbreviation']   = esc_html__(
133
+			'In order to proceed, you need to enter an abbreviation for the name of your State/Province.',
134
+			'event_espresso'
135
+		);
136
+		EE_Registry::$i18n_js_strings['ans_save_success']      = esc_html__(
137
+			'The new state was successfully saved to the database.',
138
+			'event_espresso'
139
+		);
140
+		EE_Registry::$i18n_js_strings['ans_server_save_error'] = esc_html__(
141
+			'An unknown error has occurred on the server while saving the new state to the database.',
142
+			'event_espresso'
143
+		);
144
+	}
145
+
146
+
147
+
148
+	/**
149
+	 * @return void
150
+	 */
151
+	public static function wp_enqueue_scripts()
152
+	{
153
+		if (apply_filters('EED_Single_Page_Checkout__SPCO_active', false)) {
154
+			wp_register_script('add_new_state', ANS_ASSETS_URL . 'add_new_state.js',
155
+				array('espresso_core', 'single_page_checkout'), EVENT_ESPRESSO_VERSION, true);
156
+			wp_enqueue_script('add_new_state');
157
+		}
158
+	}
159
+
160
+
161
+
162
+	/**
163
+	 * display_add_new_state_micro_form
164
+	 *
165
+	 * @param EE_Form_Section_Proper $question_group_reg_form
166
+	 * @return string
167
+	 * @throws EE_Error
168
+	 * @throws InvalidArgumentException
169
+	 * @throws InvalidDataTypeException
170
+	 * @throws InvalidInterfaceException
171
+	 */
172
+	//	public static function display_add_new_state_micro_form( $html, EE_Form_Input_With_Options_Base $input ){
173
+	public static function display_add_new_state_micro_form(EE_Form_Section_Proper $question_group_reg_form)
174
+	{
175
+		// only add the 'new_state_micro_form' when displaying reg forms,
176
+		// not during processing since we process the 'new_state_micro_form' in it's own AJAX request
177
+		$action = EE_Registry::instance()->REQ->get('action', '');
178
+		// is the "state" question in this form section?
179
+		$input = $question_group_reg_form->get_subsection('state');
180
+		if ($action === 'process_reg_step' || $action === 'update_reg_step') {
181
+			//ok then all we need to do is make sure the input's HTML name is consistent
182
+			//by forcing it to set it now, like it did while getting the form for display
183
+			if ($input instanceof EE_State_Select_Input) {
184
+				$input->html_name();
185
+			}
186
+			return $question_group_reg_form;
187
+		}
188
+		// we're only doing this for state select inputs
189
+		if ($input instanceof EE_State_Select_Input) {
190
+			// grab any set values from the request
191
+			$country_name        = str_replace('state', 'nsmf_new_state_country', $input->html_name());
192
+			$state_name          = str_replace('state', 'nsmf_new_state_name', $input->html_name());
193
+			$abbrv_name          = str_replace('state', 'nsmf_new_state_abbrv', $input->html_name());
194
+			$new_state_submit_id = str_replace('state', 'new_state', $input->html_id());
195
+			$country_options     = array();
196
+			$countries           = EEM_Country::instance()->get_all_countries();
197
+			if (! empty($countries)) {
198
+				foreach ($countries as $country) {
199
+					if ($country instanceof EE_Country) {
200
+						$country_options[$country->ID()] = $country->name();
201
+					}
202
+				}
203
+			}
204
+			$new_state_micro_form = new EE_Form_Section_Proper(
205
+				array(
206
+					'name'            => 'new_state_micro_form',
207
+					'html_id'         => 'new_state_micro_form',
208
+					'layout_strategy' => new EE_Div_Per_Section_Layout(),
209
+					'subsections'     => array(
210
+						// add hidden input to indicate that a new state is being added
211
+						'add_new_state'               => new EE_Hidden_Input(
212
+							array(
213
+								'html_name' => str_replace(
214
+									'state',
215
+									'nsmf_add_new_state',
216
+									$input->html_name()
217
+								),
218
+								'html_id'   => str_replace(
219
+									'state',
220
+									'nsmf_add_new_state',
221
+									$input->html_id()
222
+								),
223
+								'default'   => 0,
224
+							)
225
+						),
226
+						// add link for displaying hidden container
227
+						'click_here_link'             => new EE_Form_Section_HTML(
228
+							apply_filters(
229
+								'FHEE__EED_Add_New_State__display_add_new_state_micro_form__click_here_link',
230
+								EEH_HTML::link(
231
+									'',
232
+									esc_html__('click here to add a new state/province', 'event_espresso'),
233
+									'',
234
+									'display-' . $input->html_id(),
235
+									'ee-form-add-new-state-lnk display-the-hidden smaller-text hide-if-no-js',
236
+									'',
237
+									'data-target="' . $input->html_id() . '"'
238
+								)
239
+							)
240
+						),
241
+						// add initial html for hidden container
242
+						'add_new_state_micro_form'    => new EE_Form_Section_HTML(
243
+							apply_filters(
244
+								'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_micro_form',
245
+								EEH_HTML::div('', $input->html_id() . '-dv', 'ee-form-add-new-state-dv',
246
+									'display: none;') .
247
+								EEH_HTML::h6(
248
+									esc_html__(
249
+										'Is your state/province missing from the dropdown menu above? You can add it by completing the following steps:',
250
+										'event_espresso'
251
+									)
252
+								) .
253
+								EEH_HTML::ul() .
254
+								EEH_HTML::li(
255
+									esc_html__(
256
+										'first select the Country that your State/Province belongs to',
257
+										'event_espresso'
258
+									)
259
+								) .
260
+								EEH_HTML::li(
261
+									esc_html__('enter the name of your State/Province', 'event_espresso')
262
+								) .
263
+								EEH_HTML::li(
264
+									esc_html__(
265
+										'enter a two to six letter abbreviation for the name of your State/Province',
266
+										'event_espresso'
267
+									)
268
+								) .
269
+								EEH_HTML::li(esc_html__('click the ADD button', 'event_espresso')) .
270
+								EEH_HTML::ulx()
271
+							)
272
+						),
273
+						// NEW STATE COUNTRY
274
+						'new_state_country'           => new EE_Country_Select_Input(
275
+							$country_options,
276
+							array(
277
+								'html_name'       => $country_name,
278
+								'html_id'         => str_replace(
279
+									'state',
280
+									'nsmf_new_state_country', $input->html_id()
281
+								),
282
+								'html_class'      => $input->html_class() . ' new-state-country',
283
+								'html_label_text' => esc_html__('New State/Province Country', 'event_espresso'),
284
+								'default'         => EE_Registry::instance()->REQ->get($country_name, ''),
285
+								'required'        => false,
286
+							)
287
+						),
288
+						// NEW STATE NAME
289
+						'new_state_name'              => new EE_Text_Input(
290
+							array(
291
+								'html_name'       => $state_name,
292
+								'html_id'         => str_replace(
293
+									'state',
294
+									'nsmf_new_state_name', $input->html_id()
295
+								),
296
+								'html_class'      => $input->html_class() . ' new-state-state',
297
+								'html_label_text' => esc_html__('New State/Province Name',
298
+									'event_espresso'),
299
+								'default'         => EE_Registry::instance()->REQ->get($state_name, ''),
300
+								'required'        => false,
301
+							)
302
+						),
303
+						'spacer'                      => new EE_Form_Section_HTML(EEH_HTML::br()),
304
+						// NEW STATE NAME
305
+						'new_state_abbrv'             => new EE_Text_Input(
306
+							array(
307
+								'html_name'             => $abbrv_name,
308
+								'html_id'               => str_replace('state', 'nsmf_new_state_abbrv',
309
+									$input->html_id()),
310
+								'html_class'            => $input->html_class() . ' new-state-abbrv',
311
+								'html_label_text'       => esc_html__(
312
+															   'New State/Province Abbreviation',
313
+															   'event_espresso'
314
+														   ) . ' *',
315
+								'html_other_attributes' => 'size="24"',
316
+								'default'               => EE_Registry::instance()->REQ->get($abbrv_name, ''),
317
+								'required'              => false,
318
+							)
319
+						),
320
+						// "submit" button
321
+						'add_new_state_submit_button' => new EE_Form_Section_HTML(
322
+							apply_filters(
323
+								'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_submit_button',
324
+								EEH_HTML::nbsp(3) .
325
+								EEH_HTML::link(
326
+									'',
327
+									esc_html__('ADD', 'event_espresso'),
328
+									'',
329
+									'submit-' . $new_state_submit_id,
330
+									'ee-form-add-new-state-submit button button-secondary',
331
+									'',
332
+									'data-target="' . $new_state_submit_id . '"'
333
+								)
334
+							)
335
+						),
336
+						// extra info
337
+						'add_new_state_extra'         => new EE_Form_Section_HTML(
338
+							apply_filters(
339
+								'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_extra',
340
+								EEH_HTML::br(2)
341
+								.
342
+								EEH_HTML::div('', '', 'small-text')
343
+								.
344
+								EEH_HTML::strong(
345
+									'* ' .
346
+									esc_html__(
347
+										'Don\'t know your State/Province Abbreviation?',
348
+										'event_espresso'
349
+									)
350
+								)
351
+								.
352
+								EEH_HTML::br()
353
+								.
354
+								sprintf(
355
+									esc_html__(
356
+										'You can look here: %s, for a list of Countries and links to their State/Province Abbreviations ("Subdivisions assigned codes" column).',
357
+										'event_espresso'
358
+									),
359
+									EEH_HTML::link(
360
+										'http://en.wikipedia.org/wiki/ISO_3166-2',
361
+										'http://en.wikipedia.org/wiki/ISO_3166-2',
362
+										'',
363
+										'',
364
+										'ee-form-add-new-state-wiki-lnk',
365
+										'',
366
+										'target="_blank"'
367
+									)
368
+								)
369
+								.
370
+								EEH_HTML::divx()
371
+								.
372
+								EEH_HTML::br()
373
+								.
374
+								EEH_HTML::link(
375
+									'',
376
+									esc_html__('cancel new State/Province', 'event_espresso'),
377
+									'',
378
+									'hide-' . $input->html_id(),
379
+									'ee-form-cancel-new-state-lnk smaller-text',
380
+									'',
381
+									'data-target="' . $input->html_id() . '"'
382
+								)
383
+								.
384
+								EEH_HTML::divx()
385
+								.
386
+								EEH_HTML::br()
387
+							)
388
+						),
389
+					),
390
+				)
391
+			);
392
+			$question_group_reg_form->add_subsections(
393
+				array('new_state_micro_form' => $new_state_micro_form),
394
+				'state',
395
+				false
396
+			);
397
+		}
398
+		return $question_group_reg_form;
399
+	}
400
+
401
+
402
+
403
+	/**
404
+	 * set_new_state_input_width
405
+	 *
406
+	 * @return int|string
407
+	 * @throws EE_Error
408
+	 * @throws InvalidArgumentException
409
+	 * @throws InvalidDataTypeException
410
+	 * @throws InvalidInterfaceException
411
+	 * @throws ReflectionException
412
+	 */
413
+	public static function add_new_state()
414
+	{
415
+		$REQ = EE_Registry::instance()->load_core('Request_Handler');
416
+		if (absint($REQ->get('nsmf_add_new_state')) === 1) {
417
+			EE_Registry::instance()->load_model('State');
418
+			// grab country ISO code, new state name, and new state abbreviation
419
+			$state_country = $REQ->is_set('nsmf_new_state_country')
420
+				? sanitize_text_field($REQ->get('nsmf_new_state_country'))
421
+				: false;
422
+			$state_name    = $REQ->is_set('nsmf_new_state_name')
423
+				? sanitize_text_field($REQ->get('nsmf_new_state_name'))
424
+				: false;
425
+			$state_abbr    = $REQ->is_set('nsmf_new_state_abbrv')
426
+				? sanitize_text_field($REQ->get('nsmf_new_state_abbrv'))
427
+				: false;
428
+			if ($state_country && $state_name && $state_abbr) {
429
+				$new_state = EED_Add_New_State::save_new_state_to_db(array(
430
+					'CNT_ISO'    => strtoupper($state_country),
431
+					'STA_abbrev' => strtoupper($state_abbr),
432
+					'STA_name'   => ucwords($state_name),
433
+					'STA_active' => false,
434
+				));
435
+				if ($new_state instanceof EE_State) {
436
+					// clean house
437
+					EE_Registry::instance()->REQ->un_set('nsmf_add_new_state');
438
+					EE_Registry::instance()->REQ->un_set('nsmf_new_state_country');
439
+					EE_Registry::instance()->REQ->un_set('nsmf_new_state_name');
440
+					EE_Registry::instance()->REQ->un_set('nsmf_new_state_abbrv');
441
+					// get any existing new states
442
+					$new_states                   = EE_Registry::instance()->SSN->get_session_data(
443
+						'nsmf_new_states'
444
+					);
445
+					$new_states[$new_state->ID()] = $new_state;
446
+					EE_Registry::instance()->SSN->set_session_data(
447
+						array('nsmf_new_states' => $new_states)
448
+					);
449
+					if (EE_Registry::instance()->REQ->ajax) {
450
+						echo wp_json_encode(array(
451
+							'success'      => true,
452
+							'id'           => $new_state->ID(),
453
+							'name'         => $new_state->name(),
454
+							'abbrev'       => $new_state->abbrev(),
455
+							'country_iso'  => $new_state->country_iso(),
456
+							'country_name' => $new_state->country()->name(),
457
+						));
458
+						exit();
459
+					}
460
+					return $new_state->ID();
461
+				}
462
+			} else {
463
+				$error = esc_html__(
464
+					'A new State/Province could not be added because invalid or missing data was received.',
465
+					'event_espresso'
466
+				);
467
+				if (EE_Registry::instance()->REQ->ajax) {
468
+					echo wp_json_encode(array('error' => $error));
469
+					exit();
470
+				}
471
+				EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
472
+			}
473
+		}
474
+		return false;
475
+	}
476
+
477
+
478
+
479
+	/**
480
+	 * recursively drills down through request params to remove any that were added by this module
481
+	 *
482
+	 * @param array $request_params
483
+	 * @return array
484
+	 */
485
+	public static function filter_checkout_request_params($request_params)
486
+	{
487
+		foreach ($request_params as $form_section) {
488
+			if (is_array($form_section)) {
489
+				EED_Add_New_State::unset_new_state_request_params($form_section);
490
+				EED_Add_New_State::filter_checkout_request_params($form_section);
491
+			}
492
+		}
493
+		return $request_params;
494
+	}
495
+
496
+
497
+
498
+	/**
499
+	 * @param array $request_params
500
+	 * @return array
501
+	 */
502
+	public static function unset_new_state_request_params($request_params)
503
+	{
504
+		unset(
505
+			$request_params['new_state_micro_form'],
506
+			$request_params['new_state_micro_add_new_state'],
507
+			$request_params['new_state_micro_new_state_country'],
508
+			$request_params['new_state_micro_new_state_name'],
509
+			$request_params['new_state_micro_new_state_abbrv']
510
+		);
511
+		return $request_params;
512
+	}
513
+
514
+
515
+
516
+	/**
517
+	 * @param array $props_n_values
518
+	 * @return bool
519
+	 * @throws EE_Error
520
+	 * @throws InvalidArgumentException
521
+	 * @throws InvalidDataTypeException
522
+	 * @throws InvalidInterfaceException
523
+	 */
524
+	public static function save_new_state_to_db($props_n_values = array())
525
+	{
526
+		$existing_state = EEM_State::instance()->get_all(array($props_n_values, 'limit' => 1));
527
+		if (! empty($existing_state)) {
528
+			return array_pop($existing_state);
529
+		}
530
+		$new_state = EE_State::new_instance($props_n_values);
531
+		if ($new_state instanceof EE_State) {
532
+			// if not non-ajax admin
533
+			$new_state_key    = 'new-state-added-' . $new_state->country_iso() . '-' . $new_state->abbrev();
534
+			$new_state_notice = sprintf(
535
+				esc_html__(
536
+					'A new State named "%1$s (%2$s)" was dynamically added from an Event Espresso form for the Country of "%3$s".%5$sTo verify, edit, and/or delete this new State, please go to the %4$s and update the States / Provinces section.%5$sCheck "Yes" to have this new State added to dropdown select lists in forms.',
537
+					'event_espresso'
538
+				),
539
+				'<b>' . $new_state->name() . '</b>',
540
+				'<b>' . $new_state->abbrev() . '</b>',
541
+				'<b>' . $new_state->country()->name() . '</b>',
542
+				'<a href="' . add_query_arg(array(
543
+					'page'    => 'espresso_general_settings',
544
+					'action'  => 'country_settings',
545
+					'country' => $new_state->country_iso(),
546
+				), admin_url('admin.php')) . '">' . esc_html__('Event Espresso - General Settings > Countries Tab',
547
+					'event_espresso') . '</a>',
548
+				'<br />'
549
+			);
550
+			EE_Error::add_persistent_admin_notice($new_state_key, $new_state_notice);
551
+			$new_state->save();
552
+			EEM_State::instance()->reset_cached_states();
553
+			return $new_state;
554
+		}
555
+		return false;
556
+	}
557
+
558
+
559
+
560
+	/**
561
+	 * @param string $CNT_ISO
562
+	 * @param string $STA_ID
563
+	 * @param array  $cols_n_values
564
+	 * @return void
565
+	 * @throws EE_Error
566
+	 * @throws InvalidArgumentException
567
+	 * @throws InvalidDataTypeException
568
+	 * @throws InvalidInterfaceException
569
+	 */
570
+	public static function update_country_settings($CNT_ISO = '', $STA_ID = '', $cols_n_values = array())
571
+	{
572
+		if (! $CNT_ISO) {
573
+			EE_Error::add_error(
574
+				esc_html__('An invalid or missing Country ISO Code was received.', 'event_espresso'),
575
+				__FILE__,
576
+				__FUNCTION__,
577
+				__LINE__
578
+			);
579
+		}
580
+		$STA_abbrev = is_array($cols_n_values) && isset($cols_n_values['STA_abbrev']) ? $cols_n_values['STA_abbrev']
581
+			: false;
582
+		if (! $STA_abbrev && ! empty($STA_ID)) {
583
+			$state = EEM_State::instance()->get_one_by_ID($STA_ID);
584
+			if ($state instanceof EE_State) {
585
+				$STA_abbrev = $state->abbrev();
586
+			}
587
+		}
588
+		if (! $STA_abbrev) {
589
+			EE_Error::add_error(
590
+				esc_html__('An invalid or missing State Abbreviation was received.', 'event_espresso'),
591
+				__FILE__,
592
+				__FUNCTION__,
593
+				__LINE__
594
+			);
595
+		}
596
+		EE_Error::dismiss_persistent_admin_notice($CNT_ISO . '-' . $STA_abbrev, true, true);
597
+	}
598
+
599
+
600
+
601
+	/**
602
+	 * @param EE_State[]                            $state_options
603
+	 * @param EE_SPCO_Reg_Step_Attendee_Information $reg_step
604
+	 * @param EE_Registration                       $registration
605
+	 * @param EE_Question                           $question
606
+	 * @param                                       $answer
607
+	 * @return array
608
+	 * @throws EE_Error
609
+	 * @throws InvalidArgumentException
610
+	 * @throws InvalidDataTypeException
611
+	 * @throws InvalidInterfaceException
612
+	 */
613
+	public static function inject_new_reg_state_into_options(
614
+		$state_options = array(),
615
+		EE_SPCO_Reg_Step_Attendee_Information $reg_step,
616
+		EE_Registration $registration,
617
+		EE_Question $question,
618
+		$answer
619
+	) {
620
+		if ($answer instanceof EE_Answer && $question instanceof EE_Question
621
+			&& $question->type() === EEM_Question::QST_type_state
622
+		) {
623
+			$STA_ID = $answer->value();
624
+			if (! empty($STA_ID)) {
625
+				$state = EEM_State::instance()->get_one_by_ID($STA_ID);
626
+				if ($state instanceof EE_State) {
627
+					$country = $state->country();
628
+					if ($country instanceof EE_Country) {
629
+						if (! isset($state_options[$country->name()])) {
630
+							$state_options[$country->name()] = array();
631
+						}
632
+						if (! isset($state_options[$country->name()][$STA_ID])) {
633
+							$state_options[$country->name()][$STA_ID] = $state->name();
634
+						}
635
+					}
636
+				}
637
+			}
638
+		}
639
+		return $state_options;
640
+	}
641
+
642
+
643
+
644
+	/**
645
+	 * @param EE_Country[]                          $country_options
646
+	 * @param EE_SPCO_Reg_Step_Attendee_Information $reg_step
647
+	 * @param EE_Registration                       $registration
648
+	 * @param EE_Question                           $question
649
+	 * @param                                       $answer
650
+	 * @return array
651
+	 * @throws EE_Error
652
+	 * @throws InvalidArgumentException
653
+	 * @throws InvalidDataTypeException
654
+	 * @throws InvalidInterfaceException
655
+	 */
656
+	public static function inject_new_reg_country_into_options(
657
+		$country_options = array(),
658
+		EE_SPCO_Reg_Step_Attendee_Information $reg_step,
659
+		EE_Registration $registration,
660
+		EE_Question $question,
661
+		$answer
662
+	) {
663
+		if ($answer instanceof EE_Answer && $question instanceof EE_Question
664
+			&& $question->type()
665
+			   === EEM_Question::QST_type_country
666
+		) {
667
+			$CNT_ISO = $answer->value();
668
+			if (! empty($CNT_ISO)) {
669
+				$country = EEM_Country::instance()->get_one_by_ID($CNT_ISO);
670
+				if ($country instanceof EE_Country) {
671
+					if (! isset($country_options[$CNT_ISO])) {
672
+						$country_options[$CNT_ISO] = $country->name();
673
+					}
674
+				}
675
+			}
676
+		}
677
+		return $country_options;
678
+	}
679
+
680
+
681
+
682
+	/**
683
+	 * @param EE_State[] $state_options
684
+	 * @return array
685
+	 * @throws EE_Error
686
+	 * @throws InvalidArgumentException
687
+	 * @throws InvalidDataTypeException
688
+	 * @throws InvalidInterfaceException
689
+	 */
690
+	public static function state_options($state_options = array())
691
+	{
692
+		$new_states = EED_Add_New_State::_get_new_states();
693
+		foreach ($new_states as $new_state) {
694
+			if (
695
+				$new_state instanceof EE_State
696
+				&& $new_state->country() instanceof EE_Country
697
+			) {
698
+				$state_options[$new_state->country()->name()][$new_state->ID()] = $new_state->name();
699
+			}
700
+		}
701
+		return $state_options;
702
+	}
703
+
704
+
705
+
706
+	/**
707
+	 * @return array
708
+	 * @throws InvalidArgumentException
709
+	 * @throws InvalidDataTypeException
710
+	 * @throws InvalidInterfaceException
711
+	 */
712
+	protected static function _get_new_states()
713
+	{
714
+		$new_states = array();
715
+		if (EE_Registry::instance()->SSN instanceof EE_Session) {
716
+			$new_states = EE_Registry::instance()->SSN->get_session_data(
717
+				'nsmf_new_states'
718
+			);
719
+		}
720
+		return is_array($new_states) ? $new_states : array();
721
+	}
722
+
723
+
724
+
725
+	/**
726
+	 * @param EE_Country[] $country_options
727
+	 * @return array
728
+	 * @throws EE_Error
729
+	 * @throws InvalidArgumentException
730
+	 * @throws InvalidDataTypeException
731
+	 * @throws InvalidInterfaceException
732
+	 */
733
+	public static function country_options($country_options = array())
734
+	{
735
+		$new_states = EED_Add_New_State::_get_new_states();
736
+		foreach ($new_states as $new_state) {
737
+			if (
738
+				$new_state instanceof EE_State
739
+				&& $new_state->country() instanceof EE_Country
740
+			) {
741
+				$country_options[$new_state->country()->ID()] = $new_state->country()->name();
742
+			}
743
+		}
744
+		return $country_options;
745
+	}
746 746
 
747 747
 
748 748
 
Please login to merge, or discard this patch.
Spacing   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -96,11 +96,11 @@  discard block
 block discarded – undo
96 96
      */
97 97
     public static function set_definitions()
98 98
     {
99
-        define('ANS_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets' . DS);
99
+        define('ANS_ASSETS_URL', plugin_dir_url(__FILE__).'assets'.DS);
100 100
         define('ANS_TEMPLATES_PATH', str_replace(
101 101
                                          '\\',
102 102
                                          DS,
103
-                                         plugin_dir_path(__FILE__)) . 'templates' . DS
103
+                                         plugin_dir_path(__FILE__)).'templates'.DS
104 104
         );
105 105
     }
106 106
 
@@ -121,19 +121,19 @@  discard block
 block discarded – undo
121 121
      */
122 122
     public static function translate_js_strings()
123 123
     {
124
-        EE_Registry::$i18n_js_strings['ans_no_country']        = esc_html__(
124
+        EE_Registry::$i18n_js_strings['ans_no_country'] = esc_html__(
125 125
             'In order to proceed, you need to select the Country that your State/Province belongs to.',
126 126
             'event_espresso'
127 127
         );
128
-        EE_Registry::$i18n_js_strings['ans_no_name']           = esc_html__(
128
+        EE_Registry::$i18n_js_strings['ans_no_name'] = esc_html__(
129 129
             'In order to proceed, you need to enter the name of your State/Province.',
130 130
             'event_espresso'
131 131
         );
132
-        EE_Registry::$i18n_js_strings['ans_no_abbreviation']   = esc_html__(
132
+        EE_Registry::$i18n_js_strings['ans_no_abbreviation'] = esc_html__(
133 133
             'In order to proceed, you need to enter an abbreviation for the name of your State/Province.',
134 134
             'event_espresso'
135 135
         );
136
-        EE_Registry::$i18n_js_strings['ans_save_success']      = esc_html__(
136
+        EE_Registry::$i18n_js_strings['ans_save_success'] = esc_html__(
137 137
             'The new state was successfully saved to the database.',
138 138
             'event_espresso'
139 139
         );
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
     public static function wp_enqueue_scripts()
152 152
     {
153 153
         if (apply_filters('EED_Single_Page_Checkout__SPCO_active', false)) {
154
-            wp_register_script('add_new_state', ANS_ASSETS_URL . 'add_new_state.js',
154
+            wp_register_script('add_new_state', ANS_ASSETS_URL.'add_new_state.js',
155 155
                 array('espresso_core', 'single_page_checkout'), EVENT_ESPRESSO_VERSION, true);
156 156
             wp_enqueue_script('add_new_state');
157 157
         }
@@ -194,7 +194,7 @@  discard block
 block discarded – undo
194 194
             $new_state_submit_id = str_replace('state', 'new_state', $input->html_id());
195 195
             $country_options     = array();
196 196
             $countries           = EEM_Country::instance()->get_all_countries();
197
-            if (! empty($countries)) {
197
+            if ( ! empty($countries)) {
198 198
                 foreach ($countries as $country) {
199 199
                     if ($country instanceof EE_Country) {
200 200
                         $country_options[$country->ID()] = $country->name();
@@ -231,10 +231,10 @@  discard block
 block discarded – undo
231 231
                                     '',
232 232
                                     esc_html__('click here to add a new state/province', 'event_espresso'),
233 233
                                     '',
234
-                                    'display-' . $input->html_id(),
234
+                                    'display-'.$input->html_id(),
235 235
                                     'ee-form-add-new-state-lnk display-the-hidden smaller-text hide-if-no-js',
236 236
                                     '',
237
-                                    'data-target="' . $input->html_id() . '"'
237
+                                    'data-target="'.$input->html_id().'"'
238 238
                                 )
239 239
                             )
240 240
                         ),
@@ -242,31 +242,31 @@  discard block
 block discarded – undo
242 242
                         'add_new_state_micro_form'    => new EE_Form_Section_HTML(
243 243
                             apply_filters(
244 244
                                 'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_micro_form',
245
-                                EEH_HTML::div('', $input->html_id() . '-dv', 'ee-form-add-new-state-dv',
246
-                                    'display: none;') .
245
+                                EEH_HTML::div('', $input->html_id().'-dv', 'ee-form-add-new-state-dv',
246
+                                    'display: none;').
247 247
                                 EEH_HTML::h6(
248 248
                                     esc_html__(
249 249
                                         'Is your state/province missing from the dropdown menu above? You can add it by completing the following steps:',
250 250
                                         'event_espresso'
251 251
                                     )
252
-                                ) .
253
-                                EEH_HTML::ul() .
252
+                                ).
253
+                                EEH_HTML::ul().
254 254
                                 EEH_HTML::li(
255 255
                                     esc_html__(
256 256
                                         'first select the Country that your State/Province belongs to',
257 257
                                         'event_espresso'
258 258
                                     )
259
-                                ) .
259
+                                ).
260 260
                                 EEH_HTML::li(
261 261
                                     esc_html__('enter the name of your State/Province', 'event_espresso')
262
-                                ) .
262
+                                ).
263 263
                                 EEH_HTML::li(
264 264
                                     esc_html__(
265 265
                                         'enter a two to six letter abbreviation for the name of your State/Province',
266 266
                                         'event_espresso'
267 267
                                     )
268
-                                ) .
269
-                                EEH_HTML::li(esc_html__('click the ADD button', 'event_espresso')) .
268
+                                ).
269
+                                EEH_HTML::li(esc_html__('click the ADD button', 'event_espresso')).
270 270
                                 EEH_HTML::ulx()
271 271
                             )
272 272
                         ),
@@ -279,7 +279,7 @@  discard block
 block discarded – undo
279 279
                                     'state',
280 280
                                     'nsmf_new_state_country', $input->html_id()
281 281
                                 ),
282
-                                'html_class'      => $input->html_class() . ' new-state-country',
282
+                                'html_class'      => $input->html_class().' new-state-country',
283 283
                                 'html_label_text' => esc_html__('New State/Province Country', 'event_espresso'),
284 284
                                 'default'         => EE_Registry::instance()->REQ->get($country_name, ''),
285 285
                                 'required'        => false,
@@ -293,7 +293,7 @@  discard block
 block discarded – undo
293 293
                                     'state',
294 294
                                     'nsmf_new_state_name', $input->html_id()
295 295
                                 ),
296
-                                'html_class'      => $input->html_class() . ' new-state-state',
296
+                                'html_class'      => $input->html_class().' new-state-state',
297 297
                                 'html_label_text' => esc_html__('New State/Province Name',
298 298
                                     'event_espresso'),
299 299
                                 'default'         => EE_Registry::instance()->REQ->get($state_name, ''),
@@ -307,11 +307,11 @@  discard block
 block discarded – undo
307 307
                                 'html_name'             => $abbrv_name,
308 308
                                 'html_id'               => str_replace('state', 'nsmf_new_state_abbrv',
309 309
                                     $input->html_id()),
310
-                                'html_class'            => $input->html_class() . ' new-state-abbrv',
310
+                                'html_class'            => $input->html_class().' new-state-abbrv',
311 311
                                 'html_label_text'       => esc_html__(
312 312
                                                                'New State/Province Abbreviation',
313 313
                                                                'event_espresso'
314
-                                                           ) . ' *',
314
+                                                           ).' *',
315 315
                                 'html_other_attributes' => 'size="24"',
316 316
                                 'default'               => EE_Registry::instance()->REQ->get($abbrv_name, ''),
317 317
                                 'required'              => false,
@@ -321,15 +321,15 @@  discard block
 block discarded – undo
321 321
                         'add_new_state_submit_button' => new EE_Form_Section_HTML(
322 322
                             apply_filters(
323 323
                                 'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_submit_button',
324
-                                EEH_HTML::nbsp(3) .
324
+                                EEH_HTML::nbsp(3).
325 325
                                 EEH_HTML::link(
326 326
                                     '',
327 327
                                     esc_html__('ADD', 'event_espresso'),
328 328
                                     '',
329
-                                    'submit-' . $new_state_submit_id,
329
+                                    'submit-'.$new_state_submit_id,
330 330
                                     'ee-form-add-new-state-submit button button-secondary',
331 331
                                     '',
332
-                                    'data-target="' . $new_state_submit_id . '"'
332
+                                    'data-target="'.$new_state_submit_id.'"'
333 333
                                 )
334 334
                             )
335 335
                         ),
@@ -342,7 +342,7 @@  discard block
 block discarded – undo
342 342
                                 EEH_HTML::div('', '', 'small-text')
343 343
                                 .
344 344
                                 EEH_HTML::strong(
345
-                                    '* ' .
345
+                                    '* '.
346 346
                                     esc_html__(
347 347
                                         'Don\'t know your State/Province Abbreviation?',
348 348
                                         'event_espresso'
@@ -375,10 +375,10 @@  discard block
 block discarded – undo
375 375
                                     '',
376 376
                                     esc_html__('cancel new State/Province', 'event_espresso'),
377 377
                                     '',
378
-                                    'hide-' . $input->html_id(),
378
+                                    'hide-'.$input->html_id(),
379 379
                                     'ee-form-cancel-new-state-lnk smaller-text',
380 380
                                     '',
381
-                                    'data-target="' . $input->html_id() . '"'
381
+                                    'data-target="'.$input->html_id().'"'
382 382
                                 )
383 383
                                 .
384 384
                                 EEH_HTML::divx()
@@ -524,27 +524,27 @@  discard block
 block discarded – undo
524 524
     public static function save_new_state_to_db($props_n_values = array())
525 525
     {
526 526
         $existing_state = EEM_State::instance()->get_all(array($props_n_values, 'limit' => 1));
527
-        if (! empty($existing_state)) {
527
+        if ( ! empty($existing_state)) {
528 528
             return array_pop($existing_state);
529 529
         }
530 530
         $new_state = EE_State::new_instance($props_n_values);
531 531
         if ($new_state instanceof EE_State) {
532 532
             // if not non-ajax admin
533
-            $new_state_key    = 'new-state-added-' . $new_state->country_iso() . '-' . $new_state->abbrev();
533
+            $new_state_key    = 'new-state-added-'.$new_state->country_iso().'-'.$new_state->abbrev();
534 534
             $new_state_notice = sprintf(
535 535
                 esc_html__(
536 536
                     'A new State named "%1$s (%2$s)" was dynamically added from an Event Espresso form for the Country of "%3$s".%5$sTo verify, edit, and/or delete this new State, please go to the %4$s and update the States / Provinces section.%5$sCheck "Yes" to have this new State added to dropdown select lists in forms.',
537 537
                     'event_espresso'
538 538
                 ),
539
-                '<b>' . $new_state->name() . '</b>',
540
-                '<b>' . $new_state->abbrev() . '</b>',
541
-                '<b>' . $new_state->country()->name() . '</b>',
542
-                '<a href="' . add_query_arg(array(
539
+                '<b>'.$new_state->name().'</b>',
540
+                '<b>'.$new_state->abbrev().'</b>',
541
+                '<b>'.$new_state->country()->name().'</b>',
542
+                '<a href="'.add_query_arg(array(
543 543
                     'page'    => 'espresso_general_settings',
544 544
                     'action'  => 'country_settings',
545 545
                     'country' => $new_state->country_iso(),
546
-                ), admin_url('admin.php')) . '">' . esc_html__('Event Espresso - General Settings > Countries Tab',
547
-                    'event_espresso') . '</a>',
546
+                ), admin_url('admin.php')).'">'.esc_html__('Event Espresso - General Settings > Countries Tab',
547
+                    'event_espresso').'</a>',
548 548
                 '<br />'
549 549
             );
550 550
             EE_Error::add_persistent_admin_notice($new_state_key, $new_state_notice);
@@ -569,7 +569,7 @@  discard block
 block discarded – undo
569 569
      */
570 570
     public static function update_country_settings($CNT_ISO = '', $STA_ID = '', $cols_n_values = array())
571 571
     {
572
-        if (! $CNT_ISO) {
572
+        if ( ! $CNT_ISO) {
573 573
             EE_Error::add_error(
574 574
                 esc_html__('An invalid or missing Country ISO Code was received.', 'event_espresso'),
575 575
                 __FILE__,
@@ -579,13 +579,13 @@  discard block
 block discarded – undo
579 579
         }
580 580
         $STA_abbrev = is_array($cols_n_values) && isset($cols_n_values['STA_abbrev']) ? $cols_n_values['STA_abbrev']
581 581
             : false;
582
-        if (! $STA_abbrev && ! empty($STA_ID)) {
582
+        if ( ! $STA_abbrev && ! empty($STA_ID)) {
583 583
             $state = EEM_State::instance()->get_one_by_ID($STA_ID);
584 584
             if ($state instanceof EE_State) {
585 585
                 $STA_abbrev = $state->abbrev();
586 586
             }
587 587
         }
588
-        if (! $STA_abbrev) {
588
+        if ( ! $STA_abbrev) {
589 589
             EE_Error::add_error(
590 590
                 esc_html__('An invalid or missing State Abbreviation was received.', 'event_espresso'),
591 591
                 __FILE__,
@@ -593,7 +593,7 @@  discard block
 block discarded – undo
593 593
                 __LINE__
594 594
             );
595 595
         }
596
-        EE_Error::dismiss_persistent_admin_notice($CNT_ISO . '-' . $STA_abbrev, true, true);
596
+        EE_Error::dismiss_persistent_admin_notice($CNT_ISO.'-'.$STA_abbrev, true, true);
597 597
     }
598 598
 
599 599
 
@@ -621,15 +621,15 @@  discard block
 block discarded – undo
621 621
             && $question->type() === EEM_Question::QST_type_state
622 622
         ) {
623 623
             $STA_ID = $answer->value();
624
-            if (! empty($STA_ID)) {
624
+            if ( ! empty($STA_ID)) {
625 625
                 $state = EEM_State::instance()->get_one_by_ID($STA_ID);
626 626
                 if ($state instanceof EE_State) {
627 627
                     $country = $state->country();
628 628
                     if ($country instanceof EE_Country) {
629
-                        if (! isset($state_options[$country->name()])) {
629
+                        if ( ! isset($state_options[$country->name()])) {
630 630
                             $state_options[$country->name()] = array();
631 631
                         }
632
-                        if (! isset($state_options[$country->name()][$STA_ID])) {
632
+                        if ( ! isset($state_options[$country->name()][$STA_ID])) {
633 633
                             $state_options[$country->name()][$STA_ID] = $state->name();
634 634
                         }
635 635
                     }
@@ -665,10 +665,10 @@  discard block
 block discarded – undo
665 665
                === EEM_Question::QST_type_country
666 666
         ) {
667 667
             $CNT_ISO = $answer->value();
668
-            if (! empty($CNT_ISO)) {
668
+            if ( ! empty($CNT_ISO)) {
669 669
                 $country = EEM_Country::instance()->get_one_by_ID($CNT_ISO);
670 670
                 if ($country instanceof EE_Country) {
671
-                    if (! isset($country_options[$CNT_ISO])) {
671
+                    if ( ! isset($country_options[$CNT_ISO])) {
672 672
                         $country_options[$CNT_ISO] = $country->name();
673 673
                     }
674 674
                 }
Please login to merge, or discard this patch.
core/EE_Addon.core.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -140,7 +140,7 @@
 block discarded – undo
140 140
      * Sets addon_name
141 141
      *
142 142
      * @param string $addon_name
143
-     * @return boolean
143
+     * @return string
144 144
      */
145 145
     public function set_name($addon_name)
146 146
     {
Please login to merge, or discard this patch.
Indentation   +714 added lines, -714 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if (! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 /**
5 5
  * Event Espresso
@@ -25,702 +25,702 @@  discard block
 block discarded – undo
25 25
 {
26 26
 
27 27
 
28
-    /**
29
-     * prefix to be added onto an addon's plugin slug to make a wp option name
30
-     * which will be used to store the plugin's activation history
31
-     */
32
-    const ee_addon_version_history_option_prefix = 'ee_version_history_';
33
-
34
-    /**
35
-     * @var $_version
36
-     * @type string
37
-     */
38
-    protected $_version = '';
39
-
40
-    /**
41
-     * @var $_min_core_version
42
-     * @type string
43
-     */
44
-    protected $_min_core_version = '';
45
-
46
-    /**
47
-     * derived from plugin 'main_file_path using plugin_basename()
48
-     *
49
-     * @type string $_plugin_basename
50
-     */
51
-    protected $_plugin_basename = '';
52
-
53
-    /**
54
-     * A non-internationalized name to identify this addon for use in URLs, etc
55
-     *
56
-     * @type string $_plugin_slug
57
-     */
58
-    protected $_plugin_slug = '';
59
-
60
-    /**
61
-     * A non-internationalized name to identify this addon. Eg 'Calendar','MailChimp',etc/
62
-     *
63
-     * @type string _addon_name
64
-     */
65
-    protected $_addon_name = '';
66
-
67
-    /**
68
-     * one of the EE_System::req_type_* constants
69
-     *
70
-     * @type int $_req_type
71
-     */
72
-    protected $_req_type;
73
-
74
-    /**
75
-     * page slug to be used when generating the "Settings" link on the WP plugin page
76
-     *
77
-     * @type string $_plugin_action_slug
78
-     */
79
-    protected $_plugin_action_slug = '';
80
-
81
-    /**
82
-     * if not empty, inserts a new table row after this plugin's row on the WP Plugins page
83
-     * that can be used for adding upgrading/marketing info
84
-     *
85
-     * @type array $_plugins_page_row
86
-     */
87
-    protected $_plugins_page_row = array();
88
-
89
-
90
-    /**
91
-     *    class constructor
92
-     */
93
-    public function __construct()
94
-    {
95
-        add_action('AHEE__EE_System__load_controllers__load_admin_controllers', array($this, 'admin_init'));
96
-    }
97
-
98
-
99
-    /**
100
-     * @param mixed $version
101
-     */
102
-    public function set_version($version = null)
103
-    {
104
-        $this->_version = $version;
105
-    }
106
-
107
-
108
-    /**
109
-     * get__version
110
-     *
111
-     * @return string
112
-     */
113
-    public function version()
114
-    {
115
-        return $this->_version;
116
-    }
117
-
118
-
119
-    /**
120
-     * @param mixed $min_core_version
121
-     */
122
-    public function set_min_core_version($min_core_version = null)
123
-    {
124
-        $this->_min_core_version = $min_core_version;
125
-    }
126
-
127
-
128
-    /**
129
-     * get__min_core_version
130
-     *
131
-     * @return string
132
-     */
133
-    public function min_core_version()
134
-    {
135
-        return $this->_min_core_version;
136
-    }
137
-
138
-
139
-    /**
140
-     * Sets addon_name
141
-     *
142
-     * @param string $addon_name
143
-     * @return boolean
144
-     */
145
-    public function set_name($addon_name)
146
-    {
147
-        return $this->_addon_name = $addon_name;
148
-    }
149
-
150
-
151
-    /**
152
-     * Gets addon_name
153
-     *
154
-     * @return string
155
-     */
156
-    public function name()
157
-    {
158
-        return $this->_addon_name;
159
-    }
160
-
161
-
162
-    /**
163
-     * @return string
164
-     */
165
-    public function plugin_basename()
166
-    {
167
-
168
-        return $this->_plugin_basename;
169
-    }
170
-
171
-
172
-    /**
173
-     * @param string $plugin_basename
174
-     */
175
-    public function set_plugin_basename($plugin_basename)
176
-    {
177
-
178
-        $this->_plugin_basename = $plugin_basename;
179
-    }
180
-
181
-
182
-    /**
183
-     * @return string
184
-     */
185
-    public function plugin_slug()
186
-    {
187
-
188
-        return $this->_plugin_slug;
189
-    }
190
-
191
-
192
-    /**
193
-     * @param string $plugin_slug
194
-     */
195
-    public function set_plugin_slug($plugin_slug)
196
-    {
197
-
198
-        $this->_plugin_slug = $plugin_slug;
199
-    }
200
-
201
-
202
-    /**
203
-     * @return string
204
-     */
205
-    public function plugin_action_slug()
206
-    {
207
-
208
-        return $this->_plugin_action_slug;
209
-    }
210
-
211
-
212
-    /**
213
-     * @param string $plugin_action_slug
214
-     */
215
-    public function set_plugin_action_slug($plugin_action_slug)
216
-    {
217
-
218
-        $this->_plugin_action_slug = $plugin_action_slug;
219
-    }
220
-
221
-
222
-    /**
223
-     * @return array
224
-     */
225
-    public function get_plugins_page_row()
226
-    {
227
-
228
-        return $this->_plugins_page_row;
229
-    }
230
-
231
-
232
-    /**
233
-     * @param array $plugins_page_row
234
-     */
235
-    public function set_plugins_page_row($plugins_page_row = array())
236
-    {
237
-        // sigh.... check for example content that I stupidly merged to master and remove it if found
238
-        if (! is_array($plugins_page_row) && strpos($plugins_page_row,
239
-                '<h3>Promotions Addon Upsell Info</h3>') !== false) {
240
-            $plugins_page_row = '';
241
-        }
242
-        $this->_plugins_page_row = $plugins_page_row;
243
-    }
244
-
245
-
246
-    /**
247
-     * Called when EE core detects this addon has been activated for the first time.
248
-     * If the site isn't in maintenance mode, should setup the addon's database
249
-     *
250
-     * @return void
251
-     */
252
-    public function new_install()
253
-    {
254
-        $classname = get_class($this);
255
-        do_action("AHEE__{$classname}__new_install");
256
-        do_action('AHEE__EE_Addon__new_install', $this);
257
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
258
-        add_action('AHEE__EE_System__perform_activations_upgrades_and_migrations',
259
-            array($this, 'initialize_db_if_no_migrations_required'));
260
-    }
261
-
262
-
263
-    /**
264
-     * Called when EE core detects this addon has been reactivated. When this happens,
265
-     * it's good to just check that your data is still intact
266
-     *
267
-     * @return void
268
-     */
269
-    public function reactivation()
270
-    {
271
-        $classname = get_class($this);
272
-        do_action("AHEE__{$classname}__reactivation");
273
-        do_action('AHEE__EE_Addon__reactivation', $this);
274
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
275
-        add_action('AHEE__EE_System__perform_activations_upgrades_and_migrations',
276
-            array($this, 'initialize_db_if_no_migrations_required'));
277
-    }
278
-
279
-
280
-    public function deactivation()
281
-    {
282
-        $classname = get_class($this);
28
+	/**
29
+	 * prefix to be added onto an addon's plugin slug to make a wp option name
30
+	 * which will be used to store the plugin's activation history
31
+	 */
32
+	const ee_addon_version_history_option_prefix = 'ee_version_history_';
33
+
34
+	/**
35
+	 * @var $_version
36
+	 * @type string
37
+	 */
38
+	protected $_version = '';
39
+
40
+	/**
41
+	 * @var $_min_core_version
42
+	 * @type string
43
+	 */
44
+	protected $_min_core_version = '';
45
+
46
+	/**
47
+	 * derived from plugin 'main_file_path using plugin_basename()
48
+	 *
49
+	 * @type string $_plugin_basename
50
+	 */
51
+	protected $_plugin_basename = '';
52
+
53
+	/**
54
+	 * A non-internationalized name to identify this addon for use in URLs, etc
55
+	 *
56
+	 * @type string $_plugin_slug
57
+	 */
58
+	protected $_plugin_slug = '';
59
+
60
+	/**
61
+	 * A non-internationalized name to identify this addon. Eg 'Calendar','MailChimp',etc/
62
+	 *
63
+	 * @type string _addon_name
64
+	 */
65
+	protected $_addon_name = '';
66
+
67
+	/**
68
+	 * one of the EE_System::req_type_* constants
69
+	 *
70
+	 * @type int $_req_type
71
+	 */
72
+	protected $_req_type;
73
+
74
+	/**
75
+	 * page slug to be used when generating the "Settings" link on the WP plugin page
76
+	 *
77
+	 * @type string $_plugin_action_slug
78
+	 */
79
+	protected $_plugin_action_slug = '';
80
+
81
+	/**
82
+	 * if not empty, inserts a new table row after this plugin's row on the WP Plugins page
83
+	 * that can be used for adding upgrading/marketing info
84
+	 *
85
+	 * @type array $_plugins_page_row
86
+	 */
87
+	protected $_plugins_page_row = array();
88
+
89
+
90
+	/**
91
+	 *    class constructor
92
+	 */
93
+	public function __construct()
94
+	{
95
+		add_action('AHEE__EE_System__load_controllers__load_admin_controllers', array($this, 'admin_init'));
96
+	}
97
+
98
+
99
+	/**
100
+	 * @param mixed $version
101
+	 */
102
+	public function set_version($version = null)
103
+	{
104
+		$this->_version = $version;
105
+	}
106
+
107
+
108
+	/**
109
+	 * get__version
110
+	 *
111
+	 * @return string
112
+	 */
113
+	public function version()
114
+	{
115
+		return $this->_version;
116
+	}
117
+
118
+
119
+	/**
120
+	 * @param mixed $min_core_version
121
+	 */
122
+	public function set_min_core_version($min_core_version = null)
123
+	{
124
+		$this->_min_core_version = $min_core_version;
125
+	}
126
+
127
+
128
+	/**
129
+	 * get__min_core_version
130
+	 *
131
+	 * @return string
132
+	 */
133
+	public function min_core_version()
134
+	{
135
+		return $this->_min_core_version;
136
+	}
137
+
138
+
139
+	/**
140
+	 * Sets addon_name
141
+	 *
142
+	 * @param string $addon_name
143
+	 * @return boolean
144
+	 */
145
+	public function set_name($addon_name)
146
+	{
147
+		return $this->_addon_name = $addon_name;
148
+	}
149
+
150
+
151
+	/**
152
+	 * Gets addon_name
153
+	 *
154
+	 * @return string
155
+	 */
156
+	public function name()
157
+	{
158
+		return $this->_addon_name;
159
+	}
160
+
161
+
162
+	/**
163
+	 * @return string
164
+	 */
165
+	public function plugin_basename()
166
+	{
167
+
168
+		return $this->_plugin_basename;
169
+	}
170
+
171
+
172
+	/**
173
+	 * @param string $plugin_basename
174
+	 */
175
+	public function set_plugin_basename($plugin_basename)
176
+	{
177
+
178
+		$this->_plugin_basename = $plugin_basename;
179
+	}
180
+
181
+
182
+	/**
183
+	 * @return string
184
+	 */
185
+	public function plugin_slug()
186
+	{
187
+
188
+		return $this->_plugin_slug;
189
+	}
190
+
191
+
192
+	/**
193
+	 * @param string $plugin_slug
194
+	 */
195
+	public function set_plugin_slug($plugin_slug)
196
+	{
197
+
198
+		$this->_plugin_slug = $plugin_slug;
199
+	}
200
+
201
+
202
+	/**
203
+	 * @return string
204
+	 */
205
+	public function plugin_action_slug()
206
+	{
207
+
208
+		return $this->_plugin_action_slug;
209
+	}
210
+
211
+
212
+	/**
213
+	 * @param string $plugin_action_slug
214
+	 */
215
+	public function set_plugin_action_slug($plugin_action_slug)
216
+	{
217
+
218
+		$this->_plugin_action_slug = $plugin_action_slug;
219
+	}
220
+
221
+
222
+	/**
223
+	 * @return array
224
+	 */
225
+	public function get_plugins_page_row()
226
+	{
227
+
228
+		return $this->_plugins_page_row;
229
+	}
230
+
231
+
232
+	/**
233
+	 * @param array $plugins_page_row
234
+	 */
235
+	public function set_plugins_page_row($plugins_page_row = array())
236
+	{
237
+		// sigh.... check for example content that I stupidly merged to master and remove it if found
238
+		if (! is_array($plugins_page_row) && strpos($plugins_page_row,
239
+				'<h3>Promotions Addon Upsell Info</h3>') !== false) {
240
+			$plugins_page_row = '';
241
+		}
242
+		$this->_plugins_page_row = $plugins_page_row;
243
+	}
244
+
245
+
246
+	/**
247
+	 * Called when EE core detects this addon has been activated for the first time.
248
+	 * If the site isn't in maintenance mode, should setup the addon's database
249
+	 *
250
+	 * @return void
251
+	 */
252
+	public function new_install()
253
+	{
254
+		$classname = get_class($this);
255
+		do_action("AHEE__{$classname}__new_install");
256
+		do_action('AHEE__EE_Addon__new_install', $this);
257
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
258
+		add_action('AHEE__EE_System__perform_activations_upgrades_and_migrations',
259
+			array($this, 'initialize_db_if_no_migrations_required'));
260
+	}
261
+
262
+
263
+	/**
264
+	 * Called when EE core detects this addon has been reactivated. When this happens,
265
+	 * it's good to just check that your data is still intact
266
+	 *
267
+	 * @return void
268
+	 */
269
+	public function reactivation()
270
+	{
271
+		$classname = get_class($this);
272
+		do_action("AHEE__{$classname}__reactivation");
273
+		do_action('AHEE__EE_Addon__reactivation', $this);
274
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
275
+		add_action('AHEE__EE_System__perform_activations_upgrades_and_migrations',
276
+			array($this, 'initialize_db_if_no_migrations_required'));
277
+	}
278
+
279
+
280
+	public function deactivation()
281
+	{
282
+		$classname = get_class($this);
283 283
 //		echo "Deactivating $classname";die;
284
-        do_action("AHEE__{$classname}__deactivation");
285
-        do_action('AHEE__EE_Addon__deactivation', $this);
286
-        //check if the site no longer needs to be in maintenance mode
287
-        EE_Register_Addon::deregister($this->name());
288
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
289
-    }
290
-
291
-
292
-    /**
293
-     * Takes care of double-checking that we're not in maintenance mode, and then
294
-     * initializing this addon's necessary initial data. This is called by default on new activations
295
-     * and reactivations
296
-     *
297
-     * @param boolean $verify_schema whether to verify the database's schema for this addon, or just its data.
298
-     *                               This is a resource-intensive job so we prefer to only do it when necessary
299
-     * @return void
300
-     * @throws \EE_Error
301
-     */
302
-    public function initialize_db_if_no_migrations_required($verify_schema = true)
303
-    {
304
-        if ($verify_schema === '') {
305
-            //wp core bug imo: if no args are passed to `do_action('some_hook_name')` besides the hook's name
306
-            //(ie, no 2nd or 3rd arguments), instead of calling the registered callbacks with no arguments, it
307
-            //calls them with an argument of an empty string (ie ""), which evaluates to false
308
-            //so we need to treat the empty string as if nothing had been passed, and should instead use the default
309
-            $verify_schema = true;
310
-        }
311
-        if (EE_Maintenance_Mode::instance()->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
312
-            if ($verify_schema) {
313
-                $this->initialize_db();
314
-            }
315
-            $this->initialize_default_data();
316
-            //@todo: this will probably need to be adjusted in 4.4 as the array changed formats I believe
317
-            EE_Data_Migration_Manager::instance()->update_current_database_state_to(
318
-                array(
319
-                    'slug'    => $this->name(),
320
-                    'version' => $this->version(),
321
-                )
322
-            );
323
-            /* make sure core's data is a-ok
284
+		do_action("AHEE__{$classname}__deactivation");
285
+		do_action('AHEE__EE_Addon__deactivation', $this);
286
+		//check if the site no longer needs to be in maintenance mode
287
+		EE_Register_Addon::deregister($this->name());
288
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
289
+	}
290
+
291
+
292
+	/**
293
+	 * Takes care of double-checking that we're not in maintenance mode, and then
294
+	 * initializing this addon's necessary initial data. This is called by default on new activations
295
+	 * and reactivations
296
+	 *
297
+	 * @param boolean $verify_schema whether to verify the database's schema for this addon, or just its data.
298
+	 *                               This is a resource-intensive job so we prefer to only do it when necessary
299
+	 * @return void
300
+	 * @throws \EE_Error
301
+	 */
302
+	public function initialize_db_if_no_migrations_required($verify_schema = true)
303
+	{
304
+		if ($verify_schema === '') {
305
+			//wp core bug imo: if no args are passed to `do_action('some_hook_name')` besides the hook's name
306
+			//(ie, no 2nd or 3rd arguments), instead of calling the registered callbacks with no arguments, it
307
+			//calls them with an argument of an empty string (ie ""), which evaluates to false
308
+			//so we need to treat the empty string as if nothing had been passed, and should instead use the default
309
+			$verify_schema = true;
310
+		}
311
+		if (EE_Maintenance_Mode::instance()->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
312
+			if ($verify_schema) {
313
+				$this->initialize_db();
314
+			}
315
+			$this->initialize_default_data();
316
+			//@todo: this will probably need to be adjusted in 4.4 as the array changed formats I believe
317
+			EE_Data_Migration_Manager::instance()->update_current_database_state_to(
318
+				array(
319
+					'slug'    => $this->name(),
320
+					'version' => $this->version(),
321
+				)
322
+			);
323
+			/* make sure core's data is a-ok
324 324
              * (at the time of writing, we especially want to verify all the caps are present
325 325
              * because payment method type capabilities are added dynamically, and it's
326 326
              * possible this addon added a payment method. But it's also possible
327 327
              * other data needs to be verified)
328 328
              */
329
-            EEH_Activation::initialize_db_content();
330
-            update_option('ee_flush_rewrite_rules', true);
331
-            //in case there are lots of addons being activated at once, let's force garbage collection
332
-            //to help avoid memory limit errors
333
-            //EEH_Debug_Tools::instance()->measure_memory( 'db content initialized for ' . get_class( $this), true );
334
-            gc_collect_cycles();
335
-        } else {
336
-            //ask the data migration manager to init this addon's data
337
-            //when migrations are finished because we can't do it now
338
-            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for($this->name());
339
-        }
340
-    }
341
-
342
-
343
-    /**
344
-     * Used to setup this addon's database tables, but not necessarily any default
345
-     * data in them. The default is to actually use the most up-to-date data migration script
346
-     * for this addon, and just use its schema_changes_before_migration() and schema_changes_after_migration()
347
-     * methods to setup the db.
348
-     */
349
-    public function initialize_db()
350
-    {
351
-        //find the migration script that sets the database to be compatible with the code
352
-        $current_dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms($this->name());
353
-        if ($current_dms_name) {
354
-            $current_data_migration_script = EE_Registry::instance()->load_dms($current_dms_name);
355
-            $current_data_migration_script->set_migrating(false);
356
-            $current_data_migration_script->schema_changes_before_migration();
357
-            $current_data_migration_script->schema_changes_after_migration();
358
-            if ($current_data_migration_script->get_errors()) {
359
-                foreach ($current_data_migration_script->get_errors() as $error) {
360
-                    EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
361
-                }
362
-            }
363
-        }
364
-        //if not DMS was found that should be ok. This addon just doesn't require any database changes
365
-        EE_Data_Migration_Manager::instance()->update_current_database_state_to(
366
-            array(
367
-                'slug'    => $this->name(),
368
-                'version' => $this->version(),
369
-            )
370
-        );
371
-    }
372
-
373
-
374
-    /**
375
-     * If you want to setup default data for the addon, override this method, and call
376
-     * parent::initialize_default_data() from within it. This is normally called
377
-     * from EE_Addon::initialize_db_if_no_migrations_required(), just after EE_Addon::initialize_db()
378
-     * and should verify default data is present (but this is also called
379
-     * on reactivations and just after migrations, so please verify you actually want
380
-     * to ADD default data, because it may already be present).
381
-     * However, please call this parent (currently it just fires a hook which other
382
-     * addons may be depending on)
383
-     */
384
-    public function initialize_default_data()
385
-    {
386
-        /**
387
-         * Called when an addon is ensuring its default data is set (possibly called
388
-         * on a reactivation, so first check for the absence of other data before setting
389
-         * default data)
390
-         *
391
-         * @param EE_Addon $addon the addon that called this
392
-         */
393
-        do_action('AHEE__EE_Addon__initialize_default_data__begin', $this);
394
-        //override to insert default data. It is safe to use the models here
395
-        //because the site should not be in maintenance mode
396
-    }
397
-
398
-
399
-    /**
400
-     * EE Core detected that this addon has been upgraded. We should check if there
401
-     * are any new migration scripts, and if so put the site into maintenance mode until
402
-     * they're ran
403
-     *
404
-     * @return void
405
-     */
406
-    public function upgrade()
407
-    {
408
-        $classname = get_class($this);
409
-        do_action("AHEE__{$classname}__upgrade");
410
-        do_action('AHEE__EE_Addon__upgrade', $this);
411
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
412
-        //also it's possible there is new default data that needs to be added
413
-        add_action(
414
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
415
-            array($this, 'initialize_db_if_no_migrations_required')
416
-        );
417
-    }
418
-
419
-
420
-    /**
421
-     * If Core detects this addon has been downgraded, you may want to invoke some special logic here.
422
-     */
423
-    public function downgrade()
424
-    {
425
-        $classname = get_class($this);
426
-        do_action("AHEE__{$classname}__downgrade");
427
-        do_action('AHEE__EE_Addon__downgrade', $this);
428
-        //it's possible there's old default data that needs to be double-checked
429
-        add_action('AHEE__EE_System__perform_activations_upgrades_and_migrations',
430
-            array($this, 'initialize_db_if_no_migrations_required'));
431
-    }
432
-
433
-
434
-    /**
435
-     * set_db_update_option_name
436
-     * Until we do something better, we'll just check for migration scripts upon
437
-     * plugin activation only. In the future, we'll want to do it on plugin updates too
438
-     *
439
-     * @return bool
440
-     */
441
-    public function set_db_update_option_name()
442
-    {
443
-        EE_Error::doing_it_wrong(__FUNCTION__,
444
-            __('EE_Addon::set_db_update_option_name was renamed to EE_Addon::set_activation_indicator_option',
445
-                'event_espresso'), '4.3.0.alpha.016');
446
-        //let's just handle this on the next request, ok? right now we're just not really ready
447
-        return $this->set_activation_indicator_option();
448
-    }
449
-
450
-
451
-    /**
452
-     * Returns the name of the activation indicator option
453
-     * (an option which is set temporarily to indicate that this addon was just activated)
454
-     *
455
-     * @deprecated since version 4.3.0.alpha.016
456
-     * @return string
457
-     */
458
-    public function get_db_update_option_name()
459
-    {
460
-        EE_Error::doing_it_wrong(__FUNCTION__,
461
-            __('EE_Addon::get_db_update_option was renamed to EE_Addon::get_activation_indicator_option_name',
462
-                'event_espresso'), '4.3.0.alpha.016');
463
-        return $this->get_activation_indicator_option_name();
464
-    }
465
-
466
-
467
-    /**
468
-     * When the addon is activated, this should be called to set a wordpress option that
469
-     * indicates it was activated. This is especially useful for detecting reactivations.
470
-     *
471
-     * @return bool
472
-     */
473
-    public function set_activation_indicator_option()
474
-    {
475
-        // let's just handle this on the next request, ok? right now we're just not really ready
476
-        return update_option($this->get_activation_indicator_option_name(), true);
477
-    }
478
-
479
-
480
-    /**
481
-     * Gets the name of the wp option which is used to temporarily indicate that this addon was activated
482
-     *
483
-     * @return string
484
-     */
485
-    public function get_activation_indicator_option_name()
486
-    {
487
-        return 'ee_activation_' . $this->name();
488
-    }
489
-
490
-
491
-    /**
492
-     * Used by EE_System to set the request type of this addon. Should not be used by addon developers
493
-     *
494
-     * @param int $req_type
495
-     */
496
-    public function set_req_type($req_type)
497
-    {
498
-        $this->_req_type = $req_type;
499
-    }
500
-
501
-
502
-    /**
503
-     * Returns the request type of this addon (ie, EE_System::req_type_normal, EE_System::req_type_new_activation,
504
-     * EE_System::req_type_reactivation, EE_System::req_type_upgrade, or EE_System::req_type_downgrade). This is set by
505
-     * EE_System when it is checking for new install or upgrades of addons
506
-     */
507
-    public function detect_req_type()
508
-    {
509
-        if (! $this->_req_type) {
510
-            $this->detect_activation_or_upgrade();
511
-        }
512
-        return $this->_req_type;
513
-    }
514
-
515
-
516
-    /**
517
-     * Detects the request type for this addon (whether it was just activated, upgrades, a normal request, etc.)
518
-     * Should only be called once per request
519
-     *
520
-     * @return void
521
-     */
522
-    public function detect_activation_or_upgrade()
523
-    {
524
-        $activation_history_for_addon = $this->get_activation_history();
329
+			EEH_Activation::initialize_db_content();
330
+			update_option('ee_flush_rewrite_rules', true);
331
+			//in case there are lots of addons being activated at once, let's force garbage collection
332
+			//to help avoid memory limit errors
333
+			//EEH_Debug_Tools::instance()->measure_memory( 'db content initialized for ' . get_class( $this), true );
334
+			gc_collect_cycles();
335
+		} else {
336
+			//ask the data migration manager to init this addon's data
337
+			//when migrations are finished because we can't do it now
338
+			EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for($this->name());
339
+		}
340
+	}
341
+
342
+
343
+	/**
344
+	 * Used to setup this addon's database tables, but not necessarily any default
345
+	 * data in them. The default is to actually use the most up-to-date data migration script
346
+	 * for this addon, and just use its schema_changes_before_migration() and schema_changes_after_migration()
347
+	 * methods to setup the db.
348
+	 */
349
+	public function initialize_db()
350
+	{
351
+		//find the migration script that sets the database to be compatible with the code
352
+		$current_dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms($this->name());
353
+		if ($current_dms_name) {
354
+			$current_data_migration_script = EE_Registry::instance()->load_dms($current_dms_name);
355
+			$current_data_migration_script->set_migrating(false);
356
+			$current_data_migration_script->schema_changes_before_migration();
357
+			$current_data_migration_script->schema_changes_after_migration();
358
+			if ($current_data_migration_script->get_errors()) {
359
+				foreach ($current_data_migration_script->get_errors() as $error) {
360
+					EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
361
+				}
362
+			}
363
+		}
364
+		//if not DMS was found that should be ok. This addon just doesn't require any database changes
365
+		EE_Data_Migration_Manager::instance()->update_current_database_state_to(
366
+			array(
367
+				'slug'    => $this->name(),
368
+				'version' => $this->version(),
369
+			)
370
+		);
371
+	}
372
+
373
+
374
+	/**
375
+	 * If you want to setup default data for the addon, override this method, and call
376
+	 * parent::initialize_default_data() from within it. This is normally called
377
+	 * from EE_Addon::initialize_db_if_no_migrations_required(), just after EE_Addon::initialize_db()
378
+	 * and should verify default data is present (but this is also called
379
+	 * on reactivations and just after migrations, so please verify you actually want
380
+	 * to ADD default data, because it may already be present).
381
+	 * However, please call this parent (currently it just fires a hook which other
382
+	 * addons may be depending on)
383
+	 */
384
+	public function initialize_default_data()
385
+	{
386
+		/**
387
+		 * Called when an addon is ensuring its default data is set (possibly called
388
+		 * on a reactivation, so first check for the absence of other data before setting
389
+		 * default data)
390
+		 *
391
+		 * @param EE_Addon $addon the addon that called this
392
+		 */
393
+		do_action('AHEE__EE_Addon__initialize_default_data__begin', $this);
394
+		//override to insert default data. It is safe to use the models here
395
+		//because the site should not be in maintenance mode
396
+	}
397
+
398
+
399
+	/**
400
+	 * EE Core detected that this addon has been upgraded. We should check if there
401
+	 * are any new migration scripts, and if so put the site into maintenance mode until
402
+	 * they're ran
403
+	 *
404
+	 * @return void
405
+	 */
406
+	public function upgrade()
407
+	{
408
+		$classname = get_class($this);
409
+		do_action("AHEE__{$classname}__upgrade");
410
+		do_action('AHEE__EE_Addon__upgrade', $this);
411
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
412
+		//also it's possible there is new default data that needs to be added
413
+		add_action(
414
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
415
+			array($this, 'initialize_db_if_no_migrations_required')
416
+		);
417
+	}
418
+
419
+
420
+	/**
421
+	 * If Core detects this addon has been downgraded, you may want to invoke some special logic here.
422
+	 */
423
+	public function downgrade()
424
+	{
425
+		$classname = get_class($this);
426
+		do_action("AHEE__{$classname}__downgrade");
427
+		do_action('AHEE__EE_Addon__downgrade', $this);
428
+		//it's possible there's old default data that needs to be double-checked
429
+		add_action('AHEE__EE_System__perform_activations_upgrades_and_migrations',
430
+			array($this, 'initialize_db_if_no_migrations_required'));
431
+	}
432
+
433
+
434
+	/**
435
+	 * set_db_update_option_name
436
+	 * Until we do something better, we'll just check for migration scripts upon
437
+	 * plugin activation only. In the future, we'll want to do it on plugin updates too
438
+	 *
439
+	 * @return bool
440
+	 */
441
+	public function set_db_update_option_name()
442
+	{
443
+		EE_Error::doing_it_wrong(__FUNCTION__,
444
+			__('EE_Addon::set_db_update_option_name was renamed to EE_Addon::set_activation_indicator_option',
445
+				'event_espresso'), '4.3.0.alpha.016');
446
+		//let's just handle this on the next request, ok? right now we're just not really ready
447
+		return $this->set_activation_indicator_option();
448
+	}
449
+
450
+
451
+	/**
452
+	 * Returns the name of the activation indicator option
453
+	 * (an option which is set temporarily to indicate that this addon was just activated)
454
+	 *
455
+	 * @deprecated since version 4.3.0.alpha.016
456
+	 * @return string
457
+	 */
458
+	public function get_db_update_option_name()
459
+	{
460
+		EE_Error::doing_it_wrong(__FUNCTION__,
461
+			__('EE_Addon::get_db_update_option was renamed to EE_Addon::get_activation_indicator_option_name',
462
+				'event_espresso'), '4.3.0.alpha.016');
463
+		return $this->get_activation_indicator_option_name();
464
+	}
465
+
466
+
467
+	/**
468
+	 * When the addon is activated, this should be called to set a wordpress option that
469
+	 * indicates it was activated. This is especially useful for detecting reactivations.
470
+	 *
471
+	 * @return bool
472
+	 */
473
+	public function set_activation_indicator_option()
474
+	{
475
+		// let's just handle this on the next request, ok? right now we're just not really ready
476
+		return update_option($this->get_activation_indicator_option_name(), true);
477
+	}
478
+
479
+
480
+	/**
481
+	 * Gets the name of the wp option which is used to temporarily indicate that this addon was activated
482
+	 *
483
+	 * @return string
484
+	 */
485
+	public function get_activation_indicator_option_name()
486
+	{
487
+		return 'ee_activation_' . $this->name();
488
+	}
489
+
490
+
491
+	/**
492
+	 * Used by EE_System to set the request type of this addon. Should not be used by addon developers
493
+	 *
494
+	 * @param int $req_type
495
+	 */
496
+	public function set_req_type($req_type)
497
+	{
498
+		$this->_req_type = $req_type;
499
+	}
500
+
501
+
502
+	/**
503
+	 * Returns the request type of this addon (ie, EE_System::req_type_normal, EE_System::req_type_new_activation,
504
+	 * EE_System::req_type_reactivation, EE_System::req_type_upgrade, or EE_System::req_type_downgrade). This is set by
505
+	 * EE_System when it is checking for new install or upgrades of addons
506
+	 */
507
+	public function detect_req_type()
508
+	{
509
+		if (! $this->_req_type) {
510
+			$this->detect_activation_or_upgrade();
511
+		}
512
+		return $this->_req_type;
513
+	}
514
+
515
+
516
+	/**
517
+	 * Detects the request type for this addon (whether it was just activated, upgrades, a normal request, etc.)
518
+	 * Should only be called once per request
519
+	 *
520
+	 * @return void
521
+	 */
522
+	public function detect_activation_or_upgrade()
523
+	{
524
+		$activation_history_for_addon = $this->get_activation_history();
525 525
 //		d($activation_history_for_addon);
526
-        $request_type = EE_System::detect_req_type_given_activation_history($activation_history_for_addon,
527
-            $this->get_activation_indicator_option_name(), $this->version());
528
-        $this->set_req_type($request_type);
529
-        $classname = get_class($this);
530
-        switch ($request_type) {
531
-            case EE_System::req_type_new_activation:
532
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__new_activation");
533
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__new_activation', $this);
534
-                $this->new_install();
535
-                $this->update_list_of_installed_versions($activation_history_for_addon);
536
-                break;
537
-            case EE_System::req_type_reactivation:
538
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__reactivation");
539
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__reactivation', $this);
540
-                $this->reactivation();
541
-                $this->update_list_of_installed_versions($activation_history_for_addon);
542
-                break;
543
-            case EE_System::req_type_upgrade:
544
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__upgrade");
545
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__upgrade', $this);
546
-                $this->upgrade();
547
-                $this->update_list_of_installed_versions($activation_history_for_addon);
548
-                break;
549
-            case EE_System::req_type_downgrade:
550
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__downgrade");
551
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__downgrade', $this);
552
-                $this->downgrade();
553
-                $this->update_list_of_installed_versions($activation_history_for_addon);
554
-                break;
555
-            case EE_System::req_type_normal:
556
-            default:
526
+		$request_type = EE_System::detect_req_type_given_activation_history($activation_history_for_addon,
527
+			$this->get_activation_indicator_option_name(), $this->version());
528
+		$this->set_req_type($request_type);
529
+		$classname = get_class($this);
530
+		switch ($request_type) {
531
+			case EE_System::req_type_new_activation:
532
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__new_activation");
533
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__new_activation', $this);
534
+				$this->new_install();
535
+				$this->update_list_of_installed_versions($activation_history_for_addon);
536
+				break;
537
+			case EE_System::req_type_reactivation:
538
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__reactivation");
539
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__reactivation', $this);
540
+				$this->reactivation();
541
+				$this->update_list_of_installed_versions($activation_history_for_addon);
542
+				break;
543
+			case EE_System::req_type_upgrade:
544
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__upgrade");
545
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__upgrade', $this);
546
+				$this->upgrade();
547
+				$this->update_list_of_installed_versions($activation_history_for_addon);
548
+				break;
549
+			case EE_System::req_type_downgrade:
550
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__downgrade");
551
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__downgrade', $this);
552
+				$this->downgrade();
553
+				$this->update_list_of_installed_versions($activation_history_for_addon);
554
+				break;
555
+			case EE_System::req_type_normal:
556
+			default:
557 557
 //				$this->_maybe_redirect_to_ee_about();
558
-                break;
559
-        }
560
-
561
-        do_action("AHEE__{$classname}__detect_if_activation_or_upgrade__complete");
562
-    }
563
-
564
-    /**
565
-     * Updates the version history for this addon
566
-     *
567
-     * @param array  $version_history
568
-     * @param string $current_version_to_add
569
-     * @return boolean success
570
-     */
571
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
572
-    {
573
-        if (! $version_history) {
574
-            $version_history = $this->get_activation_history();
575
-        }
576
-        if ($current_version_to_add === null) {
577
-            $current_version_to_add = $this->version();
578
-        }
579
-        $version_history[$current_version_to_add][] = date('Y-m-d H:i:s', time());
580
-        // resave
558
+				break;
559
+		}
560
+
561
+		do_action("AHEE__{$classname}__detect_if_activation_or_upgrade__complete");
562
+	}
563
+
564
+	/**
565
+	 * Updates the version history for this addon
566
+	 *
567
+	 * @param array  $version_history
568
+	 * @param string $current_version_to_add
569
+	 * @return boolean success
570
+	 */
571
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
572
+	{
573
+		if (! $version_history) {
574
+			$version_history = $this->get_activation_history();
575
+		}
576
+		if ($current_version_to_add === null) {
577
+			$current_version_to_add = $this->version();
578
+		}
579
+		$version_history[$current_version_to_add][] = date('Y-m-d H:i:s', time());
580
+		// resave
581 581
 //		echo "updating list of installed versions:".$this->get_activation_history_option_name();d($version_history);
582
-        return update_option($this->get_activation_history_option_name(), $version_history);
583
-    }
584
-
585
-    /**
586
-     * Gets the name of the wp option that stores the activation history
587
-     * of this addon
588
-     *
589
-     * @return string
590
-     */
591
-    public function get_activation_history_option_name()
592
-    {
593
-        return self::ee_addon_version_history_option_prefix . $this->name();
594
-    }
595
-
596
-
597
-    /**
598
-     * Gets the wp option which stores the activation history for this addon
599
-     *
600
-     * @return array
601
-     */
602
-    public function get_activation_history()
603
-    {
604
-        return get_option($this->get_activation_history_option_name(), null);
605
-    }
606
-
607
-
608
-    /**
609
-     * @param string $config_section
610
-     */
611
-    public function set_config_section($config_section = '')
612
-    {
613
-        $this->_config_section = ! empty($config_section) ? $config_section : 'addons';
614
-    }
615
-
616
-    /**
617
-     *    filepath to the main file, which can be used for register_activation_hook, register_deactivation_hook, etc.
618
-     *
619
-     * @type string
620
-     */
621
-    protected $_main_plugin_file;
622
-
623
-    /**
624
-     * Sets the filepath to the main plugin file
625
-     *
626
-     * @param string $filepath
627
-     */
628
-    public function set_main_plugin_file($filepath)
629
-    {
630
-        $this->_main_plugin_file = $filepath;
631
-    }
632
-
633
-    /**
634
-     * gets the filepath to teh main file
635
-     *
636
-     * @return string
637
-     */
638
-    public function get_main_plugin_file()
639
-    {
640
-        return $this->_main_plugin_file;
641
-    }
642
-
643
-    /**
644
-     * Gets the filename (no path) of the main file (the main file loaded
645
-     * by WP)
646
-     *
647
-     * @return string
648
-     */
649
-    public function get_main_plugin_file_basename()
650
-    {
651
-        return plugin_basename($this->get_main_plugin_file());
652
-    }
653
-
654
-    /**
655
-     * Gets the folder name which contains the main plugin file
656
-     *
657
-     * @return string
658
-     */
659
-    public function get_main_plugin_file_dirname()
660
-    {
661
-        return dirname($this->get_main_plugin_file());
662
-    }
663
-
664
-
665
-    /**
666
-     * sets hooks used in the admin
667
-     *
668
-     * @return void
669
-     */
670
-    public function admin_init()
671
-    {
672
-        // is admin and not in M-Mode ?
673
-        if (is_admin() && ! EE_Maintenance_Mode::instance()->level()) {
674
-            add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
675
-            add_filter('after_plugin_row_' . $this->_plugin_basename, array($this, 'after_plugin_row'), 10, 3);
676
-        }
677
-    }
678
-
679
-
680
-    /**
681
-     * plugin_actions
682
-     * Add a settings link to the Plugins page, so people can go straight from the plugin page to the settings page.
683
-     *
684
-     * @param $links
685
-     * @param $file
686
-     * @return array
687
-     */
688
-    public function plugin_action_links($links, $file)
689
-    {
690
-        if ($file === $this->plugin_basename() && $this->plugin_action_slug() !== '') {
691
-            // before other links
692
-            array_unshift($links,
693
-                '<a href="admin.php?page=' . $this->plugin_action_slug() . '">' . __('Settings') . '</a>');
694
-        }
695
-        return $links;
696
-    }
697
-
698
-
699
-    /**
700
-     * after_plugin_row
701
-     * Add additional content to the plugins page plugin row
702
-     * Inserts another row
703
-     *
704
-     * @param $plugin_file
705
-     * @param $plugin_data
706
-     * @param $status
707
-     * @return void
708
-     */
709
-    public function after_plugin_row($plugin_file, $plugin_data, $status)
710
-    {
711
-
712
-        $after_plugin_row = '';
713
-        if ($plugin_file === $this->plugin_basename() && $this->get_plugins_page_row() !== '') {
714
-            $class            = $status ? 'active' : 'inactive';
715
-            $plugins_page_row = $this->get_plugins_page_row();
716
-            $link_text        = isset($plugins_page_row['link_text']) ? $plugins_page_row['link_text'] : '';
717
-            $link_url         = isset($plugins_page_row['link_url']) ? $plugins_page_row['link_url'] : '';
718
-            $description      = isset($plugins_page_row['description']) ? $plugins_page_row['description'] : $plugins_page_row;
719
-            if (! empty($link_text) && ! empty($link_url) && ! empty($description)) {
720
-                $after_plugin_row .= '<tr id="' . sanitize_title($plugin_file) . '-ee-addon" class="' . $class . '">';
721
-                $after_plugin_row .= '<th class="check-column" scope="row"></th>';
722
-                $after_plugin_row .= '<td class="ee-addon-upsell-info-title-td plugin-title column-primary">';
723
-                $after_plugin_row .= '<style>
582
+		return update_option($this->get_activation_history_option_name(), $version_history);
583
+	}
584
+
585
+	/**
586
+	 * Gets the name of the wp option that stores the activation history
587
+	 * of this addon
588
+	 *
589
+	 * @return string
590
+	 */
591
+	public function get_activation_history_option_name()
592
+	{
593
+		return self::ee_addon_version_history_option_prefix . $this->name();
594
+	}
595
+
596
+
597
+	/**
598
+	 * Gets the wp option which stores the activation history for this addon
599
+	 *
600
+	 * @return array
601
+	 */
602
+	public function get_activation_history()
603
+	{
604
+		return get_option($this->get_activation_history_option_name(), null);
605
+	}
606
+
607
+
608
+	/**
609
+	 * @param string $config_section
610
+	 */
611
+	public function set_config_section($config_section = '')
612
+	{
613
+		$this->_config_section = ! empty($config_section) ? $config_section : 'addons';
614
+	}
615
+
616
+	/**
617
+	 *    filepath to the main file, which can be used for register_activation_hook, register_deactivation_hook, etc.
618
+	 *
619
+	 * @type string
620
+	 */
621
+	protected $_main_plugin_file;
622
+
623
+	/**
624
+	 * Sets the filepath to the main plugin file
625
+	 *
626
+	 * @param string $filepath
627
+	 */
628
+	public function set_main_plugin_file($filepath)
629
+	{
630
+		$this->_main_plugin_file = $filepath;
631
+	}
632
+
633
+	/**
634
+	 * gets the filepath to teh main file
635
+	 *
636
+	 * @return string
637
+	 */
638
+	public function get_main_plugin_file()
639
+	{
640
+		return $this->_main_plugin_file;
641
+	}
642
+
643
+	/**
644
+	 * Gets the filename (no path) of the main file (the main file loaded
645
+	 * by WP)
646
+	 *
647
+	 * @return string
648
+	 */
649
+	public function get_main_plugin_file_basename()
650
+	{
651
+		return plugin_basename($this->get_main_plugin_file());
652
+	}
653
+
654
+	/**
655
+	 * Gets the folder name which contains the main plugin file
656
+	 *
657
+	 * @return string
658
+	 */
659
+	public function get_main_plugin_file_dirname()
660
+	{
661
+		return dirname($this->get_main_plugin_file());
662
+	}
663
+
664
+
665
+	/**
666
+	 * sets hooks used in the admin
667
+	 *
668
+	 * @return void
669
+	 */
670
+	public function admin_init()
671
+	{
672
+		// is admin and not in M-Mode ?
673
+		if (is_admin() && ! EE_Maintenance_Mode::instance()->level()) {
674
+			add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
675
+			add_filter('after_plugin_row_' . $this->_plugin_basename, array($this, 'after_plugin_row'), 10, 3);
676
+		}
677
+	}
678
+
679
+
680
+	/**
681
+	 * plugin_actions
682
+	 * Add a settings link to the Plugins page, so people can go straight from the plugin page to the settings page.
683
+	 *
684
+	 * @param $links
685
+	 * @param $file
686
+	 * @return array
687
+	 */
688
+	public function plugin_action_links($links, $file)
689
+	{
690
+		if ($file === $this->plugin_basename() && $this->plugin_action_slug() !== '') {
691
+			// before other links
692
+			array_unshift($links,
693
+				'<a href="admin.php?page=' . $this->plugin_action_slug() . '">' . __('Settings') . '</a>');
694
+		}
695
+		return $links;
696
+	}
697
+
698
+
699
+	/**
700
+	 * after_plugin_row
701
+	 * Add additional content to the plugins page plugin row
702
+	 * Inserts another row
703
+	 *
704
+	 * @param $plugin_file
705
+	 * @param $plugin_data
706
+	 * @param $status
707
+	 * @return void
708
+	 */
709
+	public function after_plugin_row($plugin_file, $plugin_data, $status)
710
+	{
711
+
712
+		$after_plugin_row = '';
713
+		if ($plugin_file === $this->plugin_basename() && $this->get_plugins_page_row() !== '') {
714
+			$class            = $status ? 'active' : 'inactive';
715
+			$plugins_page_row = $this->get_plugins_page_row();
716
+			$link_text        = isset($plugins_page_row['link_text']) ? $plugins_page_row['link_text'] : '';
717
+			$link_url         = isset($plugins_page_row['link_url']) ? $plugins_page_row['link_url'] : '';
718
+			$description      = isset($plugins_page_row['description']) ? $plugins_page_row['description'] : $plugins_page_row;
719
+			if (! empty($link_text) && ! empty($link_url) && ! empty($description)) {
720
+				$after_plugin_row .= '<tr id="' . sanitize_title($plugin_file) . '-ee-addon" class="' . $class . '">';
721
+				$after_plugin_row .= '<th class="check-column" scope="row"></th>';
722
+				$after_plugin_row .= '<td class="ee-addon-upsell-info-title-td plugin-title column-primary">';
723
+				$after_plugin_row .= '<style>
724 724
 .ee-button,
725 725
 .ee-button:active,
726 726
 .ee-button:visited {
@@ -757,35 +757,35 @@  discard block
 block discarded – undo
757 757
 }
758 758
 .ee-button:active { top:0; }
759 759
 </style>';
760
-                $after_plugin_row .= '
760
+				$after_plugin_row .= '
761 761
 <p class="ee-addon-upsell-info-dv">
762 762
 	<a class="ee-button" href="' . $link_url . '">' . $link_text . ' &nbsp;<span class="dashicons dashicons-arrow-right-alt2" style="margin:0;"></span></a>
763 763
 </p>';
764
-                $after_plugin_row .= '</td>';
765
-                $after_plugin_row .= '<td class="ee-addon-upsell-info-desc-td column-description desc">';
766
-                $after_plugin_row .= $description;
767
-                $after_plugin_row .= '</td>';
768
-                $after_plugin_row .= '</tr>';
769
-            } else {
770
-                $after_plugin_row .= $description;
771
-            }
772
-        }
773
-
774
-        echo $after_plugin_row;
775
-    }
776
-
777
-
778
-    /**
779
-     * a safe space for addons to add additional logic like setting hooks
780
-     * that will run immediately after addon registration
781
-     * making this a great place for code that needs to be "omnipresent"
782
-     *
783
-     * @since 4.9.26
784
-     */
785
-    public function after_registration()
786
-    {
787
-        // cricket chirp... cricket chirp...
788
-    }
764
+				$after_plugin_row .= '</td>';
765
+				$after_plugin_row .= '<td class="ee-addon-upsell-info-desc-td column-description desc">';
766
+				$after_plugin_row .= $description;
767
+				$after_plugin_row .= '</td>';
768
+				$after_plugin_row .= '</tr>';
769
+			} else {
770
+				$after_plugin_row .= $description;
771
+			}
772
+		}
773
+
774
+		echo $after_plugin_row;
775
+	}
776
+
777
+
778
+	/**
779
+	 * a safe space for addons to add additional logic like setting hooks
780
+	 * that will run immediately after addon registration
781
+	 * making this a great place for code that needs to be "omnipresent"
782
+	 *
783
+	 * @since 4.9.26
784
+	 */
785
+	public function after_registration()
786
+	{
787
+		// cricket chirp... cricket chirp...
788
+	}
789 789
 
790 790
 
791 791
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -1,4 +1,4 @@  discard block
 block discarded – undo
1
-<?php if (! defined('EVENT_ESPRESSO_VERSION')) {
1
+<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2 2
     exit('No direct script access allowed');
3 3
 }
4 4
 /**
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
     public function set_plugins_page_row($plugins_page_row = array())
236 236
     {
237 237
         // sigh.... check for example content that I stupidly merged to master and remove it if found
238
-        if (! is_array($plugins_page_row) && strpos($plugins_page_row,
238
+        if ( ! is_array($plugins_page_row) && strpos($plugins_page_row,
239 239
                 '<h3>Promotions Addon Upsell Info</h3>') !== false) {
240 240
             $plugins_page_row = '';
241 241
         }
@@ -484,7 +484,7 @@  discard block
 block discarded – undo
484 484
      */
485 485
     public function get_activation_indicator_option_name()
486 486
     {
487
-        return 'ee_activation_' . $this->name();
487
+        return 'ee_activation_'.$this->name();
488 488
     }
489 489
 
490 490
 
@@ -506,7 +506,7 @@  discard block
 block discarded – undo
506 506
      */
507 507
     public function detect_req_type()
508 508
     {
509
-        if (! $this->_req_type) {
509
+        if ( ! $this->_req_type) {
510 510
             $this->detect_activation_or_upgrade();
511 511
         }
512 512
         return $this->_req_type;
@@ -570,7 +570,7 @@  discard block
 block discarded – undo
570 570
      */
571 571
     public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
572 572
     {
573
-        if (! $version_history) {
573
+        if ( ! $version_history) {
574 574
             $version_history = $this->get_activation_history();
575 575
         }
576 576
         if ($current_version_to_add === null) {
@@ -590,7 +590,7 @@  discard block
 block discarded – undo
590 590
      */
591 591
     public function get_activation_history_option_name()
592 592
     {
593
-        return self::ee_addon_version_history_option_prefix . $this->name();
593
+        return self::ee_addon_version_history_option_prefix.$this->name();
594 594
     }
595 595
 
596 596
 
@@ -672,7 +672,7 @@  discard block
 block discarded – undo
672 672
         // is admin and not in M-Mode ?
673 673
         if (is_admin() && ! EE_Maintenance_Mode::instance()->level()) {
674 674
             add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
675
-            add_filter('after_plugin_row_' . $this->_plugin_basename, array($this, 'after_plugin_row'), 10, 3);
675
+            add_filter('after_plugin_row_'.$this->_plugin_basename, array($this, 'after_plugin_row'), 10, 3);
676 676
         }
677 677
     }
678 678
 
@@ -690,7 +690,7 @@  discard block
 block discarded – undo
690 690
         if ($file === $this->plugin_basename() && $this->plugin_action_slug() !== '') {
691 691
             // before other links
692 692
             array_unshift($links,
693
-                '<a href="admin.php?page=' . $this->plugin_action_slug() . '">' . __('Settings') . '</a>');
693
+                '<a href="admin.php?page='.$this->plugin_action_slug().'">'.__('Settings').'</a>');
694 694
         }
695 695
         return $links;
696 696
     }
@@ -716,8 +716,8 @@  discard block
 block discarded – undo
716 716
             $link_text        = isset($plugins_page_row['link_text']) ? $plugins_page_row['link_text'] : '';
717 717
             $link_url         = isset($plugins_page_row['link_url']) ? $plugins_page_row['link_url'] : '';
718 718
             $description      = isset($plugins_page_row['description']) ? $plugins_page_row['description'] : $plugins_page_row;
719
-            if (! empty($link_text) && ! empty($link_url) && ! empty($description)) {
720
-                $after_plugin_row .= '<tr id="' . sanitize_title($plugin_file) . '-ee-addon" class="' . $class . '">';
719
+            if ( ! empty($link_text) && ! empty($link_url) && ! empty($description)) {
720
+                $after_plugin_row .= '<tr id="'.sanitize_title($plugin_file).'-ee-addon" class="'.$class.'">';
721 721
                 $after_plugin_row .= '<th class="check-column" scope="row"></th>';
722 722
                 $after_plugin_row .= '<td class="ee-addon-upsell-info-title-td plugin-title column-primary">';
723 723
                 $after_plugin_row .= '<style>
@@ -759,7 +759,7 @@  discard block
 block discarded – undo
759 759
 </style>';
760 760
                 $after_plugin_row .= '
761 761
 <p class="ee-addon-upsell-info-dv">
762
-	<a class="ee-button" href="' . $link_url . '">' . $link_text . ' &nbsp;<span class="dashicons dashicons-arrow-right-alt2" style="margin:0;"></span></a>
762
+	<a class="ee-button" href="' . $link_url.'">'.$link_text.' &nbsp;<span class="dashicons dashicons-arrow-right-alt2" style="margin:0;"></span></a>
763 763
 </p>';
764 764
                 $after_plugin_row .= '</td>';
765 765
                 $after_plugin_row .= '<td class="ee-addon-upsell-info-desc-td column-description desc">';
Please login to merge, or discard this patch.
espresso.php 2 patches
Indentation   +192 added lines, -192 removed lines patch added patch discarded remove patch
@@ -38,217 +38,217 @@
 block discarded – undo
38 38
  * @since       4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 
64 64
 } else {
65
-    define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
-        /**
68
-         * espresso_minimum_php_version_error
69
-         *
70
-         * @return void
71
-         */
72
-        function espresso_minimum_php_version_error()
73
-        {
74
-            ?>
65
+	define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
+		/**
68
+		 * espresso_minimum_php_version_error
69
+		 *
70
+		 * @return void
71
+		 */
72
+		function espresso_minimum_php_version_error()
73
+		{
74
+			?>
75 75
             <div class="error">
76 76
                 <p>
77 77
                     <?php
78
-                    printf(
79
-                        esc_html__(
80
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
81
-                            'event_espresso'
82
-                        ),
83
-                        EE_MIN_PHP_VER_REQUIRED,
84
-                        PHP_VERSION,
85
-                        '<br/>',
86
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
87
-                    );
88
-                    ?>
78
+					printf(
79
+						esc_html__(
80
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
81
+							'event_espresso'
82
+						),
83
+						EE_MIN_PHP_VER_REQUIRED,
84
+						PHP_VERSION,
85
+						'<br/>',
86
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
87
+					);
88
+					?>
89 89
                 </p>
90 90
             </div>
91 91
             <?php
92
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
93
-        }
92
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
93
+		}
94 94
 
95
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
96
-    } else {
97
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
98
-        /**
99
-         * espresso_version
100
-         * Returns the plugin version
101
-         *
102
-         * @return string
103
-         */
104
-        function espresso_version()
105
-        {
106
-            return apply_filters('FHEE__espresso__espresso_version', '4.9.46.rc.073');
107
-        }
95
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
96
+	} else {
97
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
98
+		/**
99
+		 * espresso_version
100
+		 * Returns the plugin version
101
+		 *
102
+		 * @return string
103
+		 */
104
+		function espresso_version()
105
+		{
106
+			return apply_filters('FHEE__espresso__espresso_version', '4.9.46.rc.073');
107
+		}
108 108
 
109
-        /**
110
-         * espresso_plugin_activation
111
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
112
-         */
113
-        function espresso_plugin_activation()
114
-        {
115
-            update_option('ee_espresso_activation', true);
116
-        }
109
+		/**
110
+		 * espresso_plugin_activation
111
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
112
+		 */
113
+		function espresso_plugin_activation()
114
+		{
115
+			update_option('ee_espresso_activation', true);
116
+		}
117 117
 
118
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
119
-        /**
120
-         *    espresso_load_error_handling
121
-         *    this function loads EE's class for handling exceptions and errors
122
-         */
123
-        function espresso_load_error_handling()
124
-        {
125
-            static $error_handling_loaded = false;
126
-            if ($error_handling_loaded) {
127
-                return;
128
-            }
129
-            // load debugging tools
130
-            if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
131
-                require_once   EE_HELPERS . 'EEH_Debug_Tools.helper.php';
132
-                \EEH_Debug_Tools::instance();
133
-            }
134
-            // load error handling
135
-            if (is_readable(EE_CORE . 'EE_Error.core.php')) {
136
-                require_once EE_CORE . 'EE_Error.core.php';
137
-            } else {
138
-                wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
139
-            }
140
-            $error_handling_loaded = true;
141
-        }
118
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
119
+		/**
120
+		 *    espresso_load_error_handling
121
+		 *    this function loads EE's class for handling exceptions and errors
122
+		 */
123
+		function espresso_load_error_handling()
124
+		{
125
+			static $error_handling_loaded = false;
126
+			if ($error_handling_loaded) {
127
+				return;
128
+			}
129
+			// load debugging tools
130
+			if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
131
+				require_once   EE_HELPERS . 'EEH_Debug_Tools.helper.php';
132
+				\EEH_Debug_Tools::instance();
133
+			}
134
+			// load error handling
135
+			if (is_readable(EE_CORE . 'EE_Error.core.php')) {
136
+				require_once EE_CORE . 'EE_Error.core.php';
137
+			} else {
138
+				wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
139
+			}
140
+			$error_handling_loaded = true;
141
+		}
142 142
 
143
-        /**
144
-         *    espresso_load_required
145
-         *    given a class name and path, this function will load that file or throw an exception
146
-         *
147
-         * @param    string $classname
148
-         * @param    string $full_path_to_file
149
-         * @throws    EE_Error
150
-         */
151
-        function espresso_load_required($classname, $full_path_to_file)
152
-        {
153
-            if (is_readable($full_path_to_file)) {
154
-                require_once $full_path_to_file;
155
-            } else {
156
-                throw new \EE_Error (
157
-                    sprintf(
158
-                        esc_html__(
159
-                            'The %s class file could not be located or is not readable due to file permissions.',
160
-                            'event_espresso'
161
-                        ),
162
-                        $classname
163
-                    )
164
-                );
165
-            }
166
-        }
143
+		/**
144
+		 *    espresso_load_required
145
+		 *    given a class name and path, this function will load that file or throw an exception
146
+		 *
147
+		 * @param    string $classname
148
+		 * @param    string $full_path_to_file
149
+		 * @throws    EE_Error
150
+		 */
151
+		function espresso_load_required($classname, $full_path_to_file)
152
+		{
153
+			if (is_readable($full_path_to_file)) {
154
+				require_once $full_path_to_file;
155
+			} else {
156
+				throw new \EE_Error (
157
+					sprintf(
158
+						esc_html__(
159
+							'The %s class file could not be located or is not readable due to file permissions.',
160
+							'event_espresso'
161
+						),
162
+						$classname
163
+					)
164
+				);
165
+			}
166
+		}
167 167
 
168
-        /**
169
-         * @since 4.9.27
170
-         * @throws \EE_Error
171
-         * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
172
-         * @throws \EventEspresso\core\exceptions\InvalidEntityException
173
-         * @throws \EventEspresso\core\exceptions\InvalidIdentifierException
174
-         * @throws \EventEspresso\core\exceptions\InvalidClassException
175
-         * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
176
-         * @throws \EventEspresso\core\services\container\exceptions\ServiceExistsException
177
-         * @throws \EventEspresso\core\services\container\exceptions\ServiceNotFoundException
178
-         * @throws \OutOfBoundsException
179
-         */
180
-        function bootstrap_espresso()
181
-        {
182
-            require_once __DIR__ . '/core/espresso_definitions.php';
183
-            try {
184
-                espresso_load_error_handling();
185
-                espresso_load_required(
186
-                    'EEH_Base',
187
-                    EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
188
-                );
189
-                espresso_load_required(
190
-                    'EEH_File',
191
-                    EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
192
-                );
193
-                espresso_load_required(
194
-                    'EEH_File',
195
-                    EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
196
-                );
197
-                espresso_load_required(
198
-                    'EEH_Array',
199
-                    EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
200
-                );
201
-                // instantiate and configure PSR4 autoloader
202
-                espresso_load_required(
203
-                    'Psr4Autoloader',
204
-                    EE_CORE . 'Psr4Autoloader.php'
205
-                );
206
-                espresso_load_required(
207
-                    'EE_Psr4AutoloaderInit',
208
-                    EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
209
-                );
210
-                $AutoloaderInit = new EE_Psr4AutoloaderInit();
211
-                $AutoloaderInit->initializeAutoloader();
212
-                espresso_load_required(
213
-                    'EE_Request',
214
-                    EE_CORE . 'request_stack' . DS . 'EE_Request.core.php'
215
-                );
216
-                espresso_load_required(
217
-                    'EE_Response',
218
-                    EE_CORE . 'request_stack' . DS . 'EE_Response.core.php'
219
-                );
220
-                espresso_load_required(
221
-                    'EE_Bootstrap',
222
-                    EE_CORE . 'EE_Bootstrap.core.php'
223
-                );
224
-                // bootstrap EE and the request stack
225
-                new EE_Bootstrap(
226
-                    new EE_Request($_GET, $_POST, $_COOKIE),
227
-                    new EE_Response()
228
-                );
229
-            } catch (Exception $e) {
230
-                require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
231
-                new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
232
-            }
233
-        }
234
-        bootstrap_espresso();
235
-    }
168
+		/**
169
+		 * @since 4.9.27
170
+		 * @throws \EE_Error
171
+		 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
172
+		 * @throws \EventEspresso\core\exceptions\InvalidEntityException
173
+		 * @throws \EventEspresso\core\exceptions\InvalidIdentifierException
174
+		 * @throws \EventEspresso\core\exceptions\InvalidClassException
175
+		 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
176
+		 * @throws \EventEspresso\core\services\container\exceptions\ServiceExistsException
177
+		 * @throws \EventEspresso\core\services\container\exceptions\ServiceNotFoundException
178
+		 * @throws \OutOfBoundsException
179
+		 */
180
+		function bootstrap_espresso()
181
+		{
182
+			require_once __DIR__ . '/core/espresso_definitions.php';
183
+			try {
184
+				espresso_load_error_handling();
185
+				espresso_load_required(
186
+					'EEH_Base',
187
+					EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
188
+				);
189
+				espresso_load_required(
190
+					'EEH_File',
191
+					EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
192
+				);
193
+				espresso_load_required(
194
+					'EEH_File',
195
+					EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
196
+				);
197
+				espresso_load_required(
198
+					'EEH_Array',
199
+					EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
200
+				);
201
+				// instantiate and configure PSR4 autoloader
202
+				espresso_load_required(
203
+					'Psr4Autoloader',
204
+					EE_CORE . 'Psr4Autoloader.php'
205
+				);
206
+				espresso_load_required(
207
+					'EE_Psr4AutoloaderInit',
208
+					EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
209
+				);
210
+				$AutoloaderInit = new EE_Psr4AutoloaderInit();
211
+				$AutoloaderInit->initializeAutoloader();
212
+				espresso_load_required(
213
+					'EE_Request',
214
+					EE_CORE . 'request_stack' . DS . 'EE_Request.core.php'
215
+				);
216
+				espresso_load_required(
217
+					'EE_Response',
218
+					EE_CORE . 'request_stack' . DS . 'EE_Response.core.php'
219
+				);
220
+				espresso_load_required(
221
+					'EE_Bootstrap',
222
+					EE_CORE . 'EE_Bootstrap.core.php'
223
+				);
224
+				// bootstrap EE and the request stack
225
+				new EE_Bootstrap(
226
+					new EE_Request($_GET, $_POST, $_COOKIE),
227
+					new EE_Response()
228
+				);
229
+			} catch (Exception $e) {
230
+				require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
231
+				new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
232
+			}
233
+		}
234
+		bootstrap_espresso();
235
+	}
236 236
 }
237 237
 if (! function_exists('espresso_deactivate_plugin')) {
238
-    /**
239
-     *    deactivate_plugin
240
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
241
-     *
242
-     * @access public
243
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
244
-     * @return    void
245
-     */
246
-    function espresso_deactivate_plugin($plugin_basename = '')
247
-    {
248
-        if (! function_exists('deactivate_plugins')) {
249
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
250
-        }
251
-        unset($_GET['activate'], $_REQUEST['activate']);
252
-        deactivate_plugins($plugin_basename);
253
-    }
238
+	/**
239
+	 *    deactivate_plugin
240
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
241
+	 *
242
+	 * @access public
243
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
244
+	 * @return    void
245
+	 */
246
+	function espresso_deactivate_plugin($plugin_basename = '')
247
+	{
248
+		if (! function_exists('deactivate_plugins')) {
249
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
250
+		}
251
+		unset($_GET['activate'], $_REQUEST['activate']);
252
+		deactivate_plugins($plugin_basename);
253
+	}
254 254
 }
Please login to merge, or discard this patch.
Spacing   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -38,7 +38,7 @@  discard block
 block discarded – undo
38 38
  * @since       4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
41
+    if ( ! function_exists('espresso_duplicate_plugin_error')) {
42 42
         /**
43 43
          *    espresso_duplicate_plugin_error
44 44
          *    displays if more than one version of EE is activated at the same time
@@ -63,7 +63,7 @@  discard block
 block discarded – undo
63 63
 
64 64
 } else {
65 65
     define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
+    if ( ! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67 67
         /**
68 68
          * espresso_minimum_php_version_error
69 69
          *
@@ -127,13 +127,13 @@  discard block
 block discarded – undo
127 127
                 return;
128 128
             }
129 129
             // load debugging tools
130
-            if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
131
-                require_once   EE_HELPERS . 'EEH_Debug_Tools.helper.php';
130
+            if (WP_DEBUG === true && is_readable(EE_HELPERS.'EEH_Debug_Tools.helper.php')) {
131
+                require_once   EE_HELPERS.'EEH_Debug_Tools.helper.php';
132 132
                 \EEH_Debug_Tools::instance();
133 133
             }
134 134
             // load error handling
135
-            if (is_readable(EE_CORE . 'EE_Error.core.php')) {
136
-                require_once EE_CORE . 'EE_Error.core.php';
135
+            if (is_readable(EE_CORE.'EE_Error.core.php')) {
136
+                require_once EE_CORE.'EE_Error.core.php';
137 137
             } else {
138 138
                 wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
139 139
             }
@@ -153,7 +153,7 @@  discard block
 block discarded – undo
153 153
             if (is_readable($full_path_to_file)) {
154 154
                 require_once $full_path_to_file;
155 155
             } else {
156
-                throw new \EE_Error (
156
+                throw new \EE_Error(
157 157
                     sprintf(
158 158
                         esc_html__(
159 159
                             'The %s class file could not be located or is not readable due to file permissions.',
@@ -179,47 +179,47 @@  discard block
 block discarded – undo
179 179
          */
180 180
         function bootstrap_espresso()
181 181
         {
182
-            require_once __DIR__ . '/core/espresso_definitions.php';
182
+            require_once __DIR__.'/core/espresso_definitions.php';
183 183
             try {
184 184
                 espresso_load_error_handling();
185 185
                 espresso_load_required(
186 186
                     'EEH_Base',
187
-                    EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
187
+                    EE_CORE.'helpers'.DS.'EEH_Base.helper.php'
188 188
                 );
189 189
                 espresso_load_required(
190 190
                     'EEH_File',
191
-                    EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
191
+                    EE_CORE.'interfaces'.DS.'EEHI_File.interface.php'
192 192
                 );
193 193
                 espresso_load_required(
194 194
                     'EEH_File',
195
-                    EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
195
+                    EE_CORE.'helpers'.DS.'EEH_File.helper.php'
196 196
                 );
197 197
                 espresso_load_required(
198 198
                     'EEH_Array',
199
-                    EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
199
+                    EE_CORE.'helpers'.DS.'EEH_Array.helper.php'
200 200
                 );
201 201
                 // instantiate and configure PSR4 autoloader
202 202
                 espresso_load_required(
203 203
                     'Psr4Autoloader',
204
-                    EE_CORE . 'Psr4Autoloader.php'
204
+                    EE_CORE.'Psr4Autoloader.php'
205 205
                 );
206 206
                 espresso_load_required(
207 207
                     'EE_Psr4AutoloaderInit',
208
-                    EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
208
+                    EE_CORE.'EE_Psr4AutoloaderInit.core.php'
209 209
                 );
210 210
                 $AutoloaderInit = new EE_Psr4AutoloaderInit();
211 211
                 $AutoloaderInit->initializeAutoloader();
212 212
                 espresso_load_required(
213 213
                     'EE_Request',
214
-                    EE_CORE . 'request_stack' . DS . 'EE_Request.core.php'
214
+                    EE_CORE.'request_stack'.DS.'EE_Request.core.php'
215 215
                 );
216 216
                 espresso_load_required(
217 217
                     'EE_Response',
218
-                    EE_CORE . 'request_stack' . DS . 'EE_Response.core.php'
218
+                    EE_CORE.'request_stack'.DS.'EE_Response.core.php'
219 219
                 );
220 220
                 espresso_load_required(
221 221
                     'EE_Bootstrap',
222
-                    EE_CORE . 'EE_Bootstrap.core.php'
222
+                    EE_CORE.'EE_Bootstrap.core.php'
223 223
                 );
224 224
                 // bootstrap EE and the request stack
225 225
                 new EE_Bootstrap(
@@ -227,14 +227,14 @@  discard block
 block discarded – undo
227 227
                     new EE_Response()
228 228
                 );
229 229
             } catch (Exception $e) {
230
-                require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
230
+                require_once EE_CORE.'exceptions'.DS.'ExceptionStackTraceDisplay.php';
231 231
                 new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
232 232
             }
233 233
         }
234 234
         bootstrap_espresso();
235 235
     }
236 236
 }
237
-if (! function_exists('espresso_deactivate_plugin')) {
237
+if ( ! function_exists('espresso_deactivate_plugin')) {
238 238
     /**
239 239
      *    deactivate_plugin
240 240
      * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
@@ -245,8 +245,8 @@  discard block
 block discarded – undo
245 245
      */
246 246
     function espresso_deactivate_plugin($plugin_basename = '')
247 247
     {
248
-        if (! function_exists('deactivate_plugins')) {
249
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
248
+        if ( ! function_exists('deactivate_plugins')) {
249
+            require_once ABSPATH.'wp-admin/includes/plugin.php';
250 250
         }
251 251
         unset($_GET['activate'], $_REQUEST['activate']);
252 252
         deactivate_plugins($plugin_basename);
Please login to merge, or discard this patch.
core/espresso_definitions.php 2 patches
Indentation   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -7,16 +7,16 @@  discard block
 block discarded – undo
7 7
 define('EE_SUPPORT_EMAIL', '[email protected]');
8 8
 //used to be DIRECTORY_SEPARATOR, but that caused issues on windows
9 9
 if ( ! defined('DS')) {
10
-    define('DS', '/');
10
+	define('DS', '/');
11 11
 }
12 12
 if ( ! defined('PS')) {
13
-    define('PS', PATH_SEPARATOR);
13
+	define('PS', PATH_SEPARATOR);
14 14
 }
15 15
 if ( ! defined('SP')) {
16
-    define('SP', ' ');
16
+	define('SP', ' ');
17 17
 }
18 18
 if ( ! defined('EENL')) {
19
-    define('EENL', "\n");
19
+	define('EENL', "\n");
20 20
 }
21 21
 // define the plugin directory and URL
22 22
 define('EE_PLUGIN_BASENAME', plugin_basename(EVENT_ESPRESSO_MAIN_FILE));
@@ -70,16 +70,16 @@  discard block
 block discarded – undo
70 70
 define('EE_LANGUAGES_SAFE_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'languages' . DS);
71 71
 //check for DOMPDF fonts in uploads
72 72
 if (file_exists(EVENT_ESPRESSO_UPLOAD_DIR . 'fonts' . DS)) {
73
-    define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'fonts' . DS);
73
+	define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'fonts' . DS);
74 74
 }
75 75
 //ajax constants
76 76
 define(
77
-    'EE_FRONT_AJAX',
78
-    isset($_REQUEST['ee_front_ajax']) || isset($_REQUEST['data']['ee_front_ajax'])
77
+	'EE_FRONT_AJAX',
78
+	isset($_REQUEST['ee_front_ajax']) || isset($_REQUEST['data']['ee_front_ajax'])
79 79
 );
80 80
 define(
81
-    'EE_ADMIN_AJAX',
82
-    isset($_REQUEST['ee_admin_ajax']) || isset($_REQUEST['data']['ee_admin_ajax'])
81
+	'EE_ADMIN_AJAX',
82
+	isset($_REQUEST['ee_admin_ajax']) || isset($_REQUEST['data']['ee_admin_ajax'])
83 83
 );
84 84
 //just a handy constant occasionally needed for finding values representing infinity in the DB
85 85
 //you're better to use this than its straight value (currently -1) in case you ever
@@ -89,7 +89,7 @@  discard block
 block discarded – undo
89 89
 define('EE_DEBUG', false);
90 90
 // for older WP versions
91 91
 if ( ! defined('MONTH_IN_SECONDS')) {
92
-    define('MONTH_IN_SECONDS', DAY_IN_SECONDS * 30);
92
+	define('MONTH_IN_SECONDS', DAY_IN_SECONDS * 30);
93 93
 }
94 94
 
95 95
 // End of file espresso_definitions.php
Please login to merge, or discard this patch.
Spacing   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -20,57 +20,57 @@  discard block
 block discarded – undo
20 20
 }
21 21
 // define the plugin directory and URL
22 22
 define('EE_PLUGIN_BASENAME', plugin_basename(EVENT_ESPRESSO_MAIN_FILE));
23
-define('EE_PLUGIN_DIR_PATH', dirname(EVENT_ESPRESSO_MAIN_FILE) . DS);
23
+define('EE_PLUGIN_DIR_PATH', dirname(EVENT_ESPRESSO_MAIN_FILE).DS);
24 24
 define('EE_PLUGIN_DIR_URL', plugin_dir_url(EVENT_ESPRESSO_MAIN_FILE));
25 25
 // main root folder paths
26
-define('EE_ADMIN_PAGES', EE_PLUGIN_DIR_PATH . 'admin_pages' . DS);
27
-define('EE_CORE', EE_PLUGIN_DIR_PATH . 'core' . DS);
28
-define('EE_MODULES', EE_PLUGIN_DIR_PATH . 'modules' . DS);
29
-define('EE_PUBLIC', EE_PLUGIN_DIR_PATH . 'public' . DS);
30
-define('EE_SHORTCODES', EE_PLUGIN_DIR_PATH . 'shortcodes' . DS);
31
-define('EE_WIDGETS', EE_PLUGIN_DIR_PATH . 'widgets' . DS);
32
-define('EE_PAYMENT_METHODS', EE_PLUGIN_DIR_PATH . 'payment_methods' . DS);
33
-define('EE_CAFF_PATH', EE_PLUGIN_DIR_PATH . 'caffeinated' . DS);
26
+define('EE_ADMIN_PAGES', EE_PLUGIN_DIR_PATH.'admin_pages'.DS);
27
+define('EE_CORE', EE_PLUGIN_DIR_PATH.'core'.DS);
28
+define('EE_MODULES', EE_PLUGIN_DIR_PATH.'modules'.DS);
29
+define('EE_PUBLIC', EE_PLUGIN_DIR_PATH.'public'.DS);
30
+define('EE_SHORTCODES', EE_PLUGIN_DIR_PATH.'shortcodes'.DS);
31
+define('EE_WIDGETS', EE_PLUGIN_DIR_PATH.'widgets'.DS);
32
+define('EE_PAYMENT_METHODS', EE_PLUGIN_DIR_PATH.'payment_methods'.DS);
33
+define('EE_CAFF_PATH', EE_PLUGIN_DIR_PATH.'caffeinated'.DS);
34 34
 // core system paths
35
-define('EE_ADMIN', EE_CORE . 'admin' . DS);
36
-define('EE_CPTS', EE_CORE . 'CPTs' . DS);
37
-define('EE_CLASSES', EE_CORE . 'db_classes' . DS);
38
-define('EE_INTERFACES', EE_CORE . 'interfaces' . DS);
39
-define('EE_BUSINESS', EE_CORE . 'business' . DS);
40
-define('EE_MODELS', EE_CORE . 'db_models' . DS);
41
-define('EE_HELPERS', EE_CORE . 'helpers' . DS);
42
-define('EE_LIBRARIES', EE_CORE . 'libraries' . DS);
43
-define('EE_TEMPLATES', EE_CORE . 'templates' . DS);
44
-define('EE_THIRD_PARTY', EE_CORE . 'third_party_libs' . DS);
45
-define('EE_GLOBAL_ASSETS', EE_TEMPLATES . 'global_assets' . DS);
46
-define('EE_FORM_SECTIONS', EE_LIBRARIES . 'form_sections' . DS);
35
+define('EE_ADMIN', EE_CORE.'admin'.DS);
36
+define('EE_CPTS', EE_CORE.'CPTs'.DS);
37
+define('EE_CLASSES', EE_CORE.'db_classes'.DS);
38
+define('EE_INTERFACES', EE_CORE.'interfaces'.DS);
39
+define('EE_BUSINESS', EE_CORE.'business'.DS);
40
+define('EE_MODELS', EE_CORE.'db_models'.DS);
41
+define('EE_HELPERS', EE_CORE.'helpers'.DS);
42
+define('EE_LIBRARIES', EE_CORE.'libraries'.DS);
43
+define('EE_TEMPLATES', EE_CORE.'templates'.DS);
44
+define('EE_THIRD_PARTY', EE_CORE.'third_party_libs'.DS);
45
+define('EE_GLOBAL_ASSETS', EE_TEMPLATES.'global_assets'.DS);
46
+define('EE_FORM_SECTIONS', EE_LIBRARIES.'form_sections'.DS);
47 47
 // gateways
48
-define('EE_GATEWAYS', EE_MODULES . 'gateways' . DS);
49
-define('EE_GATEWAYS_URL', EE_PLUGIN_DIR_URL . 'modules' . DS . 'gateways' . DS);
48
+define('EE_GATEWAYS', EE_MODULES.'gateways'.DS);
49
+define('EE_GATEWAYS_URL', EE_PLUGIN_DIR_URL.'modules'.DS.'gateways'.DS);
50 50
 // asset URL paths
51
-define('EE_TEMPLATES_URL', EE_PLUGIN_DIR_URL . 'core' . DS . 'templates' . DS);
52
-define('EE_GLOBAL_ASSETS_URL', EE_TEMPLATES_URL . 'global_assets' . DS);
53
-define('EE_IMAGES_URL', EE_GLOBAL_ASSETS_URL . 'images' . DS);
54
-define('EE_THIRD_PARTY_URL', EE_PLUGIN_DIR_URL . 'core' . DS . 'third_party_libs' . DS);
55
-define('EE_HELPERS_ASSETS', EE_PLUGIN_DIR_URL . 'core/helpers/assets/');
56
-define('EE_LIBRARIES_URL', EE_PLUGIN_DIR_URL . 'core/libraries/');
51
+define('EE_TEMPLATES_URL', EE_PLUGIN_DIR_URL.'core'.DS.'templates'.DS);
52
+define('EE_GLOBAL_ASSETS_URL', EE_TEMPLATES_URL.'global_assets'.DS);
53
+define('EE_IMAGES_URL', EE_GLOBAL_ASSETS_URL.'images'.DS);
54
+define('EE_THIRD_PARTY_URL', EE_PLUGIN_DIR_URL.'core'.DS.'third_party_libs'.DS);
55
+define('EE_HELPERS_ASSETS', EE_PLUGIN_DIR_URL.'core/helpers/assets/');
56
+define('EE_LIBRARIES_URL', EE_PLUGIN_DIR_URL.'core/libraries/');
57 57
 // define upload paths
58 58
 $uploads = wp_upload_dir();
59 59
 // define the uploads directory and URL
60
-define('EVENT_ESPRESSO_UPLOAD_DIR', $uploads['basedir'] . DS . 'espresso' . DS);
61
-define('EVENT_ESPRESSO_UPLOAD_URL', $uploads['baseurl'] . DS . 'espresso' . DS);
60
+define('EVENT_ESPRESSO_UPLOAD_DIR', $uploads['basedir'].DS.'espresso'.DS);
61
+define('EVENT_ESPRESSO_UPLOAD_URL', $uploads['baseurl'].DS.'espresso'.DS);
62 62
 // define the templates directory and URL
63
-define('EVENT_ESPRESSO_TEMPLATE_DIR', $uploads['basedir'] . DS . 'espresso' . DS . 'templates' . DS);
64
-define('EVENT_ESPRESSO_TEMPLATE_URL', $uploads['baseurl'] . DS . 'espresso' . DS . 'templates' . DS);
63
+define('EVENT_ESPRESSO_TEMPLATE_DIR', $uploads['basedir'].DS.'espresso'.DS.'templates'.DS);
64
+define('EVENT_ESPRESSO_TEMPLATE_URL', $uploads['baseurl'].DS.'espresso'.DS.'templates'.DS);
65 65
 // define the gateway directory and URL
66
-define('EVENT_ESPRESSO_GATEWAY_DIR', $uploads['basedir'] . DS . 'espresso' . DS . 'gateways' . DS);
67
-define('EVENT_ESPRESSO_GATEWAY_URL', $uploads['baseurl'] . DS . 'espresso' . DS . 'gateways' . DS);
66
+define('EVENT_ESPRESSO_GATEWAY_DIR', $uploads['basedir'].DS.'espresso'.DS.'gateways'.DS);
67
+define('EVENT_ESPRESSO_GATEWAY_URL', $uploads['baseurl'].DS.'espresso'.DS.'gateways'.DS);
68 68
 // languages folder/path
69
-define('EE_LANGUAGES_SAFE_LOC', '..' . DS . 'uploads' . DS . 'espresso' . DS . 'languages' . DS);
70
-define('EE_LANGUAGES_SAFE_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'languages' . DS);
69
+define('EE_LANGUAGES_SAFE_LOC', '..'.DS.'uploads'.DS.'espresso'.DS.'languages'.DS);
70
+define('EE_LANGUAGES_SAFE_DIR', EVENT_ESPRESSO_UPLOAD_DIR.'languages'.DS);
71 71
 //check for DOMPDF fonts in uploads
72
-if (file_exists(EVENT_ESPRESSO_UPLOAD_DIR . 'fonts' . DS)) {
73
-    define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'fonts' . DS);
72
+if (file_exists(EVENT_ESPRESSO_UPLOAD_DIR.'fonts'.DS)) {
73
+    define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR.'fonts'.DS);
74 74
 }
75 75
 //ajax constants
76 76
 define(
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
 //you're better to use this than its straight value (currently -1) in case you ever
86 86
 //want to change its default value! or find when -1 means infinity
87 87
 define('EE_INF_IN_DB', -1);
88
-define('EE_INF', INF > (float)PHP_INT_MAX ? INF : PHP_INT_MAX);
88
+define('EE_INF', INF > (float) PHP_INT_MAX ? INF : PHP_INT_MAX);
89 89
 define('EE_DEBUG', false);
90 90
 // for older WP versions
91 91
 if ( ! defined('MONTH_IN_SECONDS')) {
Please login to merge, or discard this patch.