Completed
Branch FET/11011/recurring-events-man... (00e770)
by
unknown
63:13 queued 46:54
created
core/libraries/messages/EE_Messages_Queue.lib.php 2 patches
Indentation   +689 added lines, -689 removed lines patch added patch discarded remove patch
@@ -2,7 +2,7 @@  discard block
 block discarded – undo
2 2
 use \EventEspresso\core\exceptions\SendMessageException;
3 3
 
4 4
 if (! defined('EVENT_ESPRESSO_VERSION')) {
5
-    exit('No direct script access allowed');
5
+	exit('No direct script access allowed');
6 6
 }
7 7
 
8 8
 /**
@@ -18,693 +18,693 @@  discard block
 block discarded – undo
18 18
 {
19 19
 
20 20
 
21
-    /**
22
-     * @type    string  reference for sending action
23
-     */
24
-    const action_sending = 'sending';
25
-
26
-    /**
27
-     * @type    string  reference for generation action
28
-     */
29
-    const action_generating = 'generation';
30
-
31
-
32
-    /**
33
-     * @type EE_Message_Repository $_message_repository
34
-     */
35
-    protected $_message_repository;
36
-
37
-    /**
38
-     * Sets the limit of how many messages are generated per process.
39
-     *
40
-     * @type int
41
-     */
42
-    protected $_batch_count;
43
-
44
-
45
-    /**
46
-     * This is an array of cached queue items being stored in this object.
47
-     * The array keys will be the ID of the EE_Message in the db if saved.  If the EE_Message
48
-     * is not saved to the db then its key will be an increment of "UNS" (i.e. UNS1, UNS2 etc.)
49
-     *
50
-     * @type EE_Message[]
51
-     */
52
-    protected $_cached_queue_items;
53
-
54
-    /**
55
-     * Tracks the number of unsaved queue items.
56
-     *
57
-     * @type int
58
-     */
59
-    protected $_unsaved_count = 0;
60
-
61
-    /**
62
-     * used to record if a do_messenger_hooks has already been called for a message type.  This prevents multiple
63
-     * hooks getting fired if users have setup their action/filter hooks to prevent duplicate calls.
64
-     *
65
-     * @type array
66
-     */
67
-    protected $_did_hook = array();
68
-
69
-
70
-    /**
71
-     * Constructor.
72
-     * Setup all the initial properties and load a EE_Message_Repository.
73
-     *
74
-     * @param \EE_Message_Repository $message_repository
75
-     */
76
-    public function __construct(EE_Message_Repository $message_repository)
77
-    {
78
-        $this->_batch_count        = apply_filters('FHEE__EE_Messages_Queue___batch_count', 50);
79
-        $this->_message_repository = $message_repository;
80
-    }
81
-
82
-
83
-    /**
84
-     * Add a EE_Message object to the queue
85
-     *
86
-     * @param EE_Message $message
87
-     * @param array      $data         This will be an array of data to attach to the object in the repository.  If the
88
-     *                                 object is persisted, this data will be saved on an extra_meta object related to
89
-     *                                 EE_Message.
90
-     * @param  bool      $preview      Whether this EE_Message represents a preview or not.
91
-     * @param  bool      $test_send    This indicates whether to do a test send instead of actual send. A test send will
92
-     *                                 use the messenger send method but typically is based on preview data.
93
-     * @return bool          Whether the message was successfully added to the repository or not.
94
-     */
95
-    public function add(EE_Message $message, $data = array(), $preview = false, $test_send = false)
96
-    {
97
-        $data['preview']   = $preview;
98
-        $data['test_send'] = $test_send;
99
-        return $this->_message_repository->add($message, $data);
100
-    }
101
-
102
-
103
-    /**
104
-     * Removes EE_Message from _queue that matches the given EE_Message if the pointer is on a matching EE_Message
105
-     *
106
-     * @param EE_Message $message The message to detach from the queue
107
-     * @param bool       $persist This flag indicates whether to attempt to delete the object from the db as well.
108
-     * @return bool
109
-     */
110
-    public function remove(EE_Message $message, $persist = false)
111
-    {
112
-        if ($persist && $this->_message_repository->current() !== $message) {
113
-            //get pointer on right message
114
-            if ($this->_message_repository->has($message)) {
115
-                $this->_message_repository->rewind();
116
-                while ($this->_message_repository->valid()) {
117
-                    if ($this->_message_repository->current() === $message) {
118
-                        break;
119
-                    }
120
-                    $this->_message_repository->next();
121
-                }
122
-            } else {
123
-                return false;
124
-            }
125
-        }
126
-        return $persist ? $this->_message_repository->delete() : $this->_message_repository->remove($message);
127
-    }
128
-
129
-
130
-    /**
131
-     * Persists all queued EE_Message objects to the db.
132
-     *
133
-     * @param bool $do_hooks_only       @see EE_Message_Repository::saveAll
134
-     * @return array @see EE_Messages_Repository::saveAll() for return values.
135
-     */
136
-    public function save($do_hooks_only = false)
137
-    {
138
-        return $this->_message_repository->saveAll($do_hooks_only);
139
-    }
140
-
141
-
142
-    /**
143
-     * @return EE_Message_Repository
144
-     */
145
-    public function get_message_repository()
146
-    {
147
-        return $this->_message_repository;
148
-    }
149
-
150
-
151
-    /**
152
-     * This does the following things:
153
-     * 1. Checks if there is a lock on generation (prevents race conditions).  If there is a lock then exits (return
154
-     * false).
155
-     * 2. If no lock, sets lock, then retrieves a batch of non-generated EE_Message objects and adds to queue
156
-     * 3. Returns bool.  True = batch ready.  False = no batch ready (or nothing available for generation).
157
-     * Note: Callers should make sure they release the lock otherwise batch generation will be prevented from
158
-     * continuing. The lock is on a transient that is set to expire after one hour as a fallback in case locks are not
159
-     * removed.
160
-     *
161
-     * @return bool  true if successfully retrieved batch, false no batch ready.
162
-     */
163
-    public function get_batch_to_generate()
164
-    {
165
-        if ($this->is_locked(EE_Messages_Queue::action_generating)) {
166
-            return false;
167
-        }
168
-
169
-        //lock batch generation to prevent race conditions.
170
-        $this->lock_queue(EE_Messages_Queue::action_generating);
171
-
172
-        $query_args = array(
173
-            // key 0 = where conditions
174
-            0          => array('STS_ID' => EEM_Message::status_incomplete),
175
-            'order_by' => $this->_get_priority_orderby(),
176
-            'limit'    => $this->_batch_count,
177
-        );
178
-        $messages   = EEM_Message::instance()->get_all($query_args);
179
-
180
-        if ( ! $messages) {
181
-            return false; //nothing to generate
182
-        }
183
-
184
-        foreach ($messages as $message) {
185
-            if ($message instanceof EE_Message) {
186
-                $data = $message->all_extra_meta_array();
187
-                $this->add($message, $data);
188
-            }
189
-        }
190
-        return true;
191
-    }
192
-
193
-
194
-    /**
195
-     * This does the following things:
196
-     * 1. Checks if there is a lock on sending (prevents race conditions).  If there is a lock then exits (return
197
-     * false).
198
-     * 2. Grabs the allowed number of messages to send for the rate_limit.  If cannot send any more messages, then
199
-     * return false.
200
-     * 2. If no lock, sets lock, then retrieves a batch of EE_Message objects, adds to queue and triggers execution.
201
-     * 3. On success or unsuccessful send, sets status appropriately.
202
-     * 4. Saves messages via the queue
203
-     * 5. Releases lock.
204
-     *
205
-     * @return bool  true on success, false if something preventing sending (i.e. lock set).  Note: true does not
206
-     *               necessarily mean that all messages were successfully sent.  It just means that this method
207
-     *               successfully completed. On true, client may want to call $this->count_STS_in_queue(
208
-     *               EEM_Message::status_failed ) to see if any failed EE_Message objects.  Each failed message object
209
-     *               will also have a saved error message on it to assist with notifying user.
210
-     */
211
-    public function get_to_send_batch_and_send()
212
-    {
213
-        $rate_limit = $this->get_rate_limit();
214
-        if ($rate_limit < 1 || $this->is_locked(EE_Messages_Queue::action_sending)) {
215
-            return false;
216
-        }
217
-
218
-        $this->lock_queue(EE_Messages_Queue::action_sending);
219
-
220
-        $batch = $this->_batch_count < $rate_limit ? $this->_batch_count : $rate_limit;
221
-
222
-        $query_args = array(
223
-            // key 0 = where conditions
224
-            0          => array('STS_ID' => array('IN', EEM_Message::instance()->stati_indicating_to_send())),
225
-            'order_by' => $this->_get_priority_orderby(),
226
-            'limit'    => $batch,
227
-        );
228
-
229
-        $messages_to_send = EEM_Message::instance()->get_all($query_args);
230
-
231
-
232
-        //any to send?
233
-        if ( ! $messages_to_send) {
234
-            $this->unlock_queue(EE_Messages_Queue::action_sending);
235
-            return false;
236
-        }
237
-
238
-        $queue_count = 0;
239
-
240
-        //add to queue.
241
-        foreach ($messages_to_send as $message) {
242
-            if ($message instanceof EE_Message) {
243
-                $queue_count++;
244
-                $this->add($message);
245
-            }
246
-        }
247
-
248
-        //send messages  (this also updates the rate limit)
249
-        $this->execute();
250
-
251
-        //release lock
252
-        $this->unlock_queue(EE_Messages_Queue::action_sending);
253
-        //update rate limit
254
-        $this->set_rate_limit($queue_count);
255
-        return true;
256
-    }
257
-
258
-
259
-    /**
260
-     * Locks the queue so that no other queues can call the "batch" methods.
261
-     *
262
-     * @param   string $type The type of queue being locked.
263
-     */
264
-    public function lock_queue($type = EE_Messages_Queue::action_generating)
265
-    {
266
-        update_option($this->_get_lock_key($type), $this->_get_lock_expiry($type));
267
-    }
268
-
269
-
270
-    /**
271
-     * Unlocks the queue so that batch methods can be used.
272
-     *
273
-     * @param   string $type The type of queue being unlocked.
274
-     */
275
-    public function unlock_queue($type = EE_Messages_Queue::action_generating)
276
-    {
277
-        delete_option($this->_get_lock_key($type));
278
-    }
279
-
280
-
281
-    /**
282
-     * Retrieve the key used for the lock transient.
283
-     *
284
-     * @param string $type The type of lock.
285
-     * @return string
286
-     */
287
-    protected function _get_lock_key($type = EE_Messages_Queue::action_generating)
288
-    {
289
-        return '_ee_lock_' . $type;
290
-    }
291
-
292
-
293
-    /**
294
-     * Retrieve the expiry time for the lock transient.
295
-     *
296
-     * @param string $type The type of lock
297
-     * @return int   time to expiry in seconds.
298
-     */
299
-    protected function _get_lock_expiry($type = EE_Messages_Queue::action_generating)
300
-    {
301
-        return time() + (int) apply_filters('FHEE__EE_Messages_Queue__lock_expiry', HOUR_IN_SECONDS, $type);
302
-    }
303
-
304
-
305
-    /**
306
-     * Returns the key used for rate limit transient.
307
-     *
308
-     * @return string
309
-     */
310
-    protected function _get_rate_limit_key()
311
-    {
312
-        return '_ee_rate_limit';
313
-    }
314
-
315
-
316
-    /**
317
-     * Returns the rate limit expiry time.
318
-     *
319
-     * @return int
320
-     */
321
-    protected function _get_rate_limit_expiry()
322
-    {
323
-        return time() + (int) apply_filters('FHEE__EE_Messages_Queue__rate_limit_expiry', HOUR_IN_SECONDS);
324
-    }
325
-
326
-
327
-    /**
328
-     * Returns the default rate limit for sending messages.
329
-     *
330
-     * @return int
331
-     */
332
-    protected function _default_rate_limit()
333
-    {
334
-        return (int) apply_filters('FHEE__EE_Messages_Queue___rate_limit', 200);
335
-    }
336
-
337
-
338
-    /**
339
-     * Return the orderby array for priority.
340
-     *
341
-     * @return array
342
-     */
343
-    protected function _get_priority_orderby()
344
-    {
345
-        return array(
346
-            'MSG_priority' => 'ASC',
347
-            'MSG_modified' => 'DESC',
348
-        );
349
-    }
350
-
351
-
352
-    /**
353
-     * Returns whether batch methods are "locked" or not.
354
-     *
355
-     * @param  string $type The type of lock being checked for.
356
-     * @return bool
357
-     */
358
-    public function is_locked($type = EE_Messages_Queue::action_generating)
359
-    {
360
-        $lock = (int) get_option($this->_get_lock_key($type), 0);
361
-        /**
362
-         * This filters the default is_locked behaviour.
363
-         */
364
-        $is_locked = filter_var(
365
-            apply_filters(
366
-                'FHEE__EE_Messages_Queue__is_locked',
367
-                $lock > time(),
368
-                $this
369
-            ),
370
-            FILTER_VALIDATE_BOOLEAN
371
-        );
372
-
373
-        /**
374
-         * @see usage of this filter in EE_Messages_Queue::initiate_request_by_priority() method.
375
-         *            Also implemented here because messages processed on the same request should not have any locks applied.
376
-         */
377
-        if (
378
-            apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
379
-            || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
380
-        ) {
381
-            $is_locked = false;
382
-        }
383
-
384
-
385
-        return $is_locked;
386
-    }
387
-
388
-
389
-    /**
390
-     * Retrieves the rate limit that may be cached as a transient.
391
-     * If the rate limit is not set, then this sets the default rate limit and expiry and returns it.
392
-     *
393
-     * @param bool $return_expiry  If true then return the expiry time not the rate_limit.
394
-     * @return int
395
-     */
396
-    protected function get_rate_limit($return_expiry = false)
397
-    {
398
-        $stored_rate_info = get_option($this->_get_rate_limit_key(), array());
399
-        $rate_limit = isset($stored_rate_info[0])
400
-            ? (int) $stored_rate_info[0]
401
-            : 0;
402
-        $expiry = isset($stored_rate_info[1])
403
-            ? (int) $stored_rate_info[1]
404
-            : 0;
405
-        //set the default for tracking?
406
-        if (empty($stored_rate_info) || time() > $expiry) {
407
-            $expiry = $this->_get_rate_limit_expiry();
408
-            $rate_limit = $this->_default_rate_limit();
409
-            update_option($this->_get_rate_limit_key(), array($rate_limit, $expiry));
410
-        }
411
-        return $return_expiry ? $expiry : $rate_limit;
412
-    }
413
-
414
-
415
-    /**
416
-     * This updates existing rate limit with the new limit which is the old minus the batch.
417
-     *
418
-     * @param int $batch_completed This sets the new rate limit based on the given batch that was completed.
419
-     */
420
-    protected function set_rate_limit($batch_completed)
421
-    {
422
-        //first get the most up to date rate limit (in case its expired and reset)
423
-        $rate_limit = $this->get_rate_limit();
424
-        $expiry = $this->get_rate_limit(true);
425
-        $new_limit  = $rate_limit - $batch_completed;
426
-        //updating the transient option directly to avoid resetting the expiry.
427
-
428
-        update_option($this->_get_rate_limit_key(), array($new_limit, $expiry));
429
-    }
430
-
431
-
432
-    /**
433
-     * This method checks the queue for ANY EE_Message objects with a priority matching the given priority passed in.
434
-     * If that exists, then we immediately initiate a non-blocking request to do the requested action type.
435
-     * Note: Keep in mind that there is the possibility that the request will not execute if there is already another
436
-     * request running on a queue for the given task.
437
-     *
438
-     * @param string $task     This indicates what type of request is going to be initiated.
439
-     * @param int    $priority This indicates the priority that triggers initiating the request.
440
-     */
441
-    public function initiate_request_by_priority($task = 'generate', $priority = EEM_Message::priority_high)
442
-    {
443
-        //determine what status is matched with the priority as part of the trigger conditions.
444
-        $status = $task == 'generate'
445
-            ? EEM_Message::status_incomplete
446
-            : EEM_Message::instance()->stati_indicating_to_send();
447
-        // always make sure we save because either this will get executed immediately on a separate request
448
-        // or remains in the queue for the regularly scheduled queue batch.
449
-        $this->save();
450
-        /**
451
-         * This filter/option allows users to override processing of messages on separate requests and instead have everything
452
-         * happen on the same request.  If this is utilized remember:
453
-         * - message priorities don't matter
454
-         * - existing unprocessed messages in the queue will not get processed unless manually triggered.
455
-         * - things will be perceived to take longer to happen for end users (i.e. registrations) because of the additional
456
-         *   processing happening on the same request.
457
-         * - any race condition protection (locks) are removed because they don't apply when things are processed on
458
-         *   the same request.
459
-         */
460
-        if (
461
-            apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
462
-            || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
463
-        ) {
464
-            $messages_processor = EE_Registry::instance()->load_lib('Messages_Processor');
465
-            if ($messages_processor instanceof EE_Messages_Processor) {
466
-                return $messages_processor->process_immediately_from_queue($this);
467
-            }
468
-            //if we get here then that means the messages processor couldn't be loaded so messages will just remain
469
-            //queued for manual triggering by end user.
470
-        }
471
-
472
-        if ($this->_message_repository->count_by_priority_and_status($priority, $status)) {
473
-            EE_Messages_Scheduler::initiate_scheduled_non_blocking_request($task);
474
-        }
475
-    }
476
-
477
-
478
-    /**
479
-     *  Loops through the EE_Message objects in the _queue and calls the messenger send methods for each message.
480
-     *
481
-     * @param   bool     $save                    Used to indicate whether to save the message queue after sending
482
-     *                                            (default will save).
483
-     * @param   mixed    $sending_messenger       (optional) When the sending messenger is different than
484
-     *                                            what is on the EE_Message object in the queue.
485
-     *                                            For instance, showing the browser view of an email message,
486
-     *                                            or giving a pdf generated view of an html document.
487
-     *                                            This should be an instance of EE_messenger but if you call this
488
-     *                                            method
489
-     *                                            intending it to be a sending messenger but a valid one could not be
490
-     *                                            retrieved then send in an instance of EE_Error that contains the
491
-     *                                            related error message.
492
-     * @param   bool|int $by_priority             When set, this indicates that only messages
493
-     *                                            matching the given priority should be executed.
494
-     * @return int        Number of messages sent.  Note, 0 does not mean that no messages were processed.
495
-     *                                            Also, if the messenger is an request type messenger (or a preview),
496
-     *                                            its entirely possible that the messenger will exit before
497
-     */
498
-    public function execute($save = true, $sending_messenger = null, $by_priority = false)
499
-    {
500
-        $messages_sent   = 0;
501
-        $this->_did_hook = array();
502
-        $this->_message_repository->rewind();
503
-
504
-        while ($this->_message_repository->valid()) {
505
-            $error_messages = array();
506
-            /** @type EE_Message $message */
507
-            $message = $this->_message_repository->current();
508
-            //only process things that are queued for sending
509
-            if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) {
510
-                $this->_message_repository->next();
511
-                continue;
512
-            }
513
-            //if $by_priority is set and does not match then continue;
514
-            if ($by_priority && $by_priority != $message->priority()) {
515
-                $this->_message_repository->next();
516
-                continue;
517
-            }
518
-            //error checking
519
-            if (! $message->valid_messenger()) {
520
-                $error_messages[] = sprintf(
521
-                    __('The %s messenger is not active at time of sending.', 'event_espresso'),
522
-                    $message->messenger()
523
-                );
524
-            }
525
-            if (! $message->valid_message_type()) {
526
-                $error_messages[] = sprintf(
527
-                    __('The %s message type is not active at the time of sending.', 'event_espresso'),
528
-                    $message->message_type()
529
-                );
530
-            }
531
-            // if there was supposed to be a sending messenger for this message, but it was invalid/inactive,
532
-            // then it will instead be an EE_Error object, so let's check for that
533
-            if ($sending_messenger instanceof EE_Error) {
534
-                $error_messages[] = $sending_messenger->getMessage();
535
-            }
536
-            // if there are no errors, then let's process the message
537
-            if (empty($error_messages)) {
538
-                if ($save) {
539
-                    $message->set_messenger_is_executing();
540
-                }
541
-                if ($this->_process_message($message, $sending_messenger)) {
542
-                    $messages_sent++;
543
-                }
544
-            }
545
-            $this->_set_error_message($message, $error_messages);
546
-            //add modified time
547
-            $message->set_modified(time());
548
-            //we save each message after its processed to make sure its status persists in case PHP times-out or runs
549
-            //out of memory. @see https://events.codebasehq.com/projects/event-espresso/tickets/10281
550
-            if ($save) {
551
-                $message->save();
552
-            }
553
-
554
-            $this->_message_repository->next();
555
-        }
556
-        if ($save) {
557
-            $this->save(true);
558
-        }
559
-        return $messages_sent;
560
-    }
561
-
562
-
563
-    /**
564
-     * _process_message
565
-     *
566
-     * @param EE_Message $message
567
-     * @param mixed      $sending_messenger (optional)
568
-     * @return bool
569
-     */
570
-    protected function _process_message(EE_Message $message, $sending_messenger = null)
571
-    {
572
-        // these *should* have been validated in the execute() method above
573
-        $messenger    = $message->messenger_object();
574
-        $message_type = $message->message_type_object();
575
-        //do actions for sending messenger if it differs from generating messenger and swap values.
576
-        if (
577
-            $sending_messenger instanceof EE_messenger
578
-            && $messenger instanceof EE_messenger
579
-            && $sending_messenger->name != $messenger->name
580
-        ) {
581
-            $messenger->do_secondary_messenger_hooks($sending_messenger->name);
582
-            $messenger = $sending_messenger;
583
-        }
584
-        // send using messenger, but double check objects
585
-        if ($messenger instanceof EE_messenger && $message_type instanceof EE_message_type) {
586
-            //set hook for message type (but only if not using another messenger to send).
587
-            if ( ! isset($this->_did_hook[$message_type->name])) {
588
-                $message_type->do_messenger_hooks($messenger);
589
-                $this->_did_hook[$message_type->name] = 1;
590
-            }
591
-            //if preview then use preview method
592
-            return $this->_message_repository->is_preview()
593
-                ? $this->_do_preview($message, $messenger, $message_type, $this->_message_repository->is_test_send())
594
-                : $this->_do_send($message, $messenger, $message_type);
595
-        }
596
-        return false;
597
-    }
598
-
599
-
600
-    /**
601
-     * The intention of this method is to count how many EE_Message objects
602
-     * are in the queue with a given status.
603
-     * Example usage:
604
-     * After a caller calls the "EE_Message_Queue::execute()" method, the caller can check if there were any failed
605
-     * sends by calling $queue->count_STS_in_queue( EEM_Message_Queue::status_failed ).
606
-     *
607
-     * @param array|string $status Stati to check for in queue
608
-     * @return int  Count of EE_Message's matching the given status.
609
-     */
610
-    public function count_STS_in_queue($status)
611
-    {
612
-        $count  = 0;
613
-        $status = is_array($status) ? $status : array($status);
614
-        $this->_message_repository->rewind();
615
-        foreach ($this->_message_repository as $message) {
616
-            if (in_array($message->STS_ID(), $status)) {
617
-                $count++;
618
-            }
619
-        }
620
-        return $count;
621
-    }
622
-
623
-
624
-    /**
625
-     * Executes the get_preview method on the provided messenger.
626
-     *
627
-     * @param EE_Message      $message
628
-     * @param EE_messenger    $messenger
629
-     * @param EE_message_type $message_type
630
-     * @param                 $test_send
631
-     * @return bool   true means all went well, false means, not so much.
632
-     */
633
-    protected function _do_preview(
634
-        EE_Message $message,
635
-        EE_messenger $messenger,
636
-        EE_message_type $message_type,
637
-        $test_send
638
-    ) {
639
-        if ($preview = $messenger->get_preview($message, $message_type, $test_send)) {
640
-            if ( ! $test_send) {
641
-                $message->set_content($preview);
642
-            }
643
-            $message->set_STS_ID(EEM_Message::status_sent);
644
-            return true;
645
-        } else {
646
-            $message->set_STS_ID(EEM_Message::status_failed);
647
-            return false;
648
-        }
649
-    }
650
-
651
-
652
-    /**
653
-     * Executes the send method on the provided messenger
654
-     * EE_Messengers are expected to:
655
-     * - return true if the send was successful.
656
-     * - return false if the send was unsuccessful but can be tried again.
657
-     * - throw an Exception if the send was unsuccessful and cannot be tried again.
658
-     *
659
-     * @param EE_Message      $message
660
-     * @param EE_messenger    $messenger
661
-     * @param EE_message_type $message_type
662
-     * @return bool true means all went well, false means, not so much.
663
-     */
664
-    protected function _do_send(EE_Message $message, EE_messenger $messenger, EE_message_type $message_type)
665
-    {
666
-        try {
667
-            if ($messenger->send_message($message, $message_type)) {
668
-                $message->set_STS_ID(EEM_Message::status_sent);
669
-                return true;
670
-            } else {
671
-                $message->set_STS_ID(EEM_Message::status_retry);
672
-                return false;
673
-            }
674
-        } catch (SendMessageException $e) {
675
-            $message->set_STS_ID(EEM_Message::status_failed);
676
-            $message->set_error_message($e->getMessage());
677
-            return false;
678
-        }
679
-    }
680
-
681
-
682
-    /**
683
-     * This sets any necessary error messages on the message object and its status to failed.
684
-     *
685
-     * @param EE_Message $message
686
-     * @param array      $error_messages the response from the messenger.
687
-     */
688
-    protected function _set_error_message(EE_Message $message, $error_messages)
689
-    {
690
-        $error_messages = (array)$error_messages;
691
-        if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) {
692
-            $notices          = EE_Error::has_notices();
693
-            $error_messages[] = __(
694
-                'Messenger and Message Type were valid and active, but the messenger send method failed.',
695
-                'event_espresso'
696
-            );
697
-            if ($notices === 1) {
698
-                $notices           = EE_Error::get_vanilla_notices();
699
-                $notices['errors'] = isset($notices['errors']) ? $notices['errors'] : array();
700
-                $error_messages[]  = implode("\n", $notices['errors']);
701
-            }
702
-        }
703
-        if (count($error_messages) > 0) {
704
-            $msg = __('Message was not executed successfully.', 'event_espresso');
705
-            $msg = $msg . "\n" . implode("\n", $error_messages);
706
-            $message->set_error_message($msg);
707
-        }
708
-    }
21
+	/**
22
+	 * @type    string  reference for sending action
23
+	 */
24
+	const action_sending = 'sending';
25
+
26
+	/**
27
+	 * @type    string  reference for generation action
28
+	 */
29
+	const action_generating = 'generation';
30
+
31
+
32
+	/**
33
+	 * @type EE_Message_Repository $_message_repository
34
+	 */
35
+	protected $_message_repository;
36
+
37
+	/**
38
+	 * Sets the limit of how many messages are generated per process.
39
+	 *
40
+	 * @type int
41
+	 */
42
+	protected $_batch_count;
43
+
44
+
45
+	/**
46
+	 * This is an array of cached queue items being stored in this object.
47
+	 * The array keys will be the ID of the EE_Message in the db if saved.  If the EE_Message
48
+	 * is not saved to the db then its key will be an increment of "UNS" (i.e. UNS1, UNS2 etc.)
49
+	 *
50
+	 * @type EE_Message[]
51
+	 */
52
+	protected $_cached_queue_items;
53
+
54
+	/**
55
+	 * Tracks the number of unsaved queue items.
56
+	 *
57
+	 * @type int
58
+	 */
59
+	protected $_unsaved_count = 0;
60
+
61
+	/**
62
+	 * used to record if a do_messenger_hooks has already been called for a message type.  This prevents multiple
63
+	 * hooks getting fired if users have setup their action/filter hooks to prevent duplicate calls.
64
+	 *
65
+	 * @type array
66
+	 */
67
+	protected $_did_hook = array();
68
+
69
+
70
+	/**
71
+	 * Constructor.
72
+	 * Setup all the initial properties and load a EE_Message_Repository.
73
+	 *
74
+	 * @param \EE_Message_Repository $message_repository
75
+	 */
76
+	public function __construct(EE_Message_Repository $message_repository)
77
+	{
78
+		$this->_batch_count        = apply_filters('FHEE__EE_Messages_Queue___batch_count', 50);
79
+		$this->_message_repository = $message_repository;
80
+	}
81
+
82
+
83
+	/**
84
+	 * Add a EE_Message object to the queue
85
+	 *
86
+	 * @param EE_Message $message
87
+	 * @param array      $data         This will be an array of data to attach to the object in the repository.  If the
88
+	 *                                 object is persisted, this data will be saved on an extra_meta object related to
89
+	 *                                 EE_Message.
90
+	 * @param  bool      $preview      Whether this EE_Message represents a preview or not.
91
+	 * @param  bool      $test_send    This indicates whether to do a test send instead of actual send. A test send will
92
+	 *                                 use the messenger send method but typically is based on preview data.
93
+	 * @return bool          Whether the message was successfully added to the repository or not.
94
+	 */
95
+	public function add(EE_Message $message, $data = array(), $preview = false, $test_send = false)
96
+	{
97
+		$data['preview']   = $preview;
98
+		$data['test_send'] = $test_send;
99
+		return $this->_message_repository->add($message, $data);
100
+	}
101
+
102
+
103
+	/**
104
+	 * Removes EE_Message from _queue that matches the given EE_Message if the pointer is on a matching EE_Message
105
+	 *
106
+	 * @param EE_Message $message The message to detach from the queue
107
+	 * @param bool       $persist This flag indicates whether to attempt to delete the object from the db as well.
108
+	 * @return bool
109
+	 */
110
+	public function remove(EE_Message $message, $persist = false)
111
+	{
112
+		if ($persist && $this->_message_repository->current() !== $message) {
113
+			//get pointer on right message
114
+			if ($this->_message_repository->has($message)) {
115
+				$this->_message_repository->rewind();
116
+				while ($this->_message_repository->valid()) {
117
+					if ($this->_message_repository->current() === $message) {
118
+						break;
119
+					}
120
+					$this->_message_repository->next();
121
+				}
122
+			} else {
123
+				return false;
124
+			}
125
+		}
126
+		return $persist ? $this->_message_repository->delete() : $this->_message_repository->remove($message);
127
+	}
128
+
129
+
130
+	/**
131
+	 * Persists all queued EE_Message objects to the db.
132
+	 *
133
+	 * @param bool $do_hooks_only       @see EE_Message_Repository::saveAll
134
+	 * @return array @see EE_Messages_Repository::saveAll() for return values.
135
+	 */
136
+	public function save($do_hooks_only = false)
137
+	{
138
+		return $this->_message_repository->saveAll($do_hooks_only);
139
+	}
140
+
141
+
142
+	/**
143
+	 * @return EE_Message_Repository
144
+	 */
145
+	public function get_message_repository()
146
+	{
147
+		return $this->_message_repository;
148
+	}
149
+
150
+
151
+	/**
152
+	 * This does the following things:
153
+	 * 1. Checks if there is a lock on generation (prevents race conditions).  If there is a lock then exits (return
154
+	 * false).
155
+	 * 2. If no lock, sets lock, then retrieves a batch of non-generated EE_Message objects and adds to queue
156
+	 * 3. Returns bool.  True = batch ready.  False = no batch ready (or nothing available for generation).
157
+	 * Note: Callers should make sure they release the lock otherwise batch generation will be prevented from
158
+	 * continuing. The lock is on a transient that is set to expire after one hour as a fallback in case locks are not
159
+	 * removed.
160
+	 *
161
+	 * @return bool  true if successfully retrieved batch, false no batch ready.
162
+	 */
163
+	public function get_batch_to_generate()
164
+	{
165
+		if ($this->is_locked(EE_Messages_Queue::action_generating)) {
166
+			return false;
167
+		}
168
+
169
+		//lock batch generation to prevent race conditions.
170
+		$this->lock_queue(EE_Messages_Queue::action_generating);
171
+
172
+		$query_args = array(
173
+			// key 0 = where conditions
174
+			0          => array('STS_ID' => EEM_Message::status_incomplete),
175
+			'order_by' => $this->_get_priority_orderby(),
176
+			'limit'    => $this->_batch_count,
177
+		);
178
+		$messages   = EEM_Message::instance()->get_all($query_args);
179
+
180
+		if ( ! $messages) {
181
+			return false; //nothing to generate
182
+		}
183
+
184
+		foreach ($messages as $message) {
185
+			if ($message instanceof EE_Message) {
186
+				$data = $message->all_extra_meta_array();
187
+				$this->add($message, $data);
188
+			}
189
+		}
190
+		return true;
191
+	}
192
+
193
+
194
+	/**
195
+	 * This does the following things:
196
+	 * 1. Checks if there is a lock on sending (prevents race conditions).  If there is a lock then exits (return
197
+	 * false).
198
+	 * 2. Grabs the allowed number of messages to send for the rate_limit.  If cannot send any more messages, then
199
+	 * return false.
200
+	 * 2. If no lock, sets lock, then retrieves a batch of EE_Message objects, adds to queue and triggers execution.
201
+	 * 3. On success or unsuccessful send, sets status appropriately.
202
+	 * 4. Saves messages via the queue
203
+	 * 5. Releases lock.
204
+	 *
205
+	 * @return bool  true on success, false if something preventing sending (i.e. lock set).  Note: true does not
206
+	 *               necessarily mean that all messages were successfully sent.  It just means that this method
207
+	 *               successfully completed. On true, client may want to call $this->count_STS_in_queue(
208
+	 *               EEM_Message::status_failed ) to see if any failed EE_Message objects.  Each failed message object
209
+	 *               will also have a saved error message on it to assist with notifying user.
210
+	 */
211
+	public function get_to_send_batch_and_send()
212
+	{
213
+		$rate_limit = $this->get_rate_limit();
214
+		if ($rate_limit < 1 || $this->is_locked(EE_Messages_Queue::action_sending)) {
215
+			return false;
216
+		}
217
+
218
+		$this->lock_queue(EE_Messages_Queue::action_sending);
219
+
220
+		$batch = $this->_batch_count < $rate_limit ? $this->_batch_count : $rate_limit;
221
+
222
+		$query_args = array(
223
+			// key 0 = where conditions
224
+			0          => array('STS_ID' => array('IN', EEM_Message::instance()->stati_indicating_to_send())),
225
+			'order_by' => $this->_get_priority_orderby(),
226
+			'limit'    => $batch,
227
+		);
228
+
229
+		$messages_to_send = EEM_Message::instance()->get_all($query_args);
230
+
231
+
232
+		//any to send?
233
+		if ( ! $messages_to_send) {
234
+			$this->unlock_queue(EE_Messages_Queue::action_sending);
235
+			return false;
236
+		}
237
+
238
+		$queue_count = 0;
239
+
240
+		//add to queue.
241
+		foreach ($messages_to_send as $message) {
242
+			if ($message instanceof EE_Message) {
243
+				$queue_count++;
244
+				$this->add($message);
245
+			}
246
+		}
247
+
248
+		//send messages  (this also updates the rate limit)
249
+		$this->execute();
250
+
251
+		//release lock
252
+		$this->unlock_queue(EE_Messages_Queue::action_sending);
253
+		//update rate limit
254
+		$this->set_rate_limit($queue_count);
255
+		return true;
256
+	}
257
+
258
+
259
+	/**
260
+	 * Locks the queue so that no other queues can call the "batch" methods.
261
+	 *
262
+	 * @param   string $type The type of queue being locked.
263
+	 */
264
+	public function lock_queue($type = EE_Messages_Queue::action_generating)
265
+	{
266
+		update_option($this->_get_lock_key($type), $this->_get_lock_expiry($type));
267
+	}
268
+
269
+
270
+	/**
271
+	 * Unlocks the queue so that batch methods can be used.
272
+	 *
273
+	 * @param   string $type The type of queue being unlocked.
274
+	 */
275
+	public function unlock_queue($type = EE_Messages_Queue::action_generating)
276
+	{
277
+		delete_option($this->_get_lock_key($type));
278
+	}
279
+
280
+
281
+	/**
282
+	 * Retrieve the key used for the lock transient.
283
+	 *
284
+	 * @param string $type The type of lock.
285
+	 * @return string
286
+	 */
287
+	protected function _get_lock_key($type = EE_Messages_Queue::action_generating)
288
+	{
289
+		return '_ee_lock_' . $type;
290
+	}
291
+
292
+
293
+	/**
294
+	 * Retrieve the expiry time for the lock transient.
295
+	 *
296
+	 * @param string $type The type of lock
297
+	 * @return int   time to expiry in seconds.
298
+	 */
299
+	protected function _get_lock_expiry($type = EE_Messages_Queue::action_generating)
300
+	{
301
+		return time() + (int) apply_filters('FHEE__EE_Messages_Queue__lock_expiry', HOUR_IN_SECONDS, $type);
302
+	}
303
+
304
+
305
+	/**
306
+	 * Returns the key used for rate limit transient.
307
+	 *
308
+	 * @return string
309
+	 */
310
+	protected function _get_rate_limit_key()
311
+	{
312
+		return '_ee_rate_limit';
313
+	}
314
+
315
+
316
+	/**
317
+	 * Returns the rate limit expiry time.
318
+	 *
319
+	 * @return int
320
+	 */
321
+	protected function _get_rate_limit_expiry()
322
+	{
323
+		return time() + (int) apply_filters('FHEE__EE_Messages_Queue__rate_limit_expiry', HOUR_IN_SECONDS);
324
+	}
325
+
326
+
327
+	/**
328
+	 * Returns the default rate limit for sending messages.
329
+	 *
330
+	 * @return int
331
+	 */
332
+	protected function _default_rate_limit()
333
+	{
334
+		return (int) apply_filters('FHEE__EE_Messages_Queue___rate_limit', 200);
335
+	}
336
+
337
+
338
+	/**
339
+	 * Return the orderby array for priority.
340
+	 *
341
+	 * @return array
342
+	 */
343
+	protected function _get_priority_orderby()
344
+	{
345
+		return array(
346
+			'MSG_priority' => 'ASC',
347
+			'MSG_modified' => 'DESC',
348
+		);
349
+	}
350
+
351
+
352
+	/**
353
+	 * Returns whether batch methods are "locked" or not.
354
+	 *
355
+	 * @param  string $type The type of lock being checked for.
356
+	 * @return bool
357
+	 */
358
+	public function is_locked($type = EE_Messages_Queue::action_generating)
359
+	{
360
+		$lock = (int) get_option($this->_get_lock_key($type), 0);
361
+		/**
362
+		 * This filters the default is_locked behaviour.
363
+		 */
364
+		$is_locked = filter_var(
365
+			apply_filters(
366
+				'FHEE__EE_Messages_Queue__is_locked',
367
+				$lock > time(),
368
+				$this
369
+			),
370
+			FILTER_VALIDATE_BOOLEAN
371
+		);
372
+
373
+		/**
374
+		 * @see usage of this filter in EE_Messages_Queue::initiate_request_by_priority() method.
375
+		 *            Also implemented here because messages processed on the same request should not have any locks applied.
376
+		 */
377
+		if (
378
+			apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
379
+			|| EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
380
+		) {
381
+			$is_locked = false;
382
+		}
383
+
384
+
385
+		return $is_locked;
386
+	}
387
+
388
+
389
+	/**
390
+	 * Retrieves the rate limit that may be cached as a transient.
391
+	 * If the rate limit is not set, then this sets the default rate limit and expiry and returns it.
392
+	 *
393
+	 * @param bool $return_expiry  If true then return the expiry time not the rate_limit.
394
+	 * @return int
395
+	 */
396
+	protected function get_rate_limit($return_expiry = false)
397
+	{
398
+		$stored_rate_info = get_option($this->_get_rate_limit_key(), array());
399
+		$rate_limit = isset($stored_rate_info[0])
400
+			? (int) $stored_rate_info[0]
401
+			: 0;
402
+		$expiry = isset($stored_rate_info[1])
403
+			? (int) $stored_rate_info[1]
404
+			: 0;
405
+		//set the default for tracking?
406
+		if (empty($stored_rate_info) || time() > $expiry) {
407
+			$expiry = $this->_get_rate_limit_expiry();
408
+			$rate_limit = $this->_default_rate_limit();
409
+			update_option($this->_get_rate_limit_key(), array($rate_limit, $expiry));
410
+		}
411
+		return $return_expiry ? $expiry : $rate_limit;
412
+	}
413
+
414
+
415
+	/**
416
+	 * This updates existing rate limit with the new limit which is the old minus the batch.
417
+	 *
418
+	 * @param int $batch_completed This sets the new rate limit based on the given batch that was completed.
419
+	 */
420
+	protected function set_rate_limit($batch_completed)
421
+	{
422
+		//first get the most up to date rate limit (in case its expired and reset)
423
+		$rate_limit = $this->get_rate_limit();
424
+		$expiry = $this->get_rate_limit(true);
425
+		$new_limit  = $rate_limit - $batch_completed;
426
+		//updating the transient option directly to avoid resetting the expiry.
427
+
428
+		update_option($this->_get_rate_limit_key(), array($new_limit, $expiry));
429
+	}
430
+
431
+
432
+	/**
433
+	 * This method checks the queue for ANY EE_Message objects with a priority matching the given priority passed in.
434
+	 * If that exists, then we immediately initiate a non-blocking request to do the requested action type.
435
+	 * Note: Keep in mind that there is the possibility that the request will not execute if there is already another
436
+	 * request running on a queue for the given task.
437
+	 *
438
+	 * @param string $task     This indicates what type of request is going to be initiated.
439
+	 * @param int    $priority This indicates the priority that triggers initiating the request.
440
+	 */
441
+	public function initiate_request_by_priority($task = 'generate', $priority = EEM_Message::priority_high)
442
+	{
443
+		//determine what status is matched with the priority as part of the trigger conditions.
444
+		$status = $task == 'generate'
445
+			? EEM_Message::status_incomplete
446
+			: EEM_Message::instance()->stati_indicating_to_send();
447
+		// always make sure we save because either this will get executed immediately on a separate request
448
+		// or remains in the queue for the regularly scheduled queue batch.
449
+		$this->save();
450
+		/**
451
+		 * This filter/option allows users to override processing of messages on separate requests and instead have everything
452
+		 * happen on the same request.  If this is utilized remember:
453
+		 * - message priorities don't matter
454
+		 * - existing unprocessed messages in the queue will not get processed unless manually triggered.
455
+		 * - things will be perceived to take longer to happen for end users (i.e. registrations) because of the additional
456
+		 *   processing happening on the same request.
457
+		 * - any race condition protection (locks) are removed because they don't apply when things are processed on
458
+		 *   the same request.
459
+		 */
460
+		if (
461
+			apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
462
+			|| EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
463
+		) {
464
+			$messages_processor = EE_Registry::instance()->load_lib('Messages_Processor');
465
+			if ($messages_processor instanceof EE_Messages_Processor) {
466
+				return $messages_processor->process_immediately_from_queue($this);
467
+			}
468
+			//if we get here then that means the messages processor couldn't be loaded so messages will just remain
469
+			//queued for manual triggering by end user.
470
+		}
471
+
472
+		if ($this->_message_repository->count_by_priority_and_status($priority, $status)) {
473
+			EE_Messages_Scheduler::initiate_scheduled_non_blocking_request($task);
474
+		}
475
+	}
476
+
477
+
478
+	/**
479
+	 *  Loops through the EE_Message objects in the _queue and calls the messenger send methods for each message.
480
+	 *
481
+	 * @param   bool     $save                    Used to indicate whether to save the message queue after sending
482
+	 *                                            (default will save).
483
+	 * @param   mixed    $sending_messenger       (optional) When the sending messenger is different than
484
+	 *                                            what is on the EE_Message object in the queue.
485
+	 *                                            For instance, showing the browser view of an email message,
486
+	 *                                            or giving a pdf generated view of an html document.
487
+	 *                                            This should be an instance of EE_messenger but if you call this
488
+	 *                                            method
489
+	 *                                            intending it to be a sending messenger but a valid one could not be
490
+	 *                                            retrieved then send in an instance of EE_Error that contains the
491
+	 *                                            related error message.
492
+	 * @param   bool|int $by_priority             When set, this indicates that only messages
493
+	 *                                            matching the given priority should be executed.
494
+	 * @return int        Number of messages sent.  Note, 0 does not mean that no messages were processed.
495
+	 *                                            Also, if the messenger is an request type messenger (or a preview),
496
+	 *                                            its entirely possible that the messenger will exit before
497
+	 */
498
+	public function execute($save = true, $sending_messenger = null, $by_priority = false)
499
+	{
500
+		$messages_sent   = 0;
501
+		$this->_did_hook = array();
502
+		$this->_message_repository->rewind();
503
+
504
+		while ($this->_message_repository->valid()) {
505
+			$error_messages = array();
506
+			/** @type EE_Message $message */
507
+			$message = $this->_message_repository->current();
508
+			//only process things that are queued for sending
509
+			if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) {
510
+				$this->_message_repository->next();
511
+				continue;
512
+			}
513
+			//if $by_priority is set and does not match then continue;
514
+			if ($by_priority && $by_priority != $message->priority()) {
515
+				$this->_message_repository->next();
516
+				continue;
517
+			}
518
+			//error checking
519
+			if (! $message->valid_messenger()) {
520
+				$error_messages[] = sprintf(
521
+					__('The %s messenger is not active at time of sending.', 'event_espresso'),
522
+					$message->messenger()
523
+				);
524
+			}
525
+			if (! $message->valid_message_type()) {
526
+				$error_messages[] = sprintf(
527
+					__('The %s message type is not active at the time of sending.', 'event_espresso'),
528
+					$message->message_type()
529
+				);
530
+			}
531
+			// if there was supposed to be a sending messenger for this message, but it was invalid/inactive,
532
+			// then it will instead be an EE_Error object, so let's check for that
533
+			if ($sending_messenger instanceof EE_Error) {
534
+				$error_messages[] = $sending_messenger->getMessage();
535
+			}
536
+			// if there are no errors, then let's process the message
537
+			if (empty($error_messages)) {
538
+				if ($save) {
539
+					$message->set_messenger_is_executing();
540
+				}
541
+				if ($this->_process_message($message, $sending_messenger)) {
542
+					$messages_sent++;
543
+				}
544
+			}
545
+			$this->_set_error_message($message, $error_messages);
546
+			//add modified time
547
+			$message->set_modified(time());
548
+			//we save each message after its processed to make sure its status persists in case PHP times-out or runs
549
+			//out of memory. @see https://events.codebasehq.com/projects/event-espresso/tickets/10281
550
+			if ($save) {
551
+				$message->save();
552
+			}
553
+
554
+			$this->_message_repository->next();
555
+		}
556
+		if ($save) {
557
+			$this->save(true);
558
+		}
559
+		return $messages_sent;
560
+	}
561
+
562
+
563
+	/**
564
+	 * _process_message
565
+	 *
566
+	 * @param EE_Message $message
567
+	 * @param mixed      $sending_messenger (optional)
568
+	 * @return bool
569
+	 */
570
+	protected function _process_message(EE_Message $message, $sending_messenger = null)
571
+	{
572
+		// these *should* have been validated in the execute() method above
573
+		$messenger    = $message->messenger_object();
574
+		$message_type = $message->message_type_object();
575
+		//do actions for sending messenger if it differs from generating messenger and swap values.
576
+		if (
577
+			$sending_messenger instanceof EE_messenger
578
+			&& $messenger instanceof EE_messenger
579
+			&& $sending_messenger->name != $messenger->name
580
+		) {
581
+			$messenger->do_secondary_messenger_hooks($sending_messenger->name);
582
+			$messenger = $sending_messenger;
583
+		}
584
+		// send using messenger, but double check objects
585
+		if ($messenger instanceof EE_messenger && $message_type instanceof EE_message_type) {
586
+			//set hook for message type (but only if not using another messenger to send).
587
+			if ( ! isset($this->_did_hook[$message_type->name])) {
588
+				$message_type->do_messenger_hooks($messenger);
589
+				$this->_did_hook[$message_type->name] = 1;
590
+			}
591
+			//if preview then use preview method
592
+			return $this->_message_repository->is_preview()
593
+				? $this->_do_preview($message, $messenger, $message_type, $this->_message_repository->is_test_send())
594
+				: $this->_do_send($message, $messenger, $message_type);
595
+		}
596
+		return false;
597
+	}
598
+
599
+
600
+	/**
601
+	 * The intention of this method is to count how many EE_Message objects
602
+	 * are in the queue with a given status.
603
+	 * Example usage:
604
+	 * After a caller calls the "EE_Message_Queue::execute()" method, the caller can check if there were any failed
605
+	 * sends by calling $queue->count_STS_in_queue( EEM_Message_Queue::status_failed ).
606
+	 *
607
+	 * @param array|string $status Stati to check for in queue
608
+	 * @return int  Count of EE_Message's matching the given status.
609
+	 */
610
+	public function count_STS_in_queue($status)
611
+	{
612
+		$count  = 0;
613
+		$status = is_array($status) ? $status : array($status);
614
+		$this->_message_repository->rewind();
615
+		foreach ($this->_message_repository as $message) {
616
+			if (in_array($message->STS_ID(), $status)) {
617
+				$count++;
618
+			}
619
+		}
620
+		return $count;
621
+	}
622
+
623
+
624
+	/**
625
+	 * Executes the get_preview method on the provided messenger.
626
+	 *
627
+	 * @param EE_Message      $message
628
+	 * @param EE_messenger    $messenger
629
+	 * @param EE_message_type $message_type
630
+	 * @param                 $test_send
631
+	 * @return bool   true means all went well, false means, not so much.
632
+	 */
633
+	protected function _do_preview(
634
+		EE_Message $message,
635
+		EE_messenger $messenger,
636
+		EE_message_type $message_type,
637
+		$test_send
638
+	) {
639
+		if ($preview = $messenger->get_preview($message, $message_type, $test_send)) {
640
+			if ( ! $test_send) {
641
+				$message->set_content($preview);
642
+			}
643
+			$message->set_STS_ID(EEM_Message::status_sent);
644
+			return true;
645
+		} else {
646
+			$message->set_STS_ID(EEM_Message::status_failed);
647
+			return false;
648
+		}
649
+	}
650
+
651
+
652
+	/**
653
+	 * Executes the send method on the provided messenger
654
+	 * EE_Messengers are expected to:
655
+	 * - return true if the send was successful.
656
+	 * - return false if the send was unsuccessful but can be tried again.
657
+	 * - throw an Exception if the send was unsuccessful and cannot be tried again.
658
+	 *
659
+	 * @param EE_Message      $message
660
+	 * @param EE_messenger    $messenger
661
+	 * @param EE_message_type $message_type
662
+	 * @return bool true means all went well, false means, not so much.
663
+	 */
664
+	protected function _do_send(EE_Message $message, EE_messenger $messenger, EE_message_type $message_type)
665
+	{
666
+		try {
667
+			if ($messenger->send_message($message, $message_type)) {
668
+				$message->set_STS_ID(EEM_Message::status_sent);
669
+				return true;
670
+			} else {
671
+				$message->set_STS_ID(EEM_Message::status_retry);
672
+				return false;
673
+			}
674
+		} catch (SendMessageException $e) {
675
+			$message->set_STS_ID(EEM_Message::status_failed);
676
+			$message->set_error_message($e->getMessage());
677
+			return false;
678
+		}
679
+	}
680
+
681
+
682
+	/**
683
+	 * This sets any necessary error messages on the message object and its status to failed.
684
+	 *
685
+	 * @param EE_Message $message
686
+	 * @param array      $error_messages the response from the messenger.
687
+	 */
688
+	protected function _set_error_message(EE_Message $message, $error_messages)
689
+	{
690
+		$error_messages = (array)$error_messages;
691
+		if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) {
692
+			$notices          = EE_Error::has_notices();
693
+			$error_messages[] = __(
694
+				'Messenger and Message Type were valid and active, but the messenger send method failed.',
695
+				'event_espresso'
696
+			);
697
+			if ($notices === 1) {
698
+				$notices           = EE_Error::get_vanilla_notices();
699
+				$notices['errors'] = isset($notices['errors']) ? $notices['errors'] : array();
700
+				$error_messages[]  = implode("\n", $notices['errors']);
701
+			}
702
+		}
703
+		if (count($error_messages) > 0) {
704
+			$msg = __('Message was not executed successfully.', 'event_espresso');
705
+			$msg = $msg . "\n" . implode("\n", $error_messages);
706
+			$message->set_error_message($msg);
707
+		}
708
+	}
709 709
 
710 710
 } //end EE_Messages_Queue class
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 use \EventEspresso\core\exceptions\SendMessageException;
3 3
 
4
-if (! defined('EVENT_ESPRESSO_VERSION')) {
4
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
5 5
     exit('No direct script access allowed');
6 6
 }
7 7
 
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
             'order_by' => $this->_get_priority_orderby(),
176 176
             'limit'    => $this->_batch_count,
177 177
         );
178
-        $messages   = EEM_Message::instance()->get_all($query_args);
178
+        $messages = EEM_Message::instance()->get_all($query_args);
179 179
 
180 180
         if ( ! $messages) {
181 181
             return false; //nothing to generate
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
      */
287 287
     protected function _get_lock_key($type = EE_Messages_Queue::action_generating)
288 288
     {
289
-        return '_ee_lock_' . $type;
289
+        return '_ee_lock_'.$type;
290 290
     }
291 291
 
292 292
 
@@ -506,7 +506,7 @@  discard block
 block discarded – undo
506 506
             /** @type EE_Message $message */
507 507
             $message = $this->_message_repository->current();
508 508
             //only process things that are queued for sending
509
-            if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) {
509
+            if ( ! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) {
510 510
                 $this->_message_repository->next();
511 511
                 continue;
512 512
             }
@@ -516,13 +516,13 @@  discard block
 block discarded – undo
516 516
                 continue;
517 517
             }
518 518
             //error checking
519
-            if (! $message->valid_messenger()) {
519
+            if ( ! $message->valid_messenger()) {
520 520
                 $error_messages[] = sprintf(
521 521
                     __('The %s messenger is not active at time of sending.', 'event_espresso'),
522 522
                     $message->messenger()
523 523
                 );
524 524
             }
525
-            if (! $message->valid_message_type()) {
525
+            if ( ! $message->valid_message_type()) {
526 526
                 $error_messages[] = sprintf(
527 527
                     __('The %s message type is not active at the time of sending.', 'event_espresso'),
528 528
                     $message->message_type()
@@ -687,7 +687,7 @@  discard block
 block discarded – undo
687 687
      */
688 688
     protected function _set_error_message(EE_Message $message, $error_messages)
689 689
     {
690
-        $error_messages = (array)$error_messages;
690
+        $error_messages = (array) $error_messages;
691 691
         if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) {
692 692
             $notices          = EE_Error::has_notices();
693 693
             $error_messages[] = __(
@@ -702,7 +702,7 @@  discard block
 block discarded – undo
702 702
         }
703 703
         if (count($error_messages) > 0) {
704 704
             $msg = __('Message was not executed successfully.', 'event_espresso');
705
-            $msg = $msg . "\n" . implode("\n", $error_messages);
705
+            $msg = $msg."\n".implode("\n", $error_messages);
706 706
             $message->set_error_message($msg);
707 707
         }
708 708
     }
Please login to merge, or discard this patch.
admin_pages/payments/Payment_Log_Admin_List_Table.class.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -101,7 +101,7 @@
 block discarded – undo
101 101
     /**
102 102
      * _get_table_filters
103 103
      *
104
-     * @return array
104
+     * @return string[]
105 105
      */
106 106
     protected function _get_table_filters()
107 107
     {
Please login to merge, or discard this patch.
Indentation   +195 added lines, -195 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 if (! defined('EVENT_ESPRESSO_VERSION')) {
3
-    exit('NO direct script access allowed');
3
+	exit('NO direct script access allowed');
4 4
 }
5 5
 
6 6
 
@@ -27,205 +27,205 @@  discard block
 block discarded – undo
27 27
 class Payment_Log_Admin_List_Table extends EE_Admin_List_Table
28 28
 {
29 29
 
30
-    /**
31
-     * @param \EE_Admin_Page $admin_page
32
-     * @return Payment_Log_Admin_List_Table
33
-     */
34
-    public function __construct($admin_page)
35
-    {
36
-        parent::__construct($admin_page);
37
-    }
38
-
39
-
40
-
41
-    /**
42
-     * _setup_data
43
-     *
44
-     * @return void
45
-     */
46
-    protected function _setup_data()
47
-    {
48
-        $this->_data = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page);
49
-        //		if(isset($this->_req_data['status'] ) && $this->_req_data['status'] == 'trash'){
50
-        //			$this->_data = $this->_admin_page->get_trashed_questions( $this->_per_page,$this->_current_page, FALSE );
51
-        //		}else{
52
-        //			$this->_data = $this->_admin_page->get_questions( $this->_per_page,$this->_current_page, FALSE );
53
-        //		}
54
-        $this->_all_data_count = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page, true);
55
-        add_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', array($this, 'add_download_logs_checkbox'));
56
-    }
57
-
58
-
59
-
60
-    /**
61
-     * add_download_logs_checkbox
62
-     * adds a checkbox to the bottom of the list table, instead of at the top with the rest of the filters
63
-     *
64
-     * @return void
65
-     */
66
-    public function add_download_logs_checkbox()
67
-    {
68
-        echo "<input type='submit' class='button-primary' id='download_results' name='download_results' value='" . __('Download Results', 'event_espresso') . "'>";
69
-    }
70
-
71
-
72
-
73
-    /**
74
-     * _set_properties
75
-     *
76
-     * @return void
77
-     */
78
-    protected function _set_properties()
79
-    {
80
-        $this->_wp_list_args = array(
81
-            'singular' => __('payment log', 'event_espresso'),
82
-            'plural'   => __('payment logs', 'event_espresso'),
83
-            'ajax'     => true, //for now,
84
-            'screen'   => $this->_admin_page->get_current_screen()->id,
85
-        );
86
-        $this->_columns = array(
87
-            'cb'       => '<input type="checkbox" />',
88
-            'id'       => __('ID', 'event_espresso'),
89
-            'LOG_time' => __('Time', 'event_espresso'),
90
-            'PMD_ID'   => __('Payment Method', 'event_espresso'),
91
-            'TXN_ID'   => __('Transaction ID', 'event_espresso'),
92
-        );
93
-        $this->_sortable_columns = array(
94
-            'LOG_time' => array('LOG_time' => true),
95
-        );
96
-        $this->_hidden_columns = array();
97
-    }
98
-
99
-
100
-
101
-    /**
102
-     * _get_table_filters
103
-     *
104
-     * @return array
105
-     */
106
-    protected function _get_table_filters()
107
-    {
108
-        $filters = array();
109
-        //todo we're currently using old functions here. We need to move things into the Events_Admin_Page() class as methods.
110
-        $payment_methods = EEM_Payment_Method::instance()->get_all();
111
-        $payment_method_names = array(array('id' => 'all', 'text' => __("All", 'event_espresso')), array('id' => '0', 'text' => __("Unknown Payment Method", 'event_espresso')));
112
-        foreach ($payment_methods as $payment_method) {
113
-            $payment_method_names[] = array('id' => $payment_method->ID(), 'text' => $payment_method->admin_name());
114
-        }
115
-        $filters[] = EEH_Form_Fields::select_input('_payment_method', $payment_method_names, isset($this->_req_data['_payment_method']) ? $this->_req_data['_payment_method'] : 'all');
116
-        $start_date = isset($this->_req_data['payment-filter-start-date']) ? wp_strip_all_tags($this->_req_data['payment-filter-start-date']) : date('m/d/Y', strtotime('-6 months'));
117
-        $end_date = isset($this->_req_data['payment-filter-end-date']) ? wp_strip_all_tags($this->_req_data['payment-filter-end-date']) : date('m/d/Y');
118
-        ob_start();
119
-        ?>
30
+	/**
31
+	 * @param \EE_Admin_Page $admin_page
32
+	 * @return Payment_Log_Admin_List_Table
33
+	 */
34
+	public function __construct($admin_page)
35
+	{
36
+		parent::__construct($admin_page);
37
+	}
38
+
39
+
40
+
41
+	/**
42
+	 * _setup_data
43
+	 *
44
+	 * @return void
45
+	 */
46
+	protected function _setup_data()
47
+	{
48
+		$this->_data = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page);
49
+		//		if(isset($this->_req_data['status'] ) && $this->_req_data['status'] == 'trash'){
50
+		//			$this->_data = $this->_admin_page->get_trashed_questions( $this->_per_page,$this->_current_page, FALSE );
51
+		//		}else{
52
+		//			$this->_data = $this->_admin_page->get_questions( $this->_per_page,$this->_current_page, FALSE );
53
+		//		}
54
+		$this->_all_data_count = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page, true);
55
+		add_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', array($this, 'add_download_logs_checkbox'));
56
+	}
57
+
58
+
59
+
60
+	/**
61
+	 * add_download_logs_checkbox
62
+	 * adds a checkbox to the bottom of the list table, instead of at the top with the rest of the filters
63
+	 *
64
+	 * @return void
65
+	 */
66
+	public function add_download_logs_checkbox()
67
+	{
68
+		echo "<input type='submit' class='button-primary' id='download_results' name='download_results' value='" . __('Download Results', 'event_espresso') . "'>";
69
+	}
70
+
71
+
72
+
73
+	/**
74
+	 * _set_properties
75
+	 *
76
+	 * @return void
77
+	 */
78
+	protected function _set_properties()
79
+	{
80
+		$this->_wp_list_args = array(
81
+			'singular' => __('payment log', 'event_espresso'),
82
+			'plural'   => __('payment logs', 'event_espresso'),
83
+			'ajax'     => true, //for now,
84
+			'screen'   => $this->_admin_page->get_current_screen()->id,
85
+		);
86
+		$this->_columns = array(
87
+			'cb'       => '<input type="checkbox" />',
88
+			'id'       => __('ID', 'event_espresso'),
89
+			'LOG_time' => __('Time', 'event_espresso'),
90
+			'PMD_ID'   => __('Payment Method', 'event_espresso'),
91
+			'TXN_ID'   => __('Transaction ID', 'event_espresso'),
92
+		);
93
+		$this->_sortable_columns = array(
94
+			'LOG_time' => array('LOG_time' => true),
95
+		);
96
+		$this->_hidden_columns = array();
97
+	}
98
+
99
+
100
+
101
+	/**
102
+	 * _get_table_filters
103
+	 *
104
+	 * @return array
105
+	 */
106
+	protected function _get_table_filters()
107
+	{
108
+		$filters = array();
109
+		//todo we're currently using old functions here. We need to move things into the Events_Admin_Page() class as methods.
110
+		$payment_methods = EEM_Payment_Method::instance()->get_all();
111
+		$payment_method_names = array(array('id' => 'all', 'text' => __("All", 'event_espresso')), array('id' => '0', 'text' => __("Unknown Payment Method", 'event_espresso')));
112
+		foreach ($payment_methods as $payment_method) {
113
+			$payment_method_names[] = array('id' => $payment_method->ID(), 'text' => $payment_method->admin_name());
114
+		}
115
+		$filters[] = EEH_Form_Fields::select_input('_payment_method', $payment_method_names, isset($this->_req_data['_payment_method']) ? $this->_req_data['_payment_method'] : 'all');
116
+		$start_date = isset($this->_req_data['payment-filter-start-date']) ? wp_strip_all_tags($this->_req_data['payment-filter-start-date']) : date('m/d/Y', strtotime('-6 months'));
117
+		$end_date = isset($this->_req_data['payment-filter-end-date']) ? wp_strip_all_tags($this->_req_data['payment-filter-end-date']) : date('m/d/Y');
118
+		ob_start();
119
+		?>
120 120
         <label for="txn-filter-start-date"><?php _e('Display Transactions from ', 'event_espresso'); ?></label>
121 121
         <input id="payment-filter-start-date" class="datepicker" type="text" value="<?php echo $start_date; ?>" name="payment-filter-start-date" size="15"/>
122 122
         <label for="txn-filter-end-date"><?php _e(' until ', 'event_espresso'); ?></label>
123 123
         <input id="payment-filter-end-date" class="datepicker" type="text" value="<?php echo $end_date; ?>" name="payment-filter-end-date" size="15"/>
124 124
         <?php
125
-        $filters[] = ob_get_clean();
126
-        return $filters;
127
-    }
128
-
129
-
130
-
131
-    /**
132
-     * _add_view_counts
133
-     *
134
-     * @return void
135
-     */
136
-    protected function _add_view_counts()
137
-    {
138
-        $this->_views['all']['count'] = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page, true);
139
-    }
140
-
141
-
142
-
143
-    /**
144
-     * column_cb
145
-     *
146
-     * @param \EE_Change_Log $item
147
-     * @return string
148
-     */
149
-    public function column_cb($item)
150
-    {
151
-        return sprintf('<input type="checkbox" class="option_id" name="checkbox[%1$d]" value="%1$d" />', $item->ID());
152
-    }
153
-
154
-
155
-
156
-    /**
157
-     * column_id
158
-     *
159
-     * @param \EE_Change_Log $item
160
-     * @return string
161
-     */
162
-    public function column_id(EE_Change_Log $item)
163
-    {
164
-        $details_query_args = array(
165
-            'action' => 'payment_log_details',
166
-            'ID'     => $item->ID(),
167
-        );
168
-        $url = EE_Admin_Page::add_query_args_and_nonce($details_query_args, EE_PAYMENTS_ADMIN_URL);
169
-        return "<a href='$url'>{$item->ID()}</a>";
170
-    }
171
-
172
-
173
-
174
-    /**
175
-     * column_LOG_time
176
-     *
177
-     * @param \EE_Change_Log $item
178
-     * @return string
179
-     */
180
-    public function column_LOG_time(EE_Change_Log $item)
181
-    {
182
-        return $item->get_datetime('LOG_time');
183
-    }
184
-
185
-
186
-
187
-    /**
188
-     * column_PMD_ID
189
-     *
190
-     * @param \EE_Change_Log $item
191
-     * @return string
192
-     */
193
-    public function column_PMD_ID(EE_Change_Log $item)
194
-    {
195
-        if ($item->object() instanceof EE_Payment_Method) {
196
-            return $item->object()->admin_name();
197
-        } elseif ($item->object() instanceof EE_Payment && $item->object()->payment_method()) {
198
-            return $item->object()->payment_method()->admin_name();
199
-        } else {
200
-            return __("No longer exists", 'event_espresso');
201
-        }
202
-    }
203
-
204
-
205
-
206
-    /**
207
-     * column_TXN_ID
208
-     *
209
-     * @param \EE_Change_Log $item
210
-     * @return string
211
-     */
212
-    public function column_TXN_ID(EE_Change_Log $item)
213
-    {
214
-        if ($item->object() instanceof EE_Payment) {
215
-            if (EE_Registry::instance()->CAP->current_user_can('ee_read_transaction', 'espresso_transactions_view_transaction', $item->object()->TXN_ID())) {
216
-                $view_txn_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'view_transaction', 'TXN_ID' => $item->object()->TXN_ID()), TXN_ADMIN_URL);
217
-                return '<a href="'
218
-                       . $view_txn_lnk_url
219
-                       . '"  title="'
220
-                       . sprintf(esc_attr__('click to view transaction #%s', 'event_espresso'), $item->object()->TXN_ID())
221
-                       . '">'
222
-                       . sprintf(__('view txn %s', 'event_espresso'), $item->object()->TXN_ID())
223
-                       . '</a>';
224
-            }
225
-        } else {
226
-            return __("Unable to find transaction", 'event_espresso');
227
-        }
228
-    }
125
+		$filters[] = ob_get_clean();
126
+		return $filters;
127
+	}
128
+
129
+
130
+
131
+	/**
132
+	 * _add_view_counts
133
+	 *
134
+	 * @return void
135
+	 */
136
+	protected function _add_view_counts()
137
+	{
138
+		$this->_views['all']['count'] = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page, true);
139
+	}
140
+
141
+
142
+
143
+	/**
144
+	 * column_cb
145
+	 *
146
+	 * @param \EE_Change_Log $item
147
+	 * @return string
148
+	 */
149
+	public function column_cb($item)
150
+	{
151
+		return sprintf('<input type="checkbox" class="option_id" name="checkbox[%1$d]" value="%1$d" />', $item->ID());
152
+	}
153
+
154
+
155
+
156
+	/**
157
+	 * column_id
158
+	 *
159
+	 * @param \EE_Change_Log $item
160
+	 * @return string
161
+	 */
162
+	public function column_id(EE_Change_Log $item)
163
+	{
164
+		$details_query_args = array(
165
+			'action' => 'payment_log_details',
166
+			'ID'     => $item->ID(),
167
+		);
168
+		$url = EE_Admin_Page::add_query_args_and_nonce($details_query_args, EE_PAYMENTS_ADMIN_URL);
169
+		return "<a href='$url'>{$item->ID()}</a>";
170
+	}
171
+
172
+
173
+
174
+	/**
175
+	 * column_LOG_time
176
+	 *
177
+	 * @param \EE_Change_Log $item
178
+	 * @return string
179
+	 */
180
+	public function column_LOG_time(EE_Change_Log $item)
181
+	{
182
+		return $item->get_datetime('LOG_time');
183
+	}
184
+
185
+
186
+
187
+	/**
188
+	 * column_PMD_ID
189
+	 *
190
+	 * @param \EE_Change_Log $item
191
+	 * @return string
192
+	 */
193
+	public function column_PMD_ID(EE_Change_Log $item)
194
+	{
195
+		if ($item->object() instanceof EE_Payment_Method) {
196
+			return $item->object()->admin_name();
197
+		} elseif ($item->object() instanceof EE_Payment && $item->object()->payment_method()) {
198
+			return $item->object()->payment_method()->admin_name();
199
+		} else {
200
+			return __("No longer exists", 'event_espresso');
201
+		}
202
+	}
203
+
204
+
205
+
206
+	/**
207
+	 * column_TXN_ID
208
+	 *
209
+	 * @param \EE_Change_Log $item
210
+	 * @return string
211
+	 */
212
+	public function column_TXN_ID(EE_Change_Log $item)
213
+	{
214
+		if ($item->object() instanceof EE_Payment) {
215
+			if (EE_Registry::instance()->CAP->current_user_can('ee_read_transaction', 'espresso_transactions_view_transaction', $item->object()->TXN_ID())) {
216
+				$view_txn_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'view_transaction', 'TXN_ID' => $item->object()->TXN_ID()), TXN_ADMIN_URL);
217
+				return '<a href="'
218
+					   . $view_txn_lnk_url
219
+					   . '"  title="'
220
+					   . sprintf(esc_attr__('click to view transaction #%s', 'event_espresso'), $item->object()->TXN_ID())
221
+					   . '">'
222
+					   . sprintf(__('view txn %s', 'event_espresso'), $item->object()->TXN_ID())
223
+					   . '</a>';
224
+			}
225
+		} else {
226
+			return __("Unable to find transaction", 'event_espresso');
227
+		}
228
+	}
229 229
 
230 230
 
231 231
 
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php
2
-if (! defined('EVENT_ESPRESSO_VERSION')) {
2
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
3 3
     exit('NO direct script access allowed');
4 4
 }
5 5
 
@@ -65,7 +65,7 @@  discard block
 block discarded – undo
65 65
      */
66 66
     public function add_download_logs_checkbox()
67 67
     {
68
-        echo "<input type='submit' class='button-primary' id='download_results' name='download_results' value='" . __('Download Results', 'event_espresso') . "'>";
68
+        echo "<input type='submit' class='button-primary' id='download_results' name='download_results' value='".__('Download Results', 'event_espresso')."'>";
69 69
     }
70 70
 
71 71
 
Please login to merge, or discard this patch.
core/libraries/rest_api/ModelDataTranslator.php 3 patches
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -2,11 +2,9 @@
 block discarded – undo
2 2
 namespace EventEspresso\core\libraries\rest_api;
3 3
 
4 4
 use DomainException;
5
-use EE_Capabilities;
6 5
 use EE_Datetime_Field;
7 6
 use EE_Error;
8 7
 use EE_Infinite_Integer_Field;
9
-use EE_Maybe_Serialized_Simple_HTML_Field;
10 8
 use EE_Model_Field_Base;
11 9
 use EE_Serialized_Text_Field;
12 10
 use EEM_Base;
Please login to merge, or discard this patch.
Indentation   +834 added lines, -834 removed lines patch added patch discarded remove patch
@@ -12,7 +12,7 @@  discard block
 block discarded – undo
12 12
 use EEM_Base;
13 13
 
14 14
 if (! defined('EVENT_ESPRESSO_VERSION')) {
15
-    exit('No direct script access allowed');
15
+	exit('No direct script access allowed');
16 16
 }
17 17
 
18 18
 
@@ -37,837 +37,837 @@  discard block
 block discarded – undo
37 37
 class ModelDataTranslator
38 38
 {
39 39
 
40
-    /**
41
-     * We used to use -1 for infinity in the rest api, but that's ambiguous for
42
-     * fields that COULD contain -1; so we use null
43
-     */
44
-    const EE_INF_IN_REST = null;
45
-
46
-
47
-
48
-    /**
49
-     * Prepares a possible array of input values from JSON for use by the models
50
-     *
51
-     * @param EE_Model_Field_Base $field_obj
52
-     * @param mixed                $original_value_maybe_array
53
-     * @param string               $requested_version
54
-     * @param string               $timezone_string treat values as being in this timezone
55
-     * @return mixed
56
-     * @throws RestException
57
-     */
58
-    public static function prepareFieldValuesFromJson(
59
-        $field_obj,
60
-        $original_value_maybe_array,
61
-        $requested_version,
62
-        $timezone_string = 'UTC'
63
-    ) {
64
-        if (is_array($original_value_maybe_array)
65
-            && ! $field_obj instanceof EE_Serialized_Text_Field
66
-        ) {
67
-            $new_value_maybe_array = array();
68
-            foreach ($original_value_maybe_array as $array_key => $array_item) {
69
-                $new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson(
70
-                    $field_obj,
71
-                    $array_item,
72
-                    $requested_version,
73
-                    $timezone_string
74
-                );
75
-            }
76
-        } else {
77
-            $new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
78
-                $field_obj,
79
-                $original_value_maybe_array,
80
-                $requested_version,
81
-                $timezone_string
82
-            );
83
-        }
84
-        return $new_value_maybe_array;
85
-    }
86
-
87
-
88
-
89
-    /**
90
-     * Prepares an array of field values FOR use in JSON/REST API
91
-     *
92
-     * @param EE_Model_Field_Base $field_obj
93
-     * @param mixed                $original_value_maybe_array
94
-     * @param string               $request_version (eg 4.8.36)
95
-     * @return array
96
-     */
97
-    public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
98
-    {
99
-        if (is_array($original_value_maybe_array)) {
100
-            $new_value = array();
101
-            foreach ($original_value_maybe_array as $key => $value) {
102
-                $new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson($field_obj, $value, $request_version);
103
-            }
104
-        } else {
105
-            $new_value = ModelDataTranslator::prepareFieldValueForJson(
106
-                $field_obj,
107
-                $original_value_maybe_array,
108
-                $request_version
109
-            );
110
-        }
111
-        return $new_value;
112
-    }
113
-
114
-
115
-    /**
116
-     * Prepares incoming data from the json or $_REQUEST parameters for the models'
117
-     * "$query_params".
118
-     *
119
-     * @param EE_Model_Field_Base $field_obj
120
-     * @param mixed               $original_value
121
-     * @param string              $requested_version
122
-     * @param string              $timezone_string treat values as being in this timezone
123
-     * @return mixed
124
-     * @throws RestException
125
-     * @throws DomainException
126
-     * @throws EE_Error
127
-     */
128
-    public static function prepareFieldValueFromJson(
129
-        $field_obj,
130
-        $original_value,
131
-        $requested_version,
132
-        $timezone_string = 'UTC' // UTC
133
-    ) {
134
-        //check if they accidentally submitted an error value. If so throw an exception
135
-        if (is_array($original_value)
136
-            && isset($original_value['error_code'], $original_value['error_message'])) {
137
-            throw new RestException(
138
-                'rest_submitted_error_value',
139
-                sprintf(
140
-                    esc_html__(
141
-                        'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
142
-                        'event_espresso'
143
-                    ),
144
-                    $field_obj->get_name()
145
-                ),
146
-                array(
147
-                    'status' => 400,
148
-                )
149
-            );
150
-        }
151
-        //double-check for serialized PHP. We never accept serialized PHP. No way Jose.
152
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
153
-        $timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
154
-        $new_value = null;
155
-        //walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
156
-        // way Jose.
157
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
158
-        if ($field_obj instanceof EE_Infinite_Integer_Field
159
-            && in_array($original_value, array(null, ''), true)
160
-        ) {
161
-            $new_value = EE_INF;
162
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
163
-            $new_value = rest_parse_date(
164
-                self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
165
-            );
166
-            if ($new_value === false) {
167
-                throw new RestException(
168
-                    'invalid_format_for_timestamp',
169
-                    sprintf(
170
-                        esc_html__(
171
-                            'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format.  The timestamp provided (%3$s) is not that format.',
172
-                            'event_espresso'
173
-                        ),
174
-                        'RFC3339',
175
-                        'ISO8601',
176
-                        $original_value
177
-                    ),
178
-                    array(
179
-                        'status' => 400
180
-                    )
181
-                );
182
-            }
183
-        } else {
184
-            $new_value = $original_value;
185
-        }
186
-        return $new_value;
187
-    }
188
-
189
-
190
-    /**
191
-     * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
192
-     * information via details obtained from the host site.
193
-     *
194
-     * @param string            $original_timestamp
195
-     * @param EE_Datetime_Field $datetime_field
196
-     * @param                   $timezone_string
197
-     * @return string
198
-     * @throws DomainException
199
-     */
200
-    private static function getTimestampWithTimezoneOffset(
201
-        $original_timestamp,
202
-        EE_Datetime_Field $datetime_field,
203
-        $timezone_string
204
-    ) {
205
-        //already have timezone information?
206
-        if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) {
207
-            //yes, we're ignoring the timezone.
208
-            return $original_timestamp;
209
-        }
210
-        //need to append timezone
211
-        list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
212
-            $datetime_field->get_timezone_offset(
213
-                new \DateTimeZone($timezone_string),
214
-                $original_timestamp
215
-            )
216
-        );
217
-        $offset_string =
218
-            str_pad(
219
-                floor($offset_secs / HOUR_IN_SECONDS),
220
-                2,
221
-                '0',
222
-                STR_PAD_LEFT
223
-            )
224
-            . ':'
225
-            . str_pad(
226
-                ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
227
-                2,
228
-                '0',
229
-                STR_PAD_LEFT
230
-            );
231
-        return $original_timestamp . $offset_sign . $offset_string;
232
-    }
233
-
234
-
235
-
236
-    /**
237
-     * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
238
-     * think that can happen). If $data is an array, recurses into its keys and values
239
-     * @param mixed $data
240
-     * @throws RestException
241
-     * @return void
242
-     */
243
-    public static function throwExceptionIfContainsSerializedData($data)
244
-    {
245
-        if (is_array($data)) {
246
-            foreach ($data as $key => $value) {
247
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
248
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
249
-            }
250
-        } else {
251
-            if (is_serialized($data) || is_object($data)) {
252
-                throw new RestException(
253
-                    'serialized_data_submission_prohibited',
254
-                    esc_html__(
255
-                        // @codingStandardsIgnoreStart
256
-                        'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
257
-                        // @codingStandardsIgnoreEnd
258
-                        'event_espresso'
259
-                    )
260
-                );
261
-            }
262
-        }
263
-    }
264
-
265
-
266
-
267
-    /**
268
-     * determines what's going on with them timezone strings
269
-     *
270
-     * @param int $timezone_offset
271
-     * @return array
272
-     */
273
-    private static function parseTimezoneOffset($timezone_offset)
274
-    {
275
-        $first_char = substr((string)$timezone_offset, 0, 1);
276
-        if ($first_char === '+' || $first_char === '-') {
277
-            $offset_sign = $first_char;
278
-            $offset_secs = substr((string)$timezone_offset, 1);
279
-        } else {
280
-            $offset_sign = '+';
281
-            $offset_secs = $timezone_offset;
282
-        }
283
-        return array($offset_sign, $offset_secs);
284
-    }
285
-
286
-
287
-
288
-    /**
289
-     * Prepares a field's value for display in the API
290
-     *
291
-     * @param EE_Model_Field_Base $field_obj
292
-     * @param mixed                $original_value
293
-     * @param string               $requested_version
294
-     * @return mixed
295
-     */
296
-    public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
297
-    {
298
-        if ($original_value === EE_INF) {
299
-            $new_value = ModelDataTranslator::EE_INF_IN_REST;
300
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
301
-            if (is_string($original_value)) {
302
-                //did they submit a string of a unix timestamp?
303
-                if (is_numeric($original_value)) {
304
-                    $datetime_obj = new \DateTime();
305
-                    $datetime_obj->setTimestamp((int)$original_value);
306
-                } else {
307
-                    //first, check if its a MySQL timestamp in GMT
308
-                    $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
309
-                }
310
-                if (! $datetime_obj instanceof \DateTime) {
311
-                    //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
312
-                    $datetime_obj = $field_obj->prepare_for_set($original_value);
313
-                }
314
-                $original_value = $datetime_obj;
315
-            }
316
-            if ($original_value instanceof \DateTime) {
317
-                $new_value = $original_value->format('Y-m-d H:i:s');
318
-            } elseif (is_int($original_value) || is_float($original_value)) {
319
-                $new_value = date('Y-m-d H:i:s', $original_value);
320
-            } elseif($original_value === null || $original_value === '') {
321
-                $new_value = null;
322
-            } else {
323
-                //so it's not a datetime object, unix timestamp (as string or int),
324
-                //MySQL timestamp, or even a string in the field object's format. So no idea what it is
325
-                throw new \EE_Error(
326
-                    sprintf(
327
-                        esc_html__(
328
-                        // @codingStandardsIgnoreStart
329
-                            'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
330
-                            // @codingStandardsIgnoreEnd
331
-                            'event_espressso'
332
-                        ),
333
-                        $original_value,
334
-                        $field_obj->get_name(),
335
-                        $field_obj->get_model_name(),
336
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
337
-                    )
338
-                );
339
-            }
340
-            $new_value = mysql_to_rfc3339($new_value);
341
-        } else {
342
-            $new_value = $original_value;
343
-        }
344
-        //are we about to send an object? just don't. We have no good way to represent it in JSON.
345
-        // can't just check using is_object() because that missed PHP incomplete objects
346
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
347
-            $new_value = array(
348
-                'error_code' => 'php_object_not_return',
349
-                'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso')
350
-            );
351
-        }
352
-        return apply_filters(
353
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
354
-            $new_value,
355
-            $field_obj,
356
-            $original_value,
357
-            $requested_version
358
-        );
359
-    }
360
-
361
-
362
-
363
-    /**
364
-     * Prepares condition-query-parameters (like what's in where and having) from
365
-     * the format expected in the API to use in the models
366
-     *
367
-     * @param array     $inputted_query_params_of_this_type
368
-     * @param EEM_Base $model
369
-     * @param string    $requested_version
370
-     * @param boolean $writing whether this data will be written to the DB, or if we're just building a query.
371
-     *                         If we're writing to the DB, we don't expect any operators, or any logic query parameters,
372
-     *                         and we also won't accept serialized data unless the current user has unfiltered_html.
373
-     * @return array
374
-     * @throws DomainException
375
-     * @throws RestException
376
-     * @throws EE_Error
377
-     */
378
-    public static function prepareConditionsQueryParamsForModels(
379
-        $inputted_query_params_of_this_type,
380
-        EEM_Base $model,
381
-        $requested_version,
382
-        $writing = false
383
-    ) {
384
-        $query_param_for_models = array();
385
-        $valid_operators = $model->valid_operators();
386
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
387
-            $is_gmt_datetime_field = false;
388
-            $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
389
-                $query_param_key
390
-            );
391
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
392
-                $query_param_sans_stars,
393
-                $model
394
-            );
395
-            //double-check is it a *_gmt field?
396
-            if (! $field instanceof EE_Model_Field_Base
397
-                && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
398
-            ) {
399
-                //yep, take off '_gmt', and find the field
400
-                $query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
401
-                $field = ModelDataTranslator::deduceFieldFromQueryParam(
402
-                    $query_param_key,
403
-                    $model
404
-                );
405
-                $timezone = 'UTC';
406
-                $is_gmt_datetime_field = true;
407
-            } elseif ($field instanceof EE_Datetime_Field) {
408
-                //so it's not a GMT field. Set the timezone on the model to the default
409
-                $timezone = \EEH_DTT_Helper::get_valid_timezone_string();
410
-            } else {
411
-                //just keep using what's already set for the timezone
412
-                $timezone = $model->get_timezone();
413
-            }
414
-            if ($field instanceof EE_Model_Field_Base) {
415
-                if (! $writing && is_array($query_param_value)) {
416
-                    if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
417
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
418
-                            throw new RestException(
419
-                                'numerically_indexed_array_of_values_only',
420
-                                sprintf(
421
-                                    esc_html__(
422
-                                        'The array provided for the parameter "%1$s" should be numerically indexed.',
423
-                                        'event_espresso'
424
-                                    ),
425
-                                    $query_param_key
426
-                                ),
427
-                                array(
428
-                                    'status' => 400,
429
-                                )
430
-                            );
431
-                        }
432
-                    }
433
-                    //did they specify an operator?
434
-                    if (isset($query_param_value[0])
435
-                        && isset($valid_operators[$query_param_value[0]])
436
-                    ) {
437
-                        $op = $query_param_value[0];
438
-                        $translated_value = array($op);
439
-                        if (array_key_exists($op, $model->valid_in_style_operators())
440
-                            && isset($query_param_value[1])
441
-                            && ! isset($query_param_value[2])
442
-                        ) {
443
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
444
-                                $field,
445
-                                $query_param_value[1],
446
-                                $requested_version,
447
-                                $timezone
448
-                            );
449
-                        } elseif (array_key_exists($op, $model->valid_between_style_operators())
450
-                            && isset($query_param_value[1], $query_param_value[2])
451
-                            && !isset($query_param_value[3])
452
-                        ) {
453
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
454
-                                $field,
455
-                                $query_param_value[1],
456
-                                $requested_version,
457
-                                $timezone
458
-                            );
459
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
460
-                                $field,
461
-                                $query_param_value[2],
462
-                                $requested_version,
463
-                                $timezone
464
-                            );
465
-                        } elseif (array_key_exists($op, $model->valid_like_style_operators())
466
-                            && isset($query_param_value[1])
467
-                            && ! isset($query_param_value[2])
468
-                        ) {
469
-                            //we want to leave this value mostly-as-is (eg don't force it to be a float
470
-                            //or a boolean or an enum value. Leave it as-is with wildcards etc)
471
-                            //but do verify it at least doesn't have any serialized data
472
-                            ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
473
-                            $translated_value[] = $query_param_value[1];
474
-                        } elseif (array_key_exists($op, $model->valid_null_style_operators())
475
-                            && !isset($query_param_value[1])) {
476
-                            //no arguments should have been provided, so don't look for any
477
-                        } elseif (isset($query_param_value[1])
478
-                            && !isset($query_param_value[2])
479
-                            && ! array_key_exists(
480
-                                $op,
481
-                                array_merge(
482
-                                    $model->valid_in_style_operators(),
483
-                                    $model->valid_null_style_operators(),
484
-                                    $model->valid_like_style_operators(),
485
-                                    $model->valid_between_style_operators()
486
-                                )
487
-                            )
488
-                        ) {
489
-                            //it's a valid operator, but none of the exceptions. Treat it normally.
490
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
491
-                                $field,
492
-                                $query_param_value[1],
493
-                                $requested_version,
494
-                                $timezone
495
-                            );
496
-                        } else {
497
-                            //so they provided a valid operator, but wrong number of arguments
498
-                            if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
499
-                                throw new RestException(
500
-                                    'wrong_number_of_arguments',
501
-                                    sprintf(
502
-                                        esc_html__(
503
-                                            'The operator you provided, "%1$s" had the wrong number of arguments',
504
-                                            'event_espresso'
505
-                                        ),
506
-                                        $op
507
-                                    ),
508
-                                    array(
509
-                                        'status' => 400,
510
-                                    )
511
-                                );
512
-                            }
513
-                            $translated_value = null;
514
-                        }
515
-                    } else {
516
-                        //so they didn't provide a valid operator
517
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
518
-                            throw new RestException(
519
-                                'invalid_operator',
520
-                                sprintf(
521
-                                    esc_html__(
522
-                                        'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
523
-                                        'event_espresso'
524
-                                    ),
525
-                                    $query_param_key,
526
-                                    $query_param_value
527
-                                ),
528
-                                array(
529
-                                    'status' => 400,
530
-                                )
531
-                            );
532
-                        }
533
-                        //if we aren't in debug mode, then just try our best to fulfill the user's request
534
-                        $translated_value = null;
535
-                    }
536
-                } else {
537
-                    $translated_value = ModelDataTranslator::prepareFieldValueFromJson(
538
-                        $field,
539
-                        $query_param_value,
540
-                        $requested_version,
541
-                        $timezone
542
-                    );
543
-                }
544
-                if (
545
-                    (isset($query_param_for_models[$query_param_key]) && $is_gmt_datetime_field)
546
-                    ||
547
-                    $translated_value === null
548
-                ) {
549
-                    //they have already provided a non-gmt field, ignore the gmt one. That's what WP core
550
-                    //currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
551
-                    //OR we couldn't create a translated value from their input
552
-                    continue;
553
-                }
554
-                $query_param_for_models[$query_param_key] = $translated_value;
555
-            } else {
556
-                //so this param doesn't correspond to a field eh?
557
-                if ($writing) {
558
-                    //always tell API clients about invalid parameters when they're creating data. Otherwise,
559
-                    //they are probably going to create invalid data
560
-                    throw new RestException(
561
-                        'invalid_field',
562
-                        sprintf(
563
-                            esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
564
-                            $query_param_key
565
-                        )
566
-                    );
567
-                } else {
568
-                    //so it's not for a field, is it a logic query param key?
569
-                    if (in_array(
570
-                        $query_param_sans_stars,
571
-                        $model->logic_query_param_keys()
572
-                    )) {
573
-                        $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
574
-                            $query_param_value,
575
-                            $model,
576
-                            $requested_version
577
-                        );
578
-                    } elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
579
-                        //only tell API clients they got it wrong if we're in debug mode
580
-                        //otherwise try our best ot fulfill their request by ignoring this invalid data
581
-                        throw new RestException(
582
-                            'invalid_parameter',
583
-                            sprintf(
584
-                                esc_html__(
585
-                                    'You provided an invalid parameter, with key "%1$s"',
586
-                                    'event_espresso'
587
-                                ),
588
-                                $query_param_sans_stars
589
-                            ),
590
-                            array(
591
-                                'status' => 400,
592
-                            )
593
-                        );
594
-                    }
595
-                }
596
-            }
597
-        }
598
-        return $query_param_for_models;
599
-    }
600
-
601
-
602
-
603
-    /**
604
-     * Mostly checks if the last 4 characters are "_gmt", indicating its a
605
-     * gmt date field name
606
-     *
607
-     * @param string $field_name
608
-     * @return boolean
609
-     */
610
-    public static function isGmtDateFieldName($field_name)
611
-    {
612
-        return substr(
613
-            ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
614
-            -4,
615
-            4
616
-        ) === '_gmt';
617
-    }
618
-
619
-
620
-
621
-    /**
622
-     * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
623
-     *
624
-     * @param string $field_name
625
-     * @return string
626
-     */
627
-    public static function removeGmtFromFieldName($field_name)
628
-    {
629
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
630
-            return $field_name;
631
-        }
632
-        $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
633
-            $field_name
634
-        );
635
-        $query_param_sans_gmt_and_sans_stars = substr(
636
-            $query_param_sans_stars,
637
-            0,
638
-            strrpos(
639
-                $field_name,
640
-                '_gmt'
641
-            )
642
-        );
643
-        return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
644
-    }
645
-
646
-
647
-
648
-    /**
649
-     * Takes a field name from the REST API and prepares it for the model querying
650
-     *
651
-     * @param string $field_name
652
-     * @return string
653
-     */
654
-    public static function prepareFieldNameFromJson($field_name)
655
-    {
656
-        if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
657
-            return ModelDataTranslator::removeGmtFromFieldName($field_name);
658
-        }
659
-        return $field_name;
660
-    }
661
-
662
-
663
-
664
-    /**
665
-     * Takes array of field names from REST API and prepares for models
666
-     *
667
-     * @param array $field_names
668
-     * @return array of field names (possibly include model prefixes)
669
-     */
670
-    public static function prepareFieldNamesFromJson(array $field_names)
671
-    {
672
-        $new_array = array();
673
-        foreach ($field_names as $key => $field_name) {
674
-            $new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
675
-        }
676
-        return $new_array;
677
-    }
678
-
679
-
680
-
681
-    /**
682
-     * Takes array where array keys are field names (possibly with model path prefixes)
683
-     * from the REST API and prepares them for model querying
684
-     *
685
-     * @param array $field_names_as_keys
686
-     * @return array
687
-     */
688
-    public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
689
-    {
690
-        $new_array = array();
691
-        foreach ($field_names_as_keys as $field_name => $value) {
692
-            $new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value;
693
-        }
694
-        return $new_array;
695
-    }
696
-
697
-
698
-
699
-    /**
700
-     * Prepares an array of model query params for use in the REST API
701
-     *
702
-     * @param array     $model_query_params
703
-     * @param EEM_Base $model
704
-     * @param string    $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4
705
-     *                                     REST API
706
-     * @return array which can be passed into the EE4 REST API when querying a model resource
707
-     * @throws EE_Error
708
-     */
709
-    public static function prepareQueryParamsForRestApi(
710
-        array $model_query_params,
711
-        EEM_Base $model,
712
-        $requested_version = null
713
-    ) {
714
-        if ($requested_version === null) {
715
-            $requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
716
-        }
717
-        $rest_query_params = $model_query_params;
718
-        if (isset($model_query_params[0])) {
719
-            $rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
720
-                $model_query_params[0],
721
-                $model,
722
-                $requested_version
723
-            );
724
-            unset($rest_query_params[0]);
725
-        }
726
-        if (isset($model_query_params['having'])) {
727
-            $rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
728
-                $model_query_params['having'],
729
-                $model,
730
-                $requested_version
731
-            );
732
-        }
733
-        return apply_filters(
734
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
735
-            $rest_query_params,
736
-            $model_query_params,
737
-            $model,
738
-            $requested_version
739
-        );
740
-    }
741
-
742
-
743
-
744
-    /**
745
-     * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
746
-     *
747
-     * @param array     $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params
748
-     *                                                      passed into EEM_Base::get_all()
749
-     * @param EEM_Base $model
750
-     * @param string    $requested_version                  eg "4.8.36"
751
-     * @return array ready for use in the rest api query params
752
-     * @throws EE_Error
753
-     * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
754
-     *                                     (which would be really unusual)
755
-     */
756
-    public static function prepareConditionsQueryParamsForRestApi(
757
-        $inputted_query_params_of_this_type,
758
-        EEM_Base $model,
759
-        $requested_version
760
-    ) {
761
-        $query_param_for_models = array();
762
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
763
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
764
-                ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
765
-                $model
766
-            );
767
-            if ($field instanceof EE_Model_Field_Base) {
768
-                //did they specify an operator?
769
-                if (is_array($query_param_value)) {
770
-                    $op = $query_param_value[0];
771
-                    $translated_value = array($op);
772
-                    if (isset($query_param_value[1])) {
773
-                        $value = $query_param_value[1];
774
-                        $translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
775
-                            $field,
776
-                            $value,
777
-                            $requested_version
778
-                        );
779
-                    }
780
-                } else {
781
-                    $translated_value = ModelDataTranslator::prepareFieldValueForJson(
782
-                        $field,
783
-                        $query_param_value,
784
-                        $requested_version
785
-                    );
786
-                }
787
-                $query_param_for_models[$query_param_key] = $translated_value;
788
-            } else {
789
-                //so it's not for a field, assume it's a logic query param key
790
-                $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
791
-                    $query_param_value,
792
-                    $model,
793
-                    $requested_version
794
-                );
795
-            }
796
-        }
797
-        return $query_param_for_models;
798
-    }
799
-
800
-
801
-
802
-    /**
803
-     * @param $condition_query_param_key
804
-     * @return string
805
-     */
806
-    public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
807
-    {
808
-        $pos_of_star = strpos($condition_query_param_key, '*');
809
-        if ($pos_of_star === false) {
810
-            return $condition_query_param_key;
811
-        } else {
812
-            $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
813
-            return $condition_query_param_sans_star;
814
-        }
815
-    }
816
-
817
-
818
-
819
-    /**
820
-     * Takes the input parameter and finds the model field that it indicates.
821
-     *
822
-     * @param string    $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
823
-     * @param EEM_Base $model
824
-     * @return EE_Model_Field_Base
825
-     * @throws EE_Error
826
-     */
827
-    public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
828
-    {
829
-        //ok, now proceed with deducing which part is the model's name, and which is the field's name
830
-        //which will help us find the database table and column
831
-        $query_param_parts = explode('.', $query_param_name);
832
-        if (empty($query_param_parts)) {
833
-            throw new EE_Error(
834
-                sprintf(
835
-                    __(
836
-                        '_extract_column_name is empty when trying to extract column and table name from %s',
837
-                        'event_espresso'
838
-                    ),
839
-                    $query_param_name
840
-                )
841
-            );
842
-        }
843
-        $number_of_parts = count($query_param_parts);
844
-        $last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
845
-        if ($number_of_parts === 1) {
846
-            $field_name = $last_query_param_part;
847
-        } else {// $number_of_parts >= 2
848
-            //the last part is the column name, and there are only 2parts. therefore...
849
-            $field_name = $last_query_param_part;
850
-            $model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
851
-        }
852
-        try {
853
-            return $model->field_settings_for($field_name, false);
854
-        } catch (EE_Error $e) {
855
-            return null;
856
-        }
857
-    }
858
-
859
-
860
-
861
-    /**
862
-     * Returns true if $data can be easily represented in JSON.
863
-     * Basically, objects and resources can't be represented in JSON easily.
864
-     * @param mixed $data
865
-     * @return bool
866
-     */
867
-    protected static function isRepresentableInJson($data)
868
-    {
869
-        return is_scalar($data)
870
-               || is_array($data)
871
-               || is_null($data);
872
-    }
40
+	/**
41
+	 * We used to use -1 for infinity in the rest api, but that's ambiguous for
42
+	 * fields that COULD contain -1; so we use null
43
+	 */
44
+	const EE_INF_IN_REST = null;
45
+
46
+
47
+
48
+	/**
49
+	 * Prepares a possible array of input values from JSON for use by the models
50
+	 *
51
+	 * @param EE_Model_Field_Base $field_obj
52
+	 * @param mixed                $original_value_maybe_array
53
+	 * @param string               $requested_version
54
+	 * @param string               $timezone_string treat values as being in this timezone
55
+	 * @return mixed
56
+	 * @throws RestException
57
+	 */
58
+	public static function prepareFieldValuesFromJson(
59
+		$field_obj,
60
+		$original_value_maybe_array,
61
+		$requested_version,
62
+		$timezone_string = 'UTC'
63
+	) {
64
+		if (is_array($original_value_maybe_array)
65
+			&& ! $field_obj instanceof EE_Serialized_Text_Field
66
+		) {
67
+			$new_value_maybe_array = array();
68
+			foreach ($original_value_maybe_array as $array_key => $array_item) {
69
+				$new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson(
70
+					$field_obj,
71
+					$array_item,
72
+					$requested_version,
73
+					$timezone_string
74
+				);
75
+			}
76
+		} else {
77
+			$new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
78
+				$field_obj,
79
+				$original_value_maybe_array,
80
+				$requested_version,
81
+				$timezone_string
82
+			);
83
+		}
84
+		return $new_value_maybe_array;
85
+	}
86
+
87
+
88
+
89
+	/**
90
+	 * Prepares an array of field values FOR use in JSON/REST API
91
+	 *
92
+	 * @param EE_Model_Field_Base $field_obj
93
+	 * @param mixed                $original_value_maybe_array
94
+	 * @param string               $request_version (eg 4.8.36)
95
+	 * @return array
96
+	 */
97
+	public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
98
+	{
99
+		if (is_array($original_value_maybe_array)) {
100
+			$new_value = array();
101
+			foreach ($original_value_maybe_array as $key => $value) {
102
+				$new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson($field_obj, $value, $request_version);
103
+			}
104
+		} else {
105
+			$new_value = ModelDataTranslator::prepareFieldValueForJson(
106
+				$field_obj,
107
+				$original_value_maybe_array,
108
+				$request_version
109
+			);
110
+		}
111
+		return $new_value;
112
+	}
113
+
114
+
115
+	/**
116
+	 * Prepares incoming data from the json or $_REQUEST parameters for the models'
117
+	 * "$query_params".
118
+	 *
119
+	 * @param EE_Model_Field_Base $field_obj
120
+	 * @param mixed               $original_value
121
+	 * @param string              $requested_version
122
+	 * @param string              $timezone_string treat values as being in this timezone
123
+	 * @return mixed
124
+	 * @throws RestException
125
+	 * @throws DomainException
126
+	 * @throws EE_Error
127
+	 */
128
+	public static function prepareFieldValueFromJson(
129
+		$field_obj,
130
+		$original_value,
131
+		$requested_version,
132
+		$timezone_string = 'UTC' // UTC
133
+	) {
134
+		//check if they accidentally submitted an error value. If so throw an exception
135
+		if (is_array($original_value)
136
+			&& isset($original_value['error_code'], $original_value['error_message'])) {
137
+			throw new RestException(
138
+				'rest_submitted_error_value',
139
+				sprintf(
140
+					esc_html__(
141
+						'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
142
+						'event_espresso'
143
+					),
144
+					$field_obj->get_name()
145
+				),
146
+				array(
147
+					'status' => 400,
148
+				)
149
+			);
150
+		}
151
+		//double-check for serialized PHP. We never accept serialized PHP. No way Jose.
152
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
153
+		$timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
154
+		$new_value = null;
155
+		//walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
156
+		// way Jose.
157
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
158
+		if ($field_obj instanceof EE_Infinite_Integer_Field
159
+			&& in_array($original_value, array(null, ''), true)
160
+		) {
161
+			$new_value = EE_INF;
162
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
163
+			$new_value = rest_parse_date(
164
+				self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
165
+			);
166
+			if ($new_value === false) {
167
+				throw new RestException(
168
+					'invalid_format_for_timestamp',
169
+					sprintf(
170
+						esc_html__(
171
+							'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format.  The timestamp provided (%3$s) is not that format.',
172
+							'event_espresso'
173
+						),
174
+						'RFC3339',
175
+						'ISO8601',
176
+						$original_value
177
+					),
178
+					array(
179
+						'status' => 400
180
+					)
181
+				);
182
+			}
183
+		} else {
184
+			$new_value = $original_value;
185
+		}
186
+		return $new_value;
187
+	}
188
+
189
+
190
+	/**
191
+	 * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
192
+	 * information via details obtained from the host site.
193
+	 *
194
+	 * @param string            $original_timestamp
195
+	 * @param EE_Datetime_Field $datetime_field
196
+	 * @param                   $timezone_string
197
+	 * @return string
198
+	 * @throws DomainException
199
+	 */
200
+	private static function getTimestampWithTimezoneOffset(
201
+		$original_timestamp,
202
+		EE_Datetime_Field $datetime_field,
203
+		$timezone_string
204
+	) {
205
+		//already have timezone information?
206
+		if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) {
207
+			//yes, we're ignoring the timezone.
208
+			return $original_timestamp;
209
+		}
210
+		//need to append timezone
211
+		list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
212
+			$datetime_field->get_timezone_offset(
213
+				new \DateTimeZone($timezone_string),
214
+				$original_timestamp
215
+			)
216
+		);
217
+		$offset_string =
218
+			str_pad(
219
+				floor($offset_secs / HOUR_IN_SECONDS),
220
+				2,
221
+				'0',
222
+				STR_PAD_LEFT
223
+			)
224
+			. ':'
225
+			. str_pad(
226
+				($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
227
+				2,
228
+				'0',
229
+				STR_PAD_LEFT
230
+			);
231
+		return $original_timestamp . $offset_sign . $offset_string;
232
+	}
233
+
234
+
235
+
236
+	/**
237
+	 * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
238
+	 * think that can happen). If $data is an array, recurses into its keys and values
239
+	 * @param mixed $data
240
+	 * @throws RestException
241
+	 * @return void
242
+	 */
243
+	public static function throwExceptionIfContainsSerializedData($data)
244
+	{
245
+		if (is_array($data)) {
246
+			foreach ($data as $key => $value) {
247
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
248
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
249
+			}
250
+		} else {
251
+			if (is_serialized($data) || is_object($data)) {
252
+				throw new RestException(
253
+					'serialized_data_submission_prohibited',
254
+					esc_html__(
255
+						// @codingStandardsIgnoreStart
256
+						'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
257
+						// @codingStandardsIgnoreEnd
258
+						'event_espresso'
259
+					)
260
+				);
261
+			}
262
+		}
263
+	}
264
+
265
+
266
+
267
+	/**
268
+	 * determines what's going on with them timezone strings
269
+	 *
270
+	 * @param int $timezone_offset
271
+	 * @return array
272
+	 */
273
+	private static function parseTimezoneOffset($timezone_offset)
274
+	{
275
+		$first_char = substr((string)$timezone_offset, 0, 1);
276
+		if ($first_char === '+' || $first_char === '-') {
277
+			$offset_sign = $first_char;
278
+			$offset_secs = substr((string)$timezone_offset, 1);
279
+		} else {
280
+			$offset_sign = '+';
281
+			$offset_secs = $timezone_offset;
282
+		}
283
+		return array($offset_sign, $offset_secs);
284
+	}
285
+
286
+
287
+
288
+	/**
289
+	 * Prepares a field's value for display in the API
290
+	 *
291
+	 * @param EE_Model_Field_Base $field_obj
292
+	 * @param mixed                $original_value
293
+	 * @param string               $requested_version
294
+	 * @return mixed
295
+	 */
296
+	public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
297
+	{
298
+		if ($original_value === EE_INF) {
299
+			$new_value = ModelDataTranslator::EE_INF_IN_REST;
300
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
301
+			if (is_string($original_value)) {
302
+				//did they submit a string of a unix timestamp?
303
+				if (is_numeric($original_value)) {
304
+					$datetime_obj = new \DateTime();
305
+					$datetime_obj->setTimestamp((int)$original_value);
306
+				} else {
307
+					//first, check if its a MySQL timestamp in GMT
308
+					$datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
309
+				}
310
+				if (! $datetime_obj instanceof \DateTime) {
311
+					//so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
312
+					$datetime_obj = $field_obj->prepare_for_set($original_value);
313
+				}
314
+				$original_value = $datetime_obj;
315
+			}
316
+			if ($original_value instanceof \DateTime) {
317
+				$new_value = $original_value->format('Y-m-d H:i:s');
318
+			} elseif (is_int($original_value) || is_float($original_value)) {
319
+				$new_value = date('Y-m-d H:i:s', $original_value);
320
+			} elseif($original_value === null || $original_value === '') {
321
+				$new_value = null;
322
+			} else {
323
+				//so it's not a datetime object, unix timestamp (as string or int),
324
+				//MySQL timestamp, or even a string in the field object's format. So no idea what it is
325
+				throw new \EE_Error(
326
+					sprintf(
327
+						esc_html__(
328
+						// @codingStandardsIgnoreStart
329
+							'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
330
+							// @codingStandardsIgnoreEnd
331
+							'event_espressso'
332
+						),
333
+						$original_value,
334
+						$field_obj->get_name(),
335
+						$field_obj->get_model_name(),
336
+						$field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
337
+					)
338
+				);
339
+			}
340
+			$new_value = mysql_to_rfc3339($new_value);
341
+		} else {
342
+			$new_value = $original_value;
343
+		}
344
+		//are we about to send an object? just don't. We have no good way to represent it in JSON.
345
+		// can't just check using is_object() because that missed PHP incomplete objects
346
+		if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
347
+			$new_value = array(
348
+				'error_code' => 'php_object_not_return',
349
+				'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso')
350
+			);
351
+		}
352
+		return apply_filters(
353
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
354
+			$new_value,
355
+			$field_obj,
356
+			$original_value,
357
+			$requested_version
358
+		);
359
+	}
360
+
361
+
362
+
363
+	/**
364
+	 * Prepares condition-query-parameters (like what's in where and having) from
365
+	 * the format expected in the API to use in the models
366
+	 *
367
+	 * @param array     $inputted_query_params_of_this_type
368
+	 * @param EEM_Base $model
369
+	 * @param string    $requested_version
370
+	 * @param boolean $writing whether this data will be written to the DB, or if we're just building a query.
371
+	 *                         If we're writing to the DB, we don't expect any operators, or any logic query parameters,
372
+	 *                         and we also won't accept serialized data unless the current user has unfiltered_html.
373
+	 * @return array
374
+	 * @throws DomainException
375
+	 * @throws RestException
376
+	 * @throws EE_Error
377
+	 */
378
+	public static function prepareConditionsQueryParamsForModels(
379
+		$inputted_query_params_of_this_type,
380
+		EEM_Base $model,
381
+		$requested_version,
382
+		$writing = false
383
+	) {
384
+		$query_param_for_models = array();
385
+		$valid_operators = $model->valid_operators();
386
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
387
+			$is_gmt_datetime_field = false;
388
+			$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
389
+				$query_param_key
390
+			);
391
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
392
+				$query_param_sans_stars,
393
+				$model
394
+			);
395
+			//double-check is it a *_gmt field?
396
+			if (! $field instanceof EE_Model_Field_Base
397
+				&& ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
398
+			) {
399
+				//yep, take off '_gmt', and find the field
400
+				$query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
401
+				$field = ModelDataTranslator::deduceFieldFromQueryParam(
402
+					$query_param_key,
403
+					$model
404
+				);
405
+				$timezone = 'UTC';
406
+				$is_gmt_datetime_field = true;
407
+			} elseif ($field instanceof EE_Datetime_Field) {
408
+				//so it's not a GMT field. Set the timezone on the model to the default
409
+				$timezone = \EEH_DTT_Helper::get_valid_timezone_string();
410
+			} else {
411
+				//just keep using what's already set for the timezone
412
+				$timezone = $model->get_timezone();
413
+			}
414
+			if ($field instanceof EE_Model_Field_Base) {
415
+				if (! $writing && is_array($query_param_value)) {
416
+					if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
417
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
418
+							throw new RestException(
419
+								'numerically_indexed_array_of_values_only',
420
+								sprintf(
421
+									esc_html__(
422
+										'The array provided for the parameter "%1$s" should be numerically indexed.',
423
+										'event_espresso'
424
+									),
425
+									$query_param_key
426
+								),
427
+								array(
428
+									'status' => 400,
429
+								)
430
+							);
431
+						}
432
+					}
433
+					//did they specify an operator?
434
+					if (isset($query_param_value[0])
435
+						&& isset($valid_operators[$query_param_value[0]])
436
+					) {
437
+						$op = $query_param_value[0];
438
+						$translated_value = array($op);
439
+						if (array_key_exists($op, $model->valid_in_style_operators())
440
+							&& isset($query_param_value[1])
441
+							&& ! isset($query_param_value[2])
442
+						) {
443
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
444
+								$field,
445
+								$query_param_value[1],
446
+								$requested_version,
447
+								$timezone
448
+							);
449
+						} elseif (array_key_exists($op, $model->valid_between_style_operators())
450
+							&& isset($query_param_value[1], $query_param_value[2])
451
+							&& !isset($query_param_value[3])
452
+						) {
453
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
454
+								$field,
455
+								$query_param_value[1],
456
+								$requested_version,
457
+								$timezone
458
+							);
459
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
460
+								$field,
461
+								$query_param_value[2],
462
+								$requested_version,
463
+								$timezone
464
+							);
465
+						} elseif (array_key_exists($op, $model->valid_like_style_operators())
466
+							&& isset($query_param_value[1])
467
+							&& ! isset($query_param_value[2])
468
+						) {
469
+							//we want to leave this value mostly-as-is (eg don't force it to be a float
470
+							//or a boolean or an enum value. Leave it as-is with wildcards etc)
471
+							//but do verify it at least doesn't have any serialized data
472
+							ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
473
+							$translated_value[] = $query_param_value[1];
474
+						} elseif (array_key_exists($op, $model->valid_null_style_operators())
475
+							&& !isset($query_param_value[1])) {
476
+							//no arguments should have been provided, so don't look for any
477
+						} elseif (isset($query_param_value[1])
478
+							&& !isset($query_param_value[2])
479
+							&& ! array_key_exists(
480
+								$op,
481
+								array_merge(
482
+									$model->valid_in_style_operators(),
483
+									$model->valid_null_style_operators(),
484
+									$model->valid_like_style_operators(),
485
+									$model->valid_between_style_operators()
486
+								)
487
+							)
488
+						) {
489
+							//it's a valid operator, but none of the exceptions. Treat it normally.
490
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
491
+								$field,
492
+								$query_param_value[1],
493
+								$requested_version,
494
+								$timezone
495
+							);
496
+						} else {
497
+							//so they provided a valid operator, but wrong number of arguments
498
+							if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
499
+								throw new RestException(
500
+									'wrong_number_of_arguments',
501
+									sprintf(
502
+										esc_html__(
503
+											'The operator you provided, "%1$s" had the wrong number of arguments',
504
+											'event_espresso'
505
+										),
506
+										$op
507
+									),
508
+									array(
509
+										'status' => 400,
510
+									)
511
+								);
512
+							}
513
+							$translated_value = null;
514
+						}
515
+					} else {
516
+						//so they didn't provide a valid operator
517
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
518
+							throw new RestException(
519
+								'invalid_operator',
520
+								sprintf(
521
+									esc_html__(
522
+										'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
523
+										'event_espresso'
524
+									),
525
+									$query_param_key,
526
+									$query_param_value
527
+								),
528
+								array(
529
+									'status' => 400,
530
+								)
531
+							);
532
+						}
533
+						//if we aren't in debug mode, then just try our best to fulfill the user's request
534
+						$translated_value = null;
535
+					}
536
+				} else {
537
+					$translated_value = ModelDataTranslator::prepareFieldValueFromJson(
538
+						$field,
539
+						$query_param_value,
540
+						$requested_version,
541
+						$timezone
542
+					);
543
+				}
544
+				if (
545
+					(isset($query_param_for_models[$query_param_key]) && $is_gmt_datetime_field)
546
+					||
547
+					$translated_value === null
548
+				) {
549
+					//they have already provided a non-gmt field, ignore the gmt one. That's what WP core
550
+					//currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
551
+					//OR we couldn't create a translated value from their input
552
+					continue;
553
+				}
554
+				$query_param_for_models[$query_param_key] = $translated_value;
555
+			} else {
556
+				//so this param doesn't correspond to a field eh?
557
+				if ($writing) {
558
+					//always tell API clients about invalid parameters when they're creating data. Otherwise,
559
+					//they are probably going to create invalid data
560
+					throw new RestException(
561
+						'invalid_field',
562
+						sprintf(
563
+							esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
564
+							$query_param_key
565
+						)
566
+					);
567
+				} else {
568
+					//so it's not for a field, is it a logic query param key?
569
+					if (in_array(
570
+						$query_param_sans_stars,
571
+						$model->logic_query_param_keys()
572
+					)) {
573
+						$query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
574
+							$query_param_value,
575
+							$model,
576
+							$requested_version
577
+						);
578
+					} elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
579
+						//only tell API clients they got it wrong if we're in debug mode
580
+						//otherwise try our best ot fulfill their request by ignoring this invalid data
581
+						throw new RestException(
582
+							'invalid_parameter',
583
+							sprintf(
584
+								esc_html__(
585
+									'You provided an invalid parameter, with key "%1$s"',
586
+									'event_espresso'
587
+								),
588
+								$query_param_sans_stars
589
+							),
590
+							array(
591
+								'status' => 400,
592
+							)
593
+						);
594
+					}
595
+				}
596
+			}
597
+		}
598
+		return $query_param_for_models;
599
+	}
600
+
601
+
602
+
603
+	/**
604
+	 * Mostly checks if the last 4 characters are "_gmt", indicating its a
605
+	 * gmt date field name
606
+	 *
607
+	 * @param string $field_name
608
+	 * @return boolean
609
+	 */
610
+	public static function isGmtDateFieldName($field_name)
611
+	{
612
+		return substr(
613
+			ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
614
+			-4,
615
+			4
616
+		) === '_gmt';
617
+	}
618
+
619
+
620
+
621
+	/**
622
+	 * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
623
+	 *
624
+	 * @param string $field_name
625
+	 * @return string
626
+	 */
627
+	public static function removeGmtFromFieldName($field_name)
628
+	{
629
+		if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
630
+			return $field_name;
631
+		}
632
+		$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
633
+			$field_name
634
+		);
635
+		$query_param_sans_gmt_and_sans_stars = substr(
636
+			$query_param_sans_stars,
637
+			0,
638
+			strrpos(
639
+				$field_name,
640
+				'_gmt'
641
+			)
642
+		);
643
+		return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
644
+	}
645
+
646
+
647
+
648
+	/**
649
+	 * Takes a field name from the REST API and prepares it for the model querying
650
+	 *
651
+	 * @param string $field_name
652
+	 * @return string
653
+	 */
654
+	public static function prepareFieldNameFromJson($field_name)
655
+	{
656
+		if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
657
+			return ModelDataTranslator::removeGmtFromFieldName($field_name);
658
+		}
659
+		return $field_name;
660
+	}
661
+
662
+
663
+
664
+	/**
665
+	 * Takes array of field names from REST API and prepares for models
666
+	 *
667
+	 * @param array $field_names
668
+	 * @return array of field names (possibly include model prefixes)
669
+	 */
670
+	public static function prepareFieldNamesFromJson(array $field_names)
671
+	{
672
+		$new_array = array();
673
+		foreach ($field_names as $key => $field_name) {
674
+			$new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
675
+		}
676
+		return $new_array;
677
+	}
678
+
679
+
680
+
681
+	/**
682
+	 * Takes array where array keys are field names (possibly with model path prefixes)
683
+	 * from the REST API and prepares them for model querying
684
+	 *
685
+	 * @param array $field_names_as_keys
686
+	 * @return array
687
+	 */
688
+	public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
689
+	{
690
+		$new_array = array();
691
+		foreach ($field_names_as_keys as $field_name => $value) {
692
+			$new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value;
693
+		}
694
+		return $new_array;
695
+	}
696
+
697
+
698
+
699
+	/**
700
+	 * Prepares an array of model query params for use in the REST API
701
+	 *
702
+	 * @param array     $model_query_params
703
+	 * @param EEM_Base $model
704
+	 * @param string    $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4
705
+	 *                                     REST API
706
+	 * @return array which can be passed into the EE4 REST API when querying a model resource
707
+	 * @throws EE_Error
708
+	 */
709
+	public static function prepareQueryParamsForRestApi(
710
+		array $model_query_params,
711
+		EEM_Base $model,
712
+		$requested_version = null
713
+	) {
714
+		if ($requested_version === null) {
715
+			$requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
716
+		}
717
+		$rest_query_params = $model_query_params;
718
+		if (isset($model_query_params[0])) {
719
+			$rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
720
+				$model_query_params[0],
721
+				$model,
722
+				$requested_version
723
+			);
724
+			unset($rest_query_params[0]);
725
+		}
726
+		if (isset($model_query_params['having'])) {
727
+			$rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
728
+				$model_query_params['having'],
729
+				$model,
730
+				$requested_version
731
+			);
732
+		}
733
+		return apply_filters(
734
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
735
+			$rest_query_params,
736
+			$model_query_params,
737
+			$model,
738
+			$requested_version
739
+		);
740
+	}
741
+
742
+
743
+
744
+	/**
745
+	 * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
746
+	 *
747
+	 * @param array     $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params
748
+	 *                                                      passed into EEM_Base::get_all()
749
+	 * @param EEM_Base $model
750
+	 * @param string    $requested_version                  eg "4.8.36"
751
+	 * @return array ready for use in the rest api query params
752
+	 * @throws EE_Error
753
+	 * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
754
+	 *                                     (which would be really unusual)
755
+	 */
756
+	public static function prepareConditionsQueryParamsForRestApi(
757
+		$inputted_query_params_of_this_type,
758
+		EEM_Base $model,
759
+		$requested_version
760
+	) {
761
+		$query_param_for_models = array();
762
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
763
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
764
+				ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
765
+				$model
766
+			);
767
+			if ($field instanceof EE_Model_Field_Base) {
768
+				//did they specify an operator?
769
+				if (is_array($query_param_value)) {
770
+					$op = $query_param_value[0];
771
+					$translated_value = array($op);
772
+					if (isset($query_param_value[1])) {
773
+						$value = $query_param_value[1];
774
+						$translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
775
+							$field,
776
+							$value,
777
+							$requested_version
778
+						);
779
+					}
780
+				} else {
781
+					$translated_value = ModelDataTranslator::prepareFieldValueForJson(
782
+						$field,
783
+						$query_param_value,
784
+						$requested_version
785
+					);
786
+				}
787
+				$query_param_for_models[$query_param_key] = $translated_value;
788
+			} else {
789
+				//so it's not for a field, assume it's a logic query param key
790
+				$query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
791
+					$query_param_value,
792
+					$model,
793
+					$requested_version
794
+				);
795
+			}
796
+		}
797
+		return $query_param_for_models;
798
+	}
799
+
800
+
801
+
802
+	/**
803
+	 * @param $condition_query_param_key
804
+	 * @return string
805
+	 */
806
+	public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
807
+	{
808
+		$pos_of_star = strpos($condition_query_param_key, '*');
809
+		if ($pos_of_star === false) {
810
+			return $condition_query_param_key;
811
+		} else {
812
+			$condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
813
+			return $condition_query_param_sans_star;
814
+		}
815
+	}
816
+
817
+
818
+
819
+	/**
820
+	 * Takes the input parameter and finds the model field that it indicates.
821
+	 *
822
+	 * @param string    $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
823
+	 * @param EEM_Base $model
824
+	 * @return EE_Model_Field_Base
825
+	 * @throws EE_Error
826
+	 */
827
+	public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
828
+	{
829
+		//ok, now proceed with deducing which part is the model's name, and which is the field's name
830
+		//which will help us find the database table and column
831
+		$query_param_parts = explode('.', $query_param_name);
832
+		if (empty($query_param_parts)) {
833
+			throw new EE_Error(
834
+				sprintf(
835
+					__(
836
+						'_extract_column_name is empty when trying to extract column and table name from %s',
837
+						'event_espresso'
838
+					),
839
+					$query_param_name
840
+				)
841
+			);
842
+		}
843
+		$number_of_parts = count($query_param_parts);
844
+		$last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
845
+		if ($number_of_parts === 1) {
846
+			$field_name = $last_query_param_part;
847
+		} else {// $number_of_parts >= 2
848
+			//the last part is the column name, and there are only 2parts. therefore...
849
+			$field_name = $last_query_param_part;
850
+			$model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
851
+		}
852
+		try {
853
+			return $model->field_settings_for($field_name, false);
854
+		} catch (EE_Error $e) {
855
+			return null;
856
+		}
857
+	}
858
+
859
+
860
+
861
+	/**
862
+	 * Returns true if $data can be easily represented in JSON.
863
+	 * Basically, objects and resources can't be represented in JSON easily.
864
+	 * @param mixed $data
865
+	 * @return bool
866
+	 */
867
+	protected static function isRepresentableInJson($data)
868
+	{
869
+		return is_scalar($data)
870
+			   || is_array($data)
871
+			   || is_null($data);
872
+	}
873 873
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -11,7 +11,7 @@  discard block
 block discarded – undo
11 11
 use EE_Serialized_Text_Field;
12 12
 use EEM_Base;
13 13
 
14
-if (! defined('EVENT_ESPRESSO_VERSION')) {
14
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
15 15
     exit('No direct script access allowed');
16 16
 }
17 17
 
@@ -228,7 +228,7 @@  discard block
 block discarded – undo
228 228
                 '0',
229 229
                 STR_PAD_LEFT
230 230
             );
231
-        return $original_timestamp . $offset_sign . $offset_string;
231
+        return $original_timestamp.$offset_sign.$offset_string;
232 232
     }
233 233
 
234 234
 
@@ -272,10 +272,10 @@  discard block
 block discarded – undo
272 272
      */
273 273
     private static function parseTimezoneOffset($timezone_offset)
274 274
     {
275
-        $first_char = substr((string)$timezone_offset, 0, 1);
275
+        $first_char = substr((string) $timezone_offset, 0, 1);
276 276
         if ($first_char === '+' || $first_char === '-') {
277 277
             $offset_sign = $first_char;
278
-            $offset_secs = substr((string)$timezone_offset, 1);
278
+            $offset_secs = substr((string) $timezone_offset, 1);
279 279
         } else {
280 280
             $offset_sign = '+';
281 281
             $offset_secs = $timezone_offset;
@@ -302,12 +302,12 @@  discard block
 block discarded – undo
302 302
                 //did they submit a string of a unix timestamp?
303 303
                 if (is_numeric($original_value)) {
304 304
                     $datetime_obj = new \DateTime();
305
-                    $datetime_obj->setTimestamp((int)$original_value);
305
+                    $datetime_obj->setTimestamp((int) $original_value);
306 306
                 } else {
307 307
                     //first, check if its a MySQL timestamp in GMT
308 308
                     $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
309 309
                 }
310
-                if (! $datetime_obj instanceof \DateTime) {
310
+                if ( ! $datetime_obj instanceof \DateTime) {
311 311
                     //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
312 312
                     $datetime_obj = $field_obj->prepare_for_set($original_value);
313 313
                 }
@@ -317,7 +317,7 @@  discard block
 block discarded – undo
317 317
                 $new_value = $original_value->format('Y-m-d H:i:s');
318 318
             } elseif (is_int($original_value) || is_float($original_value)) {
319 319
                 $new_value = date('Y-m-d H:i:s', $original_value);
320
-            } elseif($original_value === null || $original_value === '') {
320
+            } elseif ($original_value === null || $original_value === '') {
321 321
                 $new_value = null;
322 322
             } else {
323 323
                 //so it's not a datetime object, unix timestamp (as string or int),
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
                         $original_value,
334 334
                         $field_obj->get_name(),
335 335
                         $field_obj->get_model_name(),
336
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
336
+                        $field_obj->get_time_format().' '.$field_obj->get_time_format()
337 337
                     )
338 338
                 );
339 339
             }
@@ -343,7 +343,7 @@  discard block
 block discarded – undo
343 343
         }
344 344
         //are we about to send an object? just don't. We have no good way to represent it in JSON.
345 345
         // can't just check using is_object() because that missed PHP incomplete objects
346
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
346
+        if ( ! ModelDataTranslator::isRepresentableInJson($new_value)) {
347 347
             $new_value = array(
348 348
                 'error_code' => 'php_object_not_return',
349 349
                 'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso')
@@ -393,7 +393,7 @@  discard block
 block discarded – undo
393 393
                 $model
394 394
             );
395 395
             //double-check is it a *_gmt field?
396
-            if (! $field instanceof EE_Model_Field_Base
396
+            if ( ! $field instanceof EE_Model_Field_Base
397 397
                 && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
398 398
             ) {
399 399
                 //yep, take off '_gmt', and find the field
@@ -412,8 +412,8 @@  discard block
 block discarded – undo
412 412
                 $timezone = $model->get_timezone();
413 413
             }
414 414
             if ($field instanceof EE_Model_Field_Base) {
415
-                if (! $writing && is_array($query_param_value)) {
416
-                    if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
415
+                if ( ! $writing && is_array($query_param_value)) {
416
+                    if ( ! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
417 417
                         if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
418 418
                             throw new RestException(
419 419
                                 'numerically_indexed_array_of_values_only',
@@ -448,7 +448,7 @@  discard block
 block discarded – undo
448 448
                             );
449 449
                         } elseif (array_key_exists($op, $model->valid_between_style_operators())
450 450
                             && isset($query_param_value[1], $query_param_value[2])
451
-                            && !isset($query_param_value[3])
451
+                            && ! isset($query_param_value[3])
452 452
                         ) {
453 453
                             $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
454 454
                                 $field,
@@ -472,10 +472,10 @@  discard block
 block discarded – undo
472 472
                             ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
473 473
                             $translated_value[] = $query_param_value[1];
474 474
                         } elseif (array_key_exists($op, $model->valid_null_style_operators())
475
-                            && !isset($query_param_value[1])) {
475
+                            && ! isset($query_param_value[1])) {
476 476
                             //no arguments should have been provided, so don't look for any
477 477
                         } elseif (isset($query_param_value[1])
478
-                            && !isset($query_param_value[2])
478
+                            && ! isset($query_param_value[2])
479 479
                             && ! array_key_exists(
480 480
                                 $op,
481 481
                                 array_merge(
@@ -626,7 +626,7 @@  discard block
 block discarded – undo
626 626
      */
627 627
     public static function removeGmtFromFieldName($field_name)
628 628
     {
629
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
629
+        if ( ! ModelDataTranslator::isGmtDateFieldName($field_name)) {
630 630
             return $field_name;
631 631
         }
632 632
         $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
Please login to merge, or discard this patch.
core/helpers/EEH_DTT_Helper.helper.php 1 patch
Indentation   +955 added lines, -955 removed lines patch added patch discarded remove patch
@@ -21,1015 +21,1015 @@
 block discarded – undo
21 21
 {
22 22
 
23 23
 
24
-    /**
25
-     * return the timezone set for the WP install
26
-     *
27
-     * @return string valid timezone string for PHP DateTimeZone() class
28
-     * @throws InvalidArgumentException
29
-     * @throws InvalidDataTypeException
30
-     * @throws InvalidInterfaceException
31
-     */
32
-    public static function get_timezone()
33
-    {
34
-        return EEH_DTT_Helper::get_valid_timezone_string();
35
-    }
24
+	/**
25
+	 * return the timezone set for the WP install
26
+	 *
27
+	 * @return string valid timezone string for PHP DateTimeZone() class
28
+	 * @throws InvalidArgumentException
29
+	 * @throws InvalidDataTypeException
30
+	 * @throws InvalidInterfaceException
31
+	 */
32
+	public static function get_timezone()
33
+	{
34
+		return EEH_DTT_Helper::get_valid_timezone_string();
35
+	}
36 36
 
37 37
 
38
-    /**
39
-     * get_valid_timezone_string
40
-     *    ensures that a valid timezone string is returned
41
-     *
42
-     * @param string $timezone_string
43
-     * @return string
44
-     * @throws InvalidArgumentException
45
-     * @throws InvalidDataTypeException
46
-     * @throws InvalidInterfaceException
47
-     */
48
-    public static function get_valid_timezone_string($timezone_string = '')
49
-    {
50
-        return self::getHelperAdapter()->getValidTimezoneString($timezone_string);
51
-    }
38
+	/**
39
+	 * get_valid_timezone_string
40
+	 *    ensures that a valid timezone string is returned
41
+	 *
42
+	 * @param string $timezone_string
43
+	 * @return string
44
+	 * @throws InvalidArgumentException
45
+	 * @throws InvalidDataTypeException
46
+	 * @throws InvalidInterfaceException
47
+	 */
48
+	public static function get_valid_timezone_string($timezone_string = '')
49
+	{
50
+		return self::getHelperAdapter()->getValidTimezoneString($timezone_string);
51
+	}
52 52
 
53 53
 
54
-    /**
55
-     * This only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
56
-     *
57
-     * @static
58
-     * @param  string $timezone_string Timezone string to check
59
-     * @param bool    $throw_error
60
-     * @return bool
61
-     * @throws InvalidArgumentException
62
-     * @throws InvalidDataTypeException
63
-     * @throws InvalidInterfaceException
64
-     */
65
-    public static function validate_timezone($timezone_string, $throw_error = true)
66
-    {
67
-        return self::getHelperAdapter()->validateTimezone($timezone_string, $throw_error);
68
-    }
54
+	/**
55
+	 * This only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
56
+	 *
57
+	 * @static
58
+	 * @param  string $timezone_string Timezone string to check
59
+	 * @param bool    $throw_error
60
+	 * @return bool
61
+	 * @throws InvalidArgumentException
62
+	 * @throws InvalidDataTypeException
63
+	 * @throws InvalidInterfaceException
64
+	 */
65
+	public static function validate_timezone($timezone_string, $throw_error = true)
66
+	{
67
+		return self::getHelperAdapter()->validateTimezone($timezone_string, $throw_error);
68
+	}
69 69
 
70 70
 
71
-    /**
72
-     * This returns a string that can represent the provided gmt offset in format that can be passed into
73
-     * DateTimeZone.  This is NOT a string that can be passed as a value on the WordPress timezone_string option.
74
-     *
75
-     * @param float|string $gmt_offset
76
-     * @return string
77
-     * @throws InvalidArgumentException
78
-     * @throws InvalidDataTypeException
79
-     * @throws InvalidInterfaceException
80
-     */
81
-    public static function get_timezone_string_from_gmt_offset($gmt_offset = '')
82
-    {
83
-        return self::getHelperAdapter()->getTimezoneStringFromGmtOffset($gmt_offset);
84
-    }
71
+	/**
72
+	 * This returns a string that can represent the provided gmt offset in format that can be passed into
73
+	 * DateTimeZone.  This is NOT a string that can be passed as a value on the WordPress timezone_string option.
74
+	 *
75
+	 * @param float|string $gmt_offset
76
+	 * @return string
77
+	 * @throws InvalidArgumentException
78
+	 * @throws InvalidDataTypeException
79
+	 * @throws InvalidInterfaceException
80
+	 */
81
+	public static function get_timezone_string_from_gmt_offset($gmt_offset = '')
82
+	{
83
+		return self::getHelperAdapter()->getTimezoneStringFromGmtOffset($gmt_offset);
84
+	}
85 85
 
86 86
 
87
-    /**
88
-     * Gets the site's GMT offset based on either the timezone string
89
-     * (in which case teh gmt offset will vary depending on the location's
90
-     * observance of daylight savings time) or the gmt_offset wp option
91
-     *
92
-     * @return int seconds offset
93
-     * @throws InvalidArgumentException
94
-     * @throws InvalidDataTypeException
95
-     * @throws InvalidInterfaceException
96
-     */
97
-    public static function get_site_timezone_gmt_offset()
98
-    {
99
-        return self::getHelperAdapter()->getSiteTimezoneGmtOffset();
100
-    }
87
+	/**
88
+	 * Gets the site's GMT offset based on either the timezone string
89
+	 * (in which case teh gmt offset will vary depending on the location's
90
+	 * observance of daylight savings time) or the gmt_offset wp option
91
+	 *
92
+	 * @return int seconds offset
93
+	 * @throws InvalidArgumentException
94
+	 * @throws InvalidDataTypeException
95
+	 * @throws InvalidInterfaceException
96
+	 */
97
+	public static function get_site_timezone_gmt_offset()
98
+	{
99
+		return self::getHelperAdapter()->getSiteTimezoneGmtOffset();
100
+	}
101 101
 
102 102
 
103
-    /**
104
-     * Depending on PHP version,
105
-     * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
106
-     * To get around that, for these fringe timezones we bump them to a known valid offset.
107
-     * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
108
-     *
109
-     * @deprecated 4.9.54.rc    Developers this was always meant to only be an internally used method.  This will be
110
-     *                          removed in a future version of EE.
111
-     * @param int $gmt_offset
112
-     * @return int
113
-     * @throws InvalidArgumentException
114
-     * @throws InvalidDataTypeException
115
-     * @throws InvalidInterfaceException
116
-     */
117
-    public static function adjust_invalid_gmt_offsets($gmt_offset = 0)
118
-    {
119
-        return self::getHelperAdapter()->adjustInvalidGmtOffsets($gmt_offset);
120
-    }
103
+	/**
104
+	 * Depending on PHP version,
105
+	 * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
106
+	 * To get around that, for these fringe timezones we bump them to a known valid offset.
107
+	 * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
108
+	 *
109
+	 * @deprecated 4.9.54.rc    Developers this was always meant to only be an internally used method.  This will be
110
+	 *                          removed in a future version of EE.
111
+	 * @param int $gmt_offset
112
+	 * @return int
113
+	 * @throws InvalidArgumentException
114
+	 * @throws InvalidDataTypeException
115
+	 * @throws InvalidInterfaceException
116
+	 */
117
+	public static function adjust_invalid_gmt_offsets($gmt_offset = 0)
118
+	{
119
+		return self::getHelperAdapter()->adjustInvalidGmtOffsets($gmt_offset);
120
+	}
121 121
 
122 122
 
123
-    /**
124
-     * get_timezone_string_from_abbreviations_list
125
-     *
126
-     * @deprecated 4.9.54.rc  Developers, this was never intended to be public.  This is a soft deprecation for now.
127
-     *                        If you are using this, you'll want to work out an alternate way of getting the value.
128
-     * @param int  $gmt_offset
129
-     * @param bool $coerce If true, we attempt to coerce with our adjustment table @see self::adjust_invalid_gmt_offset.
130
-     * @return string
131
-     * @throws EE_Error
132
-     * @throws InvalidArgumentException
133
-     * @throws InvalidDataTypeException
134
-     * @throws InvalidInterfaceException
135
-     */
136
-    public static function get_timezone_string_from_abbreviations_list($gmt_offset = 0, $coerce = true)
137
-    {
138
-        $gmt_offset =  (int) $gmt_offset;
139
-        /** @var array[] $abbreviations */
140
-        $abbreviations = DateTimeZone::listAbbreviations();
141
-        foreach ($abbreviations as $abbreviation) {
142
-            foreach ($abbreviation as $timezone) {
143
-                if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) {
144
-                    try {
145
-                        $offset = self::get_timezone_offset(new DateTimeZone($timezone['timezone_id']));
146
-                        if ($offset !== $gmt_offset) {
147
-                            continue;
148
-                        }
149
-                        return $timezone['timezone_id'];
150
-                    } catch (Exception $e) {
151
-                        continue;
152
-                    }
153
-                }
154
-            }
155
-        }
156
-        //if $coerce is true, let's see if we can get a timezone string after the offset is adjusted
157
-        if ($coerce === true) {
158
-            $timezone_string = self::get_timezone_string_from_abbreviations_list(
159
-                self::adjust_invalid_gmt_offsets($gmt_offset),
160
-                false
161
-            );
162
-            if ($timezone_string) {
163
-                return $timezone_string;
164
-            }
165
-        }
166
-        throw new EE_Error(
167
-            sprintf(
168
-                esc_html__(
169
-                    'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
170
-                    'event_espresso'
171
-                ),
172
-                $gmt_offset / HOUR_IN_SECONDS,
173
-                '<a href="http://www.php.net/manual/en/timezones.php">',
174
-                '</a>'
175
-            )
176
-        );
177
-    }
123
+	/**
124
+	 * get_timezone_string_from_abbreviations_list
125
+	 *
126
+	 * @deprecated 4.9.54.rc  Developers, this was never intended to be public.  This is a soft deprecation for now.
127
+	 *                        If you are using this, you'll want to work out an alternate way of getting the value.
128
+	 * @param int  $gmt_offset
129
+	 * @param bool $coerce If true, we attempt to coerce with our adjustment table @see self::adjust_invalid_gmt_offset.
130
+	 * @return string
131
+	 * @throws EE_Error
132
+	 * @throws InvalidArgumentException
133
+	 * @throws InvalidDataTypeException
134
+	 * @throws InvalidInterfaceException
135
+	 */
136
+	public static function get_timezone_string_from_abbreviations_list($gmt_offset = 0, $coerce = true)
137
+	{
138
+		$gmt_offset =  (int) $gmt_offset;
139
+		/** @var array[] $abbreviations */
140
+		$abbreviations = DateTimeZone::listAbbreviations();
141
+		foreach ($abbreviations as $abbreviation) {
142
+			foreach ($abbreviation as $timezone) {
143
+				if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) {
144
+					try {
145
+						$offset = self::get_timezone_offset(new DateTimeZone($timezone['timezone_id']));
146
+						if ($offset !== $gmt_offset) {
147
+							continue;
148
+						}
149
+						return $timezone['timezone_id'];
150
+					} catch (Exception $e) {
151
+						continue;
152
+					}
153
+				}
154
+			}
155
+		}
156
+		//if $coerce is true, let's see if we can get a timezone string after the offset is adjusted
157
+		if ($coerce === true) {
158
+			$timezone_string = self::get_timezone_string_from_abbreviations_list(
159
+				self::adjust_invalid_gmt_offsets($gmt_offset),
160
+				false
161
+			);
162
+			if ($timezone_string) {
163
+				return $timezone_string;
164
+			}
165
+		}
166
+		throw new EE_Error(
167
+			sprintf(
168
+				esc_html__(
169
+					'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
170
+					'event_espresso'
171
+				),
172
+				$gmt_offset / HOUR_IN_SECONDS,
173
+				'<a href="http://www.php.net/manual/en/timezones.php">',
174
+				'</a>'
175
+			)
176
+		);
177
+	}
178 178
 
179 179
 
180
-    /**
181
-     * Get Timezone Transitions
182
-     *
183
-     * @param DateTimeZone $date_time_zone
184
-     * @param int|null     $time
185
-     * @param bool         $first_only
186
-     * @return array
187
-     * @throws InvalidArgumentException
188
-     * @throws InvalidDataTypeException
189
-     * @throws InvalidInterfaceException
190
-     */
191
-    public static function get_timezone_transitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
192
-    {
193
-        return self::getHelperAdapter()->getTimezoneTransitions($date_time_zone, $time, $first_only);
194
-    }
180
+	/**
181
+	 * Get Timezone Transitions
182
+	 *
183
+	 * @param DateTimeZone $date_time_zone
184
+	 * @param int|null     $time
185
+	 * @param bool         $first_only
186
+	 * @return array
187
+	 * @throws InvalidArgumentException
188
+	 * @throws InvalidDataTypeException
189
+	 * @throws InvalidInterfaceException
190
+	 */
191
+	public static function get_timezone_transitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
192
+	{
193
+		return self::getHelperAdapter()->getTimezoneTransitions($date_time_zone, $time, $first_only);
194
+	}
195 195
 
196 196
 
197
-    /**
198
-     * Get Timezone Offset for given timezone object.
199
-     *
200
-     * @param DateTimeZone $date_time_zone
201
-     * @param null         $time
202
-     * @return mixed
203
-     * @throws InvalidArgumentException
204
-     * @throws InvalidDataTypeException
205
-     * @throws InvalidInterfaceException
206
-     */
207
-    public static function get_timezone_offset(DateTimeZone $date_time_zone, $time = null)
208
-    {
209
-        return self::getHelperAdapter()->getTimezoneOffset($date_time_zone, $time);
210
-    }
197
+	/**
198
+	 * Get Timezone Offset for given timezone object.
199
+	 *
200
+	 * @param DateTimeZone $date_time_zone
201
+	 * @param null         $time
202
+	 * @return mixed
203
+	 * @throws InvalidArgumentException
204
+	 * @throws InvalidDataTypeException
205
+	 * @throws InvalidInterfaceException
206
+	 */
207
+	public static function get_timezone_offset(DateTimeZone $date_time_zone, $time = null)
208
+	{
209
+		return self::getHelperAdapter()->getTimezoneOffset($date_time_zone, $time);
210
+	}
211 211
 
212 212
 
213
-    /**
214
-     * Prints a select input for the given timezone string.
215
-     * @param string $timezone_string
216
-     * @deprecatd 4.9.54.rc   Soft deprecation.  Consider using \EEH_DTT_Helper::wp_timezone_choice instead.
217
-     * @throws InvalidArgumentException
218
-     * @throws InvalidDataTypeException
219
-     * @throws InvalidInterfaceException
220
-     */
221
-    public static function timezone_select_input($timezone_string = '')
222
-    {
223
-        self::getHelperAdapter()->timezoneSelectInput($timezone_string);
224
-    }
213
+	/**
214
+	 * Prints a select input for the given timezone string.
215
+	 * @param string $timezone_string
216
+	 * @deprecatd 4.9.54.rc   Soft deprecation.  Consider using \EEH_DTT_Helper::wp_timezone_choice instead.
217
+	 * @throws InvalidArgumentException
218
+	 * @throws InvalidDataTypeException
219
+	 * @throws InvalidInterfaceException
220
+	 */
221
+	public static function timezone_select_input($timezone_string = '')
222
+	{
223
+		self::getHelperAdapter()->timezoneSelectInput($timezone_string);
224
+	}
225 225
 
226 226
 
227
-    /**
228
-     * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
229
-     * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
230
-     * the site is used.
231
-     * This is used typically when using a Unix timestamp any core WP functions that expect their specially
232
-     * computed timestamp (i.e. date_i18n() )
233
-     *
234
-     * @param int    $unix_timestamp                  if 0, then time() will be used.
235
-     * @param string $timezone_string                 timezone_string. If empty, then the current set timezone for the
236
-     *                                                site will be used.
237
-     * @return int $unix_timestamp with the offset applied for the given timezone.
238
-     * @throws InvalidArgumentException
239
-     * @throws InvalidDataTypeException
240
-     * @throws InvalidInterfaceException
241
-     */
242
-    public static function get_timestamp_with_offset($unix_timestamp = 0, $timezone_string = '')
243
-    {
244
-        return self::getHelperAdapter()->getTimestampWithOffset($unix_timestamp, $timezone_string);
245
-    }
227
+	/**
228
+	 * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
229
+	 * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
230
+	 * the site is used.
231
+	 * This is used typically when using a Unix timestamp any core WP functions that expect their specially
232
+	 * computed timestamp (i.e. date_i18n() )
233
+	 *
234
+	 * @param int    $unix_timestamp                  if 0, then time() will be used.
235
+	 * @param string $timezone_string                 timezone_string. If empty, then the current set timezone for the
236
+	 *                                                site will be used.
237
+	 * @return int $unix_timestamp with the offset applied for the given timezone.
238
+	 * @throws InvalidArgumentException
239
+	 * @throws InvalidDataTypeException
240
+	 * @throws InvalidInterfaceException
241
+	 */
242
+	public static function get_timestamp_with_offset($unix_timestamp = 0, $timezone_string = '')
243
+	{
244
+		return self::getHelperAdapter()->getTimestampWithOffset($unix_timestamp, $timezone_string);
245
+	}
246 246
 
247 247
 
248
-    /**
249
-     *    _set_date_time_field
250
-     *    modifies EE_Base_Class EE_Datetime_Field objects
251
-     *
252
-     * @param  EE_Base_Class $obj                 EE_Base_Class object
253
-     * @param    DateTime    $DateTime            PHP DateTime object
254
-     * @param  string        $datetime_field_name the datetime fieldname to be manipulated
255
-     * @return EE_Base_Class
256
-     * @throws EE_Error
257
-     */
258
-    protected static function _set_date_time_field(EE_Base_Class $obj, DateTime $DateTime, $datetime_field_name)
259
-    {
260
-        // grab current datetime format
261
-        $current_format = $obj->get_format();
262
-        // set new full timestamp format
263
-        $obj->set_date_format(EE_Datetime_Field::mysql_date_format);
264
-        $obj->set_time_format(EE_Datetime_Field::mysql_time_format);
265
-        // set the new date value using a full timestamp format so that no data is lost
266
-        $obj->set($datetime_field_name, $DateTime->format(EE_Datetime_Field::mysql_timestamp_format));
267
-        // reset datetime formats
268
-        $obj->set_date_format($current_format[0]);
269
-        $obj->set_time_format($current_format[1]);
270
-        return $obj;
271
-    }
248
+	/**
249
+	 *    _set_date_time_field
250
+	 *    modifies EE_Base_Class EE_Datetime_Field objects
251
+	 *
252
+	 * @param  EE_Base_Class $obj                 EE_Base_Class object
253
+	 * @param    DateTime    $DateTime            PHP DateTime object
254
+	 * @param  string        $datetime_field_name the datetime fieldname to be manipulated
255
+	 * @return EE_Base_Class
256
+	 * @throws EE_Error
257
+	 */
258
+	protected static function _set_date_time_field(EE_Base_Class $obj, DateTime $DateTime, $datetime_field_name)
259
+	{
260
+		// grab current datetime format
261
+		$current_format = $obj->get_format();
262
+		// set new full timestamp format
263
+		$obj->set_date_format(EE_Datetime_Field::mysql_date_format);
264
+		$obj->set_time_format(EE_Datetime_Field::mysql_time_format);
265
+		// set the new date value using a full timestamp format so that no data is lost
266
+		$obj->set($datetime_field_name, $DateTime->format(EE_Datetime_Field::mysql_timestamp_format));
267
+		// reset datetime formats
268
+		$obj->set_date_format($current_format[0]);
269
+		$obj->set_time_format($current_format[1]);
270
+		return $obj;
271
+	}
272 272
 
273 273
 
274
-    /**
275
-     *    date_time_add
276
-     *    helper for doing simple datetime calculations on a given datetime from EE_Base_Class
277
-     *    and modifying it IN the EE_Base_Class so you don't have to do anything else.
278
-     *
279
-     * @param  EE_Base_Class $obj                 EE_Base_Class object
280
-     * @param  string        $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
281
-     * @param  string        $period              what you are adding. The options are (years, months, days, hours,
282
-     *                                            minutes, seconds) defaults to years
283
-     * @param  integer       $value               what you want to increment the time by
284
-     * @return EE_Base_Class return the EE_Base_Class object so right away you can do something with it
285
-     *                                            (chaining)
286
-     * @throws EE_Error
287
-     * @throws Exception
288
-     */
289
-    public static function date_time_add(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
290
-    {
291
-        //get the raw UTC date.
292
-        $DateTime = $obj->get_DateTime_object($datetime_field_name);
293
-        $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value);
294
-        return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
295
-    }
274
+	/**
275
+	 *    date_time_add
276
+	 *    helper for doing simple datetime calculations on a given datetime from EE_Base_Class
277
+	 *    and modifying it IN the EE_Base_Class so you don't have to do anything else.
278
+	 *
279
+	 * @param  EE_Base_Class $obj                 EE_Base_Class object
280
+	 * @param  string        $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
281
+	 * @param  string        $period              what you are adding. The options are (years, months, days, hours,
282
+	 *                                            minutes, seconds) defaults to years
283
+	 * @param  integer       $value               what you want to increment the time by
284
+	 * @return EE_Base_Class return the EE_Base_Class object so right away you can do something with it
285
+	 *                                            (chaining)
286
+	 * @throws EE_Error
287
+	 * @throws Exception
288
+	 */
289
+	public static function date_time_add(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
290
+	{
291
+		//get the raw UTC date.
292
+		$DateTime = $obj->get_DateTime_object($datetime_field_name);
293
+		$DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value);
294
+		return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
295
+	}
296 296
 
297 297
 
298
-    /**
299
-     *    date_time_subtract
300
-     *    same as date_time_add except subtracting value instead of adding.
301
-     *
302
-     * @param EE_Base_Class $obj
303
-     * @param  string       $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
304
-     * @param string        $period
305
-     * @param int           $value
306
-     * @return EE_Base_Class
307
-     * @throws EE_Error
308
-     * @throws Exception
309
-     */
310
-    public static function date_time_subtract(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
311
-    {
312
-        //get the raw UTC date
313
-        $DateTime = $obj->get_DateTime_object($datetime_field_name);
314
-        $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value, '-');
315
-        return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
316
-    }
298
+	/**
299
+	 *    date_time_subtract
300
+	 *    same as date_time_add except subtracting value instead of adding.
301
+	 *
302
+	 * @param EE_Base_Class $obj
303
+	 * @param  string       $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
304
+	 * @param string        $period
305
+	 * @param int           $value
306
+	 * @return EE_Base_Class
307
+	 * @throws EE_Error
308
+	 * @throws Exception
309
+	 */
310
+	public static function date_time_subtract(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
311
+	{
312
+		//get the raw UTC date
313
+		$DateTime = $obj->get_DateTime_object($datetime_field_name);
314
+		$DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value, '-');
315
+		return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
316
+	}
317 317
 
318 318
 
319
-    /**
320
-     * Simply takes an incoming DateTime object and does calculations on it based on the incoming parameters
321
-     *
322
-     * @param  DateTime   $DateTime DateTime object
323
-     * @param  string     $period   a value to indicate what interval is being used in the calculation. The options are
324
-     *                              'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
325
-     * @param  int|string $value    What you want to increment the date by
326
-     * @param  string     $operand  What operand you wish to use for the calculation
327
-     * @return DateTime return whatever type came in.
328
-     * @throws Exception
329
-     * @throws EE_Error
330
-     */
331
-    protected static function _modify_datetime_object(DateTime $DateTime, $period = 'years', $value = 1, $operand = '+')
332
-    {
333
-        if (! $DateTime instanceof DateTime) {
334
-            throw new EE_Error(
335
-                sprintf(
336
-                    esc_html__('Expected a PHP DateTime object, but instead received %1$s', 'event_espresso'),
337
-                    print_r($DateTime, true)
338
-                )
339
-            );
340
-        }
341
-        switch ($period) {
342
-            case 'years' :
343
-                $value = 'P' . $value . 'Y';
344
-                break;
345
-            case 'months' :
346
-                $value = 'P' . $value . 'M';
347
-                break;
348
-            case 'weeks' :
349
-                $value = 'P' . $value . 'W';
350
-                break;
351
-            case 'days' :
352
-                $value = 'P' . $value . 'D';
353
-                break;
354
-            case 'hours' :
355
-                $value = 'PT' . $value . 'H';
356
-                break;
357
-            case 'minutes' :
358
-                $value = 'PT' . $value . 'M';
359
-                break;
360
-            case 'seconds' :
361
-                $value = 'PT' . $value . 'S';
362
-                break;
363
-        }
364
-        switch ($operand) {
365
-            case '+':
366
-                $DateTime->add(new DateInterval($value));
367
-                break;
368
-            case '-':
369
-                $DateTime->sub(new DateInterval($value));
370
-                break;
371
-        }
372
-        return $DateTime;
373
-    }
319
+	/**
320
+	 * Simply takes an incoming DateTime object and does calculations on it based on the incoming parameters
321
+	 *
322
+	 * @param  DateTime   $DateTime DateTime object
323
+	 * @param  string     $period   a value to indicate what interval is being used in the calculation. The options are
324
+	 *                              'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
325
+	 * @param  int|string $value    What you want to increment the date by
326
+	 * @param  string     $operand  What operand you wish to use for the calculation
327
+	 * @return DateTime return whatever type came in.
328
+	 * @throws Exception
329
+	 * @throws EE_Error
330
+	 */
331
+	protected static function _modify_datetime_object(DateTime $DateTime, $period = 'years', $value = 1, $operand = '+')
332
+	{
333
+		if (! $DateTime instanceof DateTime) {
334
+			throw new EE_Error(
335
+				sprintf(
336
+					esc_html__('Expected a PHP DateTime object, but instead received %1$s', 'event_espresso'),
337
+					print_r($DateTime, true)
338
+				)
339
+			);
340
+		}
341
+		switch ($period) {
342
+			case 'years' :
343
+				$value = 'P' . $value . 'Y';
344
+				break;
345
+			case 'months' :
346
+				$value = 'P' . $value . 'M';
347
+				break;
348
+			case 'weeks' :
349
+				$value = 'P' . $value . 'W';
350
+				break;
351
+			case 'days' :
352
+				$value = 'P' . $value . 'D';
353
+				break;
354
+			case 'hours' :
355
+				$value = 'PT' . $value . 'H';
356
+				break;
357
+			case 'minutes' :
358
+				$value = 'PT' . $value . 'M';
359
+				break;
360
+			case 'seconds' :
361
+				$value = 'PT' . $value . 'S';
362
+				break;
363
+		}
364
+		switch ($operand) {
365
+			case '+':
366
+				$DateTime->add(new DateInterval($value));
367
+				break;
368
+			case '-':
369
+				$DateTime->sub(new DateInterval($value));
370
+				break;
371
+		}
372
+		return $DateTime;
373
+	}
374 374
 
375 375
 
376
-    /**
377
-     * Simply takes an incoming Unix timestamp and does calculations on it based on the incoming parameters
378
-     *
379
-     * @param  int     $timestamp Unix timestamp
380
-     * @param  string  $period    a value to indicate what interval is being used in the calculation. The options are
381
-     *                            'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
382
-     * @param  integer $value     What you want to increment the date by
383
-     * @param  string  $operand   What operand you wish to use for the calculation
384
-     * @return int
385
-     * @throws EE_Error
386
-     */
387
-    protected static function _modify_timestamp($timestamp, $period = 'years', $value = 1, $operand = '+')
388
-    {
389
-        if (! preg_match(EE_Datetime_Field::unix_timestamp_regex, $timestamp)) {
390
-            throw new EE_Error(
391
-                sprintf(
392
-                    esc_html__('Expected a Unix timestamp, but instead received %1$s', 'event_espresso'),
393
-                    print_r($timestamp, true)
394
-                )
395
-            );
396
-        }
397
-        switch ($period) {
398
-            case 'years' :
399
-                $value = YEAR_IN_SECONDS * $value;
400
-                break;
401
-            case 'months' :
402
-                $value = YEAR_IN_SECONDS / 12 * $value;
403
-                break;
404
-            case 'weeks' :
405
-                $value = WEEK_IN_SECONDS * $value;
406
-                break;
407
-            case 'days' :
408
-                $value = DAY_IN_SECONDS * $value;
409
-                break;
410
-            case 'hours' :
411
-                $value = HOUR_IN_SECONDS * $value;
412
-                break;
413
-            case 'minutes' :
414
-                $value = MINUTE_IN_SECONDS * $value;
415
-                break;
416
-        }
417
-        switch ($operand) {
418
-            case '+':
419
-                $timestamp += $value;
420
-                break;
421
-            case '-':
422
-                $timestamp -= $value;
423
-                break;
424
-        }
425
-        return $timestamp;
426
-    }
376
+	/**
377
+	 * Simply takes an incoming Unix timestamp and does calculations on it based on the incoming parameters
378
+	 *
379
+	 * @param  int     $timestamp Unix timestamp
380
+	 * @param  string  $period    a value to indicate what interval is being used in the calculation. The options are
381
+	 *                            'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
382
+	 * @param  integer $value     What you want to increment the date by
383
+	 * @param  string  $operand   What operand you wish to use for the calculation
384
+	 * @return int
385
+	 * @throws EE_Error
386
+	 */
387
+	protected static function _modify_timestamp($timestamp, $period = 'years', $value = 1, $operand = '+')
388
+	{
389
+		if (! preg_match(EE_Datetime_Field::unix_timestamp_regex, $timestamp)) {
390
+			throw new EE_Error(
391
+				sprintf(
392
+					esc_html__('Expected a Unix timestamp, but instead received %1$s', 'event_espresso'),
393
+					print_r($timestamp, true)
394
+				)
395
+			);
396
+		}
397
+		switch ($period) {
398
+			case 'years' :
399
+				$value = YEAR_IN_SECONDS * $value;
400
+				break;
401
+			case 'months' :
402
+				$value = YEAR_IN_SECONDS / 12 * $value;
403
+				break;
404
+			case 'weeks' :
405
+				$value = WEEK_IN_SECONDS * $value;
406
+				break;
407
+			case 'days' :
408
+				$value = DAY_IN_SECONDS * $value;
409
+				break;
410
+			case 'hours' :
411
+				$value = HOUR_IN_SECONDS * $value;
412
+				break;
413
+			case 'minutes' :
414
+				$value = MINUTE_IN_SECONDS * $value;
415
+				break;
416
+		}
417
+		switch ($operand) {
418
+			case '+':
419
+				$timestamp += $value;
420
+				break;
421
+			case '-':
422
+				$timestamp -= $value;
423
+				break;
424
+		}
425
+		return $timestamp;
426
+	}
427 427
 
428 428
 
429
-    /**
430
-     * Simply takes an incoming UTC timestamp or DateTime object and does calculations on it based on the incoming
431
-     * parameters and returns the new timestamp or DateTime.
432
-     *
433
-     * @param  int | DateTime $DateTime_or_timestamp DateTime object or Unix timestamp
434
-     * @param  string         $period                a value to indicate what interval is being used in the
435
-     *                                               calculation. The options are 'years', 'months', 'days', 'hours',
436
-     *                                               'minutes', 'seconds'. Defaults to years.
437
-     * @param  integer        $value                 What you want to increment the date by
438
-     * @param  string         $operand               What operand you wish to use for the calculation
439
-     * @return mixed string|DateTime          return whatever type came in.
440
-     * @throws Exception
441
-     * @throws EE_Error
442
-     */
443
-    public static function calc_date($DateTime_or_timestamp, $period = 'years', $value = 1, $operand = '+')
444
-    {
445
-        if ($DateTime_or_timestamp instanceof DateTime) {
446
-            return EEH_DTT_Helper::_modify_datetime_object(
447
-                $DateTime_or_timestamp,
448
-                $period,
449
-                $value,
450
-                $operand
451
-            );
452
-        }
453
-        if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $DateTime_or_timestamp)) {
454
-            return EEH_DTT_Helper::_modify_timestamp(
455
-                $DateTime_or_timestamp,
456
-                $period,
457
-                $value,
458
-                $operand
459
-            );
460
-        }
461
-        //error
462
-        return $DateTime_or_timestamp;
463
-    }
429
+	/**
430
+	 * Simply takes an incoming UTC timestamp or DateTime object and does calculations on it based on the incoming
431
+	 * parameters and returns the new timestamp or DateTime.
432
+	 *
433
+	 * @param  int | DateTime $DateTime_or_timestamp DateTime object or Unix timestamp
434
+	 * @param  string         $period                a value to indicate what interval is being used in the
435
+	 *                                               calculation. The options are 'years', 'months', 'days', 'hours',
436
+	 *                                               'minutes', 'seconds'. Defaults to years.
437
+	 * @param  integer        $value                 What you want to increment the date by
438
+	 * @param  string         $operand               What operand you wish to use for the calculation
439
+	 * @return mixed string|DateTime          return whatever type came in.
440
+	 * @throws Exception
441
+	 * @throws EE_Error
442
+	 */
443
+	public static function calc_date($DateTime_or_timestamp, $period = 'years', $value = 1, $operand = '+')
444
+	{
445
+		if ($DateTime_or_timestamp instanceof DateTime) {
446
+			return EEH_DTT_Helper::_modify_datetime_object(
447
+				$DateTime_or_timestamp,
448
+				$period,
449
+				$value,
450
+				$operand
451
+			);
452
+		}
453
+		if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $DateTime_or_timestamp)) {
454
+			return EEH_DTT_Helper::_modify_timestamp(
455
+				$DateTime_or_timestamp,
456
+				$period,
457
+				$value,
458
+				$operand
459
+			);
460
+		}
461
+		//error
462
+		return $DateTime_or_timestamp;
463
+	}
464 464
 
465 465
 
466
-    /**
467
-     * The purpose of this helper method is to receive an incoming format string in php date/time format
468
-     * and spit out the js and moment.js equivalent formats.
469
-     * Note, if no format string is given, then it is assumed the user wants what is set for WP.
470
-     * Note, js date and time formats are those used by the jquery-ui datepicker and the jquery-ui date-
471
-     * time picker.
472
-     *
473
-     * @see http://stackoverflow.com/posts/16725290/ for the code inspiration.
474
-     * @param string $date_format_string
475
-     * @param string $time_format_string
476
-     * @return array
477
-     *              array(
478
-     *              'js' => array (
479
-     *              'date' => //date format
480
-     *              'time' => //time format
481
-     *              ),
482
-     *              'moment' => //date and time format.
483
-     *              )
484
-     */
485
-    public static function convert_php_to_js_and_moment_date_formats(
486
-        $date_format_string = null,
487
-        $time_format_string = null
488
-    ) {
489
-        if ($date_format_string === null) {
490
-            $date_format_string = (string) get_option('date_format');
491
-        }
492
-        if ($time_format_string === null) {
493
-            $time_format_string = (string) get_option('time_format');
494
-        }
495
-        $date_format = self::_php_to_js_moment_converter($date_format_string);
496
-        $time_format = self::_php_to_js_moment_converter($time_format_string);
497
-        return array(
498
-            'js'     => array(
499
-                'date' => $date_format['js'],
500
-                'time' => $time_format['js'],
501
-            ),
502
-            'moment' => $date_format['moment'] . ' ' . $time_format['moment'],
503
-        );
504
-    }
466
+	/**
467
+	 * The purpose of this helper method is to receive an incoming format string in php date/time format
468
+	 * and spit out the js and moment.js equivalent formats.
469
+	 * Note, if no format string is given, then it is assumed the user wants what is set for WP.
470
+	 * Note, js date and time formats are those used by the jquery-ui datepicker and the jquery-ui date-
471
+	 * time picker.
472
+	 *
473
+	 * @see http://stackoverflow.com/posts/16725290/ for the code inspiration.
474
+	 * @param string $date_format_string
475
+	 * @param string $time_format_string
476
+	 * @return array
477
+	 *              array(
478
+	 *              'js' => array (
479
+	 *              'date' => //date format
480
+	 *              'time' => //time format
481
+	 *              ),
482
+	 *              'moment' => //date and time format.
483
+	 *              )
484
+	 */
485
+	public static function convert_php_to_js_and_moment_date_formats(
486
+		$date_format_string = null,
487
+		$time_format_string = null
488
+	) {
489
+		if ($date_format_string === null) {
490
+			$date_format_string = (string) get_option('date_format');
491
+		}
492
+		if ($time_format_string === null) {
493
+			$time_format_string = (string) get_option('time_format');
494
+		}
495
+		$date_format = self::_php_to_js_moment_converter($date_format_string);
496
+		$time_format = self::_php_to_js_moment_converter($time_format_string);
497
+		return array(
498
+			'js'     => array(
499
+				'date' => $date_format['js'],
500
+				'time' => $time_format['js'],
501
+			),
502
+			'moment' => $date_format['moment'] . ' ' . $time_format['moment'],
503
+		);
504
+	}
505 505
 
506 506
 
507
-    /**
508
-     * This converts incoming format string into js and moment variations.
509
-     *
510
-     * @param string $format_string incoming php format string
511
-     * @return array js and moment formats.
512
-     */
513
-    protected static function _php_to_js_moment_converter($format_string)
514
-    {
515
-        /**
516
-         * This is a map of symbols for formats.
517
-         * The index is the php symbol, the equivalent values are in the array.
518
-         *
519
-         * @var array
520
-         */
521
-        $symbols_map          = array(
522
-            // Day
523
-            //01
524
-            'd' => array(
525
-                'js'     => 'dd',
526
-                'moment' => 'DD',
527
-            ),
528
-            //Mon
529
-            'D' => array(
530
-                'js'     => 'D',
531
-                'moment' => 'ddd',
532
-            ),
533
-            //1,2,...31
534
-            'j' => array(
535
-                'js'     => 'd',
536
-                'moment' => 'D',
537
-            ),
538
-            //Monday
539
-            'l' => array(
540
-                'js'     => 'DD',
541
-                'moment' => 'dddd',
542
-            ),
543
-            //ISO numeric representation of the day of the week (1-6)
544
-            'N' => array(
545
-                'js'     => '',
546
-                'moment' => 'E',
547
-            ),
548
-            //st,nd.rd
549
-            'S' => array(
550
-                'js'     => '',
551
-                'moment' => 'o',
552
-            ),
553
-            //numeric representation of day of week (0-6)
554
-            'w' => array(
555
-                'js'     => '',
556
-                'moment' => 'd',
557
-            ),
558
-            //day of year starting from 0 (0-365)
559
-            'z' => array(
560
-                'js'     => 'o',
561
-                'moment' => 'DDD' //note moment does not start with 0 so will need to modify by subtracting 1
562
-            ),
563
-            // Week
564
-            //ISO-8601 week number of year (weeks starting on monday)
565
-            'W' => array(
566
-                'js'     => '',
567
-                'moment' => 'w',
568
-            ),
569
-            // Month
570
-            // January...December
571
-            'F' => array(
572
-                'js'     => 'MM',
573
-                'moment' => 'MMMM',
574
-            ),
575
-            //01...12
576
-            'm' => array(
577
-                'js'     => 'mm',
578
-                'moment' => 'MM',
579
-            ),
580
-            //Jan...Dec
581
-            'M' => array(
582
-                'js'     => 'M',
583
-                'moment' => 'MMM',
584
-            ),
585
-            //1-12
586
-            'n' => array(
587
-                'js'     => 'm',
588
-                'moment' => 'M',
589
-            ),
590
-            //number of days in given month
591
-            't' => array(
592
-                'js'     => '',
593
-                'moment' => '',
594
-            ),
595
-            // Year
596
-            //whether leap year or not 1/0
597
-            'L' => array(
598
-                'js'     => '',
599
-                'moment' => '',
600
-            ),
601
-            //ISO-8601 year number
602
-            'o' => array(
603
-                'js'     => '',
604
-                'moment' => 'GGGG',
605
-            ),
606
-            //1999...2003
607
-            'Y' => array(
608
-                'js'     => 'yy',
609
-                'moment' => 'YYYY',
610
-            ),
611
-            //99...03
612
-            'y' => array(
613
-                'js'     => 'y',
614
-                'moment' => 'YY',
615
-            ),
616
-            // Time
617
-            // am/pm
618
-            'a' => array(
619
-                'js'     => 'tt',
620
-                'moment' => 'a',
621
-            ),
622
-            // AM/PM
623
-            'A' => array(
624
-                'js'     => 'TT',
625
-                'moment' => 'A',
626
-            ),
627
-            // Swatch Internet Time?!?
628
-            'B' => array(
629
-                'js'     => '',
630
-                'moment' => '',
631
-            ),
632
-            //1...12
633
-            'g' => array(
634
-                'js'     => 'h',
635
-                'moment' => 'h',
636
-            ),
637
-            //0...23
638
-            'G' => array(
639
-                'js'     => 'H',
640
-                'moment' => 'H',
641
-            ),
642
-            //01...12
643
-            'h' => array(
644
-                'js'     => 'hh',
645
-                'moment' => 'hh',
646
-            ),
647
-            //00...23
648
-            'H' => array(
649
-                'js'     => 'HH',
650
-                'moment' => 'HH',
651
-            ),
652
-            //00..59
653
-            'i' => array(
654
-                'js'     => 'mm',
655
-                'moment' => 'mm',
656
-            ),
657
-            //seconds... 00...59
658
-            's' => array(
659
-                'js'     => 'ss',
660
-                'moment' => 'ss',
661
-            ),
662
-            //microseconds
663
-            'u' => array(
664
-                'js'     => '',
665
-                'moment' => '',
666
-            ),
667
-        );
668
-        $jquery_ui_format     = '';
669
-        $moment_format        = '';
670
-        $escaping             = false;
671
-        $format_string_length = strlen($format_string);
672
-        for ($i = 0; $i < $format_string_length; $i++) {
673
-            $char = $format_string[ $i ];
674
-            if ($char === '\\') { // PHP date format escaping character
675
-                $i++;
676
-                if ($escaping) {
677
-                    $jquery_ui_format .= $format_string[ $i ];
678
-                    $moment_format    .= $format_string[ $i ];
679
-                } else {
680
-                    $jquery_ui_format .= '\'' . $format_string[ $i ];
681
-                    $moment_format    .= $format_string[ $i ];
682
-                }
683
-                $escaping = true;
684
-            } else {
685
-                if ($escaping) {
686
-                    $jquery_ui_format .= "'";
687
-                    $moment_format    .= "'";
688
-                    $escaping         = false;
689
-                }
690
-                if (isset($symbols_map[ $char ])) {
691
-                    $jquery_ui_format .= $symbols_map[ $char ]['js'];
692
-                    $moment_format    .= $symbols_map[ $char ]['moment'];
693
-                } else {
694
-                    $jquery_ui_format .= $char;
695
-                    $moment_format    .= $char;
696
-                }
697
-            }
698
-        }
699
-        return array('js' => $jquery_ui_format, 'moment' => $moment_format);
700
-    }
507
+	/**
508
+	 * This converts incoming format string into js and moment variations.
509
+	 *
510
+	 * @param string $format_string incoming php format string
511
+	 * @return array js and moment formats.
512
+	 */
513
+	protected static function _php_to_js_moment_converter($format_string)
514
+	{
515
+		/**
516
+		 * This is a map of symbols for formats.
517
+		 * The index is the php symbol, the equivalent values are in the array.
518
+		 *
519
+		 * @var array
520
+		 */
521
+		$symbols_map          = array(
522
+			// Day
523
+			//01
524
+			'd' => array(
525
+				'js'     => 'dd',
526
+				'moment' => 'DD',
527
+			),
528
+			//Mon
529
+			'D' => array(
530
+				'js'     => 'D',
531
+				'moment' => 'ddd',
532
+			),
533
+			//1,2,...31
534
+			'j' => array(
535
+				'js'     => 'd',
536
+				'moment' => 'D',
537
+			),
538
+			//Monday
539
+			'l' => array(
540
+				'js'     => 'DD',
541
+				'moment' => 'dddd',
542
+			),
543
+			//ISO numeric representation of the day of the week (1-6)
544
+			'N' => array(
545
+				'js'     => '',
546
+				'moment' => 'E',
547
+			),
548
+			//st,nd.rd
549
+			'S' => array(
550
+				'js'     => '',
551
+				'moment' => 'o',
552
+			),
553
+			//numeric representation of day of week (0-6)
554
+			'w' => array(
555
+				'js'     => '',
556
+				'moment' => 'd',
557
+			),
558
+			//day of year starting from 0 (0-365)
559
+			'z' => array(
560
+				'js'     => 'o',
561
+				'moment' => 'DDD' //note moment does not start with 0 so will need to modify by subtracting 1
562
+			),
563
+			// Week
564
+			//ISO-8601 week number of year (weeks starting on monday)
565
+			'W' => array(
566
+				'js'     => '',
567
+				'moment' => 'w',
568
+			),
569
+			// Month
570
+			// January...December
571
+			'F' => array(
572
+				'js'     => 'MM',
573
+				'moment' => 'MMMM',
574
+			),
575
+			//01...12
576
+			'm' => array(
577
+				'js'     => 'mm',
578
+				'moment' => 'MM',
579
+			),
580
+			//Jan...Dec
581
+			'M' => array(
582
+				'js'     => 'M',
583
+				'moment' => 'MMM',
584
+			),
585
+			//1-12
586
+			'n' => array(
587
+				'js'     => 'm',
588
+				'moment' => 'M',
589
+			),
590
+			//number of days in given month
591
+			't' => array(
592
+				'js'     => '',
593
+				'moment' => '',
594
+			),
595
+			// Year
596
+			//whether leap year or not 1/0
597
+			'L' => array(
598
+				'js'     => '',
599
+				'moment' => '',
600
+			),
601
+			//ISO-8601 year number
602
+			'o' => array(
603
+				'js'     => '',
604
+				'moment' => 'GGGG',
605
+			),
606
+			//1999...2003
607
+			'Y' => array(
608
+				'js'     => 'yy',
609
+				'moment' => 'YYYY',
610
+			),
611
+			//99...03
612
+			'y' => array(
613
+				'js'     => 'y',
614
+				'moment' => 'YY',
615
+			),
616
+			// Time
617
+			// am/pm
618
+			'a' => array(
619
+				'js'     => 'tt',
620
+				'moment' => 'a',
621
+			),
622
+			// AM/PM
623
+			'A' => array(
624
+				'js'     => 'TT',
625
+				'moment' => 'A',
626
+			),
627
+			// Swatch Internet Time?!?
628
+			'B' => array(
629
+				'js'     => '',
630
+				'moment' => '',
631
+			),
632
+			//1...12
633
+			'g' => array(
634
+				'js'     => 'h',
635
+				'moment' => 'h',
636
+			),
637
+			//0...23
638
+			'G' => array(
639
+				'js'     => 'H',
640
+				'moment' => 'H',
641
+			),
642
+			//01...12
643
+			'h' => array(
644
+				'js'     => 'hh',
645
+				'moment' => 'hh',
646
+			),
647
+			//00...23
648
+			'H' => array(
649
+				'js'     => 'HH',
650
+				'moment' => 'HH',
651
+			),
652
+			//00..59
653
+			'i' => array(
654
+				'js'     => 'mm',
655
+				'moment' => 'mm',
656
+			),
657
+			//seconds... 00...59
658
+			's' => array(
659
+				'js'     => 'ss',
660
+				'moment' => 'ss',
661
+			),
662
+			//microseconds
663
+			'u' => array(
664
+				'js'     => '',
665
+				'moment' => '',
666
+			),
667
+		);
668
+		$jquery_ui_format     = '';
669
+		$moment_format        = '';
670
+		$escaping             = false;
671
+		$format_string_length = strlen($format_string);
672
+		for ($i = 0; $i < $format_string_length; $i++) {
673
+			$char = $format_string[ $i ];
674
+			if ($char === '\\') { // PHP date format escaping character
675
+				$i++;
676
+				if ($escaping) {
677
+					$jquery_ui_format .= $format_string[ $i ];
678
+					$moment_format    .= $format_string[ $i ];
679
+				} else {
680
+					$jquery_ui_format .= '\'' . $format_string[ $i ];
681
+					$moment_format    .= $format_string[ $i ];
682
+				}
683
+				$escaping = true;
684
+			} else {
685
+				if ($escaping) {
686
+					$jquery_ui_format .= "'";
687
+					$moment_format    .= "'";
688
+					$escaping         = false;
689
+				}
690
+				if (isset($symbols_map[ $char ])) {
691
+					$jquery_ui_format .= $symbols_map[ $char ]['js'];
692
+					$moment_format    .= $symbols_map[ $char ]['moment'];
693
+				} else {
694
+					$jquery_ui_format .= $char;
695
+					$moment_format    .= $char;
696
+				}
697
+			}
698
+		}
699
+		return array('js' => $jquery_ui_format, 'moment' => $moment_format);
700
+	}
701 701
 
702 702
 
703
-    /**
704
-     * This takes an incoming format string and validates it to ensure it will work fine with PHP.
705
-     *
706
-     * @param string $format_string   Incoming format string for php date().
707
-     * @return mixed bool|array  If all is okay then TRUE is returned.  Otherwise an array of validation
708
-     *                                errors is returned.  So for client code calling, check for is_array() to
709
-     *                                indicate failed validations.
710
-     */
711
-    public static function validate_format_string($format_string)
712
-    {
713
-        $error_msg = array();
714
-        //time format checks
715
-        switch (true) {
716
-            case   strpos($format_string, 'h') !== false  :
717
-            case   strpos($format_string, 'g') !== false :
718
-                /**
719
-                 * if the time string has a lowercase 'h' which == 12 hour time format and there
720
-                 * is not any ante meridiem format ('a' or 'A').  Then throw an error because its
721
-                 * too ambiguous and PHP won't be able to figure out whether 1 = 1pm or 1am.
722
-                 */
723
-                if (stripos($format_string, 'A') === false) {
724
-                    $error_msg[] = esc_html__(
725
-                        'There is a  time format for 12 hour time but no  "a" or "A" to indicate am/pm.  Without this distinction, PHP is unable to determine if a "1" for the hour value equals "1pm" or "1am".',
726
-                        'event_espresso'
727
-                    );
728
-                }
729
-                break;
730
-        }
731
-        return empty($error_msg) ? true : $error_msg;
732
-    }
703
+	/**
704
+	 * This takes an incoming format string and validates it to ensure it will work fine with PHP.
705
+	 *
706
+	 * @param string $format_string   Incoming format string for php date().
707
+	 * @return mixed bool|array  If all is okay then TRUE is returned.  Otherwise an array of validation
708
+	 *                                errors is returned.  So for client code calling, check for is_array() to
709
+	 *                                indicate failed validations.
710
+	 */
711
+	public static function validate_format_string($format_string)
712
+	{
713
+		$error_msg = array();
714
+		//time format checks
715
+		switch (true) {
716
+			case   strpos($format_string, 'h') !== false  :
717
+			case   strpos($format_string, 'g') !== false :
718
+				/**
719
+				 * if the time string has a lowercase 'h' which == 12 hour time format and there
720
+				 * is not any ante meridiem format ('a' or 'A').  Then throw an error because its
721
+				 * too ambiguous and PHP won't be able to figure out whether 1 = 1pm or 1am.
722
+				 */
723
+				if (stripos($format_string, 'A') === false) {
724
+					$error_msg[] = esc_html__(
725
+						'There is a  time format for 12 hour time but no  "a" or "A" to indicate am/pm.  Without this distinction, PHP is unable to determine if a "1" for the hour value equals "1pm" or "1am".',
726
+						'event_espresso'
727
+					);
728
+				}
729
+				break;
730
+		}
731
+		return empty($error_msg) ? true : $error_msg;
732
+	}
733 733
 
734 734
 
735
-    /**
736
-     *     If the the first date starts at midnight on one day, and the next date ends at midnight on the
737
-     *     very next day then this method will return true.
738
-     *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-16 00:00:00 then this function will return true.
739
-     *    If $date_1 = 2015-12-15 03:00:00 and $date_2 = 2015-12_16 03:00:00 then this function will return false.
740
-     *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-15 00:00:00 then this function will return true.
741
-     *
742
-     * @param mixed $date_1
743
-     * @param mixed $date_2
744
-     * @return bool
745
-     */
746
-    public static function dates_represent_one_24_hour_date($date_1, $date_2)
747
-    {
735
+	/**
736
+	 *     If the the first date starts at midnight on one day, and the next date ends at midnight on the
737
+	 *     very next day then this method will return true.
738
+	 *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-16 00:00:00 then this function will return true.
739
+	 *    If $date_1 = 2015-12-15 03:00:00 and $date_2 = 2015-12_16 03:00:00 then this function will return false.
740
+	 *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-15 00:00:00 then this function will return true.
741
+	 *
742
+	 * @param mixed $date_1
743
+	 * @param mixed $date_2
744
+	 * @return bool
745
+	 */
746
+	public static function dates_represent_one_24_hour_date($date_1, $date_2)
747
+	{
748 748
 
749
-        if (
750
-            (! $date_1 instanceof DateTime || ! $date_2 instanceof DateTime)
751
-            || ($date_1->format(EE_Datetime_Field::mysql_time_format) !== '00:00:00'
752
-                || $date_2->format(
753
-                    EE_Datetime_Field::mysql_time_format
754
-                ) !== '00:00:00')
755
-        ) {
756
-            return false;
757
-        }
758
-        return $date_2->format('U') - $date_1->format('U') === 86400;
759
-    }
749
+		if (
750
+			(! $date_1 instanceof DateTime || ! $date_2 instanceof DateTime)
751
+			|| ($date_1->format(EE_Datetime_Field::mysql_time_format) !== '00:00:00'
752
+				|| $date_2->format(
753
+					EE_Datetime_Field::mysql_time_format
754
+				) !== '00:00:00')
755
+		) {
756
+			return false;
757
+		}
758
+		return $date_2->format('U') - $date_1->format('U') === 86400;
759
+	}
760 760
 
761 761
 
762
-    /**
763
-     * This returns the appropriate query interval string that can be used in sql queries involving mysql Date
764
-     * Functions.
765
-     *
766
-     * @param string $timezone_string    A timezone string in a valid format to instantiate a DateTimeZone object.
767
-     * @param string $field_for_interval The Database field that is the interval is applied to in the query.
768
-     * @return string
769
-     */
770
-    public static function get_sql_query_interval_for_offset($timezone_string, $field_for_interval)
771
-    {
772
-        try {
773
-            /** need to account for timezone offset on the selects */
774
-            $DateTimeZone = new DateTimeZone($timezone_string);
775
-        } catch (Exception $e) {
776
-            $DateTimeZone = null;
777
-        }
778
-        /**
779
-         * Note get_option( 'gmt_offset') returns a value in hours, whereas DateTimeZone::getOffset returns values in seconds.
780
-         * Hence we do the calc for DateTimeZone::getOffset.
781
-         */
782
-        $offset         = $DateTimeZone instanceof DateTimeZone
783
-            ? $DateTimeZone->getOffset(new DateTime('now')) / HOUR_IN_SECONDS
784
-            : (float) get_option('gmt_offset');
785
-        $query_interval = $offset < 0
786
-            ? 'DATE_SUB(' . $field_for_interval . ', INTERVAL ' . $offset * -1 . ' HOUR)'
787
-            : 'DATE_ADD(' . $field_for_interval . ', INTERVAL ' . $offset . ' HOUR)';
788
-        return $query_interval;
789
-    }
762
+	/**
763
+	 * This returns the appropriate query interval string that can be used in sql queries involving mysql Date
764
+	 * Functions.
765
+	 *
766
+	 * @param string $timezone_string    A timezone string in a valid format to instantiate a DateTimeZone object.
767
+	 * @param string $field_for_interval The Database field that is the interval is applied to in the query.
768
+	 * @return string
769
+	 */
770
+	public static function get_sql_query_interval_for_offset($timezone_string, $field_for_interval)
771
+	{
772
+		try {
773
+			/** need to account for timezone offset on the selects */
774
+			$DateTimeZone = new DateTimeZone($timezone_string);
775
+		} catch (Exception $e) {
776
+			$DateTimeZone = null;
777
+		}
778
+		/**
779
+		 * Note get_option( 'gmt_offset') returns a value in hours, whereas DateTimeZone::getOffset returns values in seconds.
780
+		 * Hence we do the calc for DateTimeZone::getOffset.
781
+		 */
782
+		$offset         = $DateTimeZone instanceof DateTimeZone
783
+			? $DateTimeZone->getOffset(new DateTime('now')) / HOUR_IN_SECONDS
784
+			: (float) get_option('gmt_offset');
785
+		$query_interval = $offset < 0
786
+			? 'DATE_SUB(' . $field_for_interval . ', INTERVAL ' . $offset * -1 . ' HOUR)'
787
+			: 'DATE_ADD(' . $field_for_interval . ', INTERVAL ' . $offset . ' HOUR)';
788
+		return $query_interval;
789
+	}
790 790
 
791 791
 
792
-    /**
793
-     * Retrieves the site's default timezone and returns it formatted so it's ready for display
794
-     * to users. If you want to customize how its displayed feel free to fetch the 'timezone_string'
795
-     * and 'gmt_offset' WordPress options directly; or use the filter
796
-     * FHEE__EEH_DTT_Helper__get_timezone_string_for_display
797
-     * (although note that we remove any HTML that may be added)
798
-     *
799
-     * @return string
800
-     */
801
-    public static function get_timezone_string_for_display()
802
-    {
803
-        $pretty_timezone = apply_filters('FHEE__EEH_DTT_Helper__get_timezone_string_for_display', '');
804
-        if (! empty($pretty_timezone)) {
805
-            return esc_html($pretty_timezone);
806
-        }
807
-        $timezone_string = get_option('timezone_string');
808
-        if ($timezone_string) {
809
-            static $mo_loaded = false;
810
-            // Load translations for continents and cities just like wp_timezone_choice does
811
-            if (! $mo_loaded) {
812
-                $locale = get_locale();
813
-                $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
814
-                load_textdomain('continents-cities', $mofile);
815
-                $mo_loaded = true;
816
-            }
817
-            //well that was easy.
818
-            $parts = explode('/', $timezone_string);
819
-            //remove the continent
820
-            unset($parts[0]);
821
-            $t_parts = array();
822
-            foreach ($parts as $part) {
823
-                $t_parts[] = translate(str_replace('_', ' ', $part), 'continents-cities');
824
-            }
825
-            return implode(' - ', $t_parts);
826
-        }
827
-        //they haven't set the timezone string, so let's return a string like "UTC+1"
828
-        $gmt_offset = get_option('gmt_offset');
829
-        $prefix     = (int) $gmt_offset >= 0 ? '+' : '';
830
-        $parts      = explode('.', (string) $gmt_offset);
831
-        if (count($parts) === 1) {
832
-            $parts[1] = '00';
833
-        } else {
834
-            //convert the part after the decimal, eg "5" (from x.5) or "25" (from x.25)
835
-            //to minutes, eg 30 or 15, respectively
836
-            $hour_fraction = (float) ('0.' . $parts[1]);
837
-            $parts[1]      = (string) $hour_fraction * 60;
838
-        }
839
-        return sprintf(__('UTC%1$s', 'event_espresso'), $prefix . implode(':', $parts));
840
-    }
792
+	/**
793
+	 * Retrieves the site's default timezone and returns it formatted so it's ready for display
794
+	 * to users. If you want to customize how its displayed feel free to fetch the 'timezone_string'
795
+	 * and 'gmt_offset' WordPress options directly; or use the filter
796
+	 * FHEE__EEH_DTT_Helper__get_timezone_string_for_display
797
+	 * (although note that we remove any HTML that may be added)
798
+	 *
799
+	 * @return string
800
+	 */
801
+	public static function get_timezone_string_for_display()
802
+	{
803
+		$pretty_timezone = apply_filters('FHEE__EEH_DTT_Helper__get_timezone_string_for_display', '');
804
+		if (! empty($pretty_timezone)) {
805
+			return esc_html($pretty_timezone);
806
+		}
807
+		$timezone_string = get_option('timezone_string');
808
+		if ($timezone_string) {
809
+			static $mo_loaded = false;
810
+			// Load translations for continents and cities just like wp_timezone_choice does
811
+			if (! $mo_loaded) {
812
+				$locale = get_locale();
813
+				$mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
814
+				load_textdomain('continents-cities', $mofile);
815
+				$mo_loaded = true;
816
+			}
817
+			//well that was easy.
818
+			$parts = explode('/', $timezone_string);
819
+			//remove the continent
820
+			unset($parts[0]);
821
+			$t_parts = array();
822
+			foreach ($parts as $part) {
823
+				$t_parts[] = translate(str_replace('_', ' ', $part), 'continents-cities');
824
+			}
825
+			return implode(' - ', $t_parts);
826
+		}
827
+		//they haven't set the timezone string, so let's return a string like "UTC+1"
828
+		$gmt_offset = get_option('gmt_offset');
829
+		$prefix     = (int) $gmt_offset >= 0 ? '+' : '';
830
+		$parts      = explode('.', (string) $gmt_offset);
831
+		if (count($parts) === 1) {
832
+			$parts[1] = '00';
833
+		} else {
834
+			//convert the part after the decimal, eg "5" (from x.5) or "25" (from x.25)
835
+			//to minutes, eg 30 or 15, respectively
836
+			$hour_fraction = (float) ('0.' . $parts[1]);
837
+			$parts[1]      = (string) $hour_fraction * 60;
838
+		}
839
+		return sprintf(__('UTC%1$s', 'event_espresso'), $prefix . implode(':', $parts));
840
+	}
841 841
 
842 842
 
843 843
 
844
-    /**
845
-     * So PHP does this awesome thing where if you are trying to get a timestamp
846
-     * for a month using a string like "February" or "February 2017",
847
-     * and you don't specify a day as part of your string,
848
-     * then PHP will use whatever the current day of the month is.
849
-     * IF the current day of the month happens to be the 30th or 31st,
850
-     * then PHP gets really confused by a date like February 30,
851
-     * so instead of saying
852
-     *      "Hey February only has 28 days (this year)...
853
-     *      ...you must have meant the last day of the month!"
854
-     * PHP does the next most logical thing, and bumps the date up to March 2nd,
855
-     * because someone requesting February 30th obviously meant March 1st!
856
-     * The way around this is to always set the day to the first,
857
-     * so that the month will stay on the month you wanted.
858
-     * this method will add that "1" into your date regardless of the format.
859
-     *
860
-     * @param string $month
861
-     * @return string
862
-     */
863
-    public static function first_of_month_timestamp($month = '')
864
-    {
865
-        $month = (string) $month;
866
-        $year  = '';
867
-        // check if the incoming string has a year in it or not
868
-        if (preg_match('/\b\d{4}\b/', $month, $matches)) {
869
-            $year = $matches[0];
870
-            // ten remove that from the month string as well as any spaces
871
-            $month = trim(str_replace($year, '', $month));
872
-            // add a space before the year
873
-            $year = " {$year}";
874
-        }
875
-        // return timestamp for something like "February 1 2017"
876
-        return strtotime("{$month} 1{$year}");
877
-    }
844
+	/**
845
+	 * So PHP does this awesome thing where if you are trying to get a timestamp
846
+	 * for a month using a string like "February" or "February 2017",
847
+	 * and you don't specify a day as part of your string,
848
+	 * then PHP will use whatever the current day of the month is.
849
+	 * IF the current day of the month happens to be the 30th or 31st,
850
+	 * then PHP gets really confused by a date like February 30,
851
+	 * so instead of saying
852
+	 *      "Hey February only has 28 days (this year)...
853
+	 *      ...you must have meant the last day of the month!"
854
+	 * PHP does the next most logical thing, and bumps the date up to March 2nd,
855
+	 * because someone requesting February 30th obviously meant March 1st!
856
+	 * The way around this is to always set the day to the first,
857
+	 * so that the month will stay on the month you wanted.
858
+	 * this method will add that "1" into your date regardless of the format.
859
+	 *
860
+	 * @param string $month
861
+	 * @return string
862
+	 */
863
+	public static function first_of_month_timestamp($month = '')
864
+	{
865
+		$month = (string) $month;
866
+		$year  = '';
867
+		// check if the incoming string has a year in it or not
868
+		if (preg_match('/\b\d{4}\b/', $month, $matches)) {
869
+			$year = $matches[0];
870
+			// ten remove that from the month string as well as any spaces
871
+			$month = trim(str_replace($year, '', $month));
872
+			// add a space before the year
873
+			$year = " {$year}";
874
+		}
875
+		// return timestamp for something like "February 1 2017"
876
+		return strtotime("{$month} 1{$year}");
877
+	}
878 878
 
879 879
 
880
-    /**
881
-     * This simply returns the timestamp for tomorrow (midnight next day) in this sites timezone.  So it may be midnight
882
-     * for this sites timezone, but the timestamp could be some other time GMT.
883
-     */
884
-    public static function tomorrow()
885
-    {
886
-        //The multiplication of -1 ensures that we switch positive offsets to negative and negative offsets to positive
887
-        //before adding to the timestamp.  Why? Because we want tomorrow to be for midnight the next day in THIS timezone
888
-        //not an offset from midnight in UTC.  So if we're starting with UTC 00:00:00, then we want to make sure the
889
-        //final timestamp is equivalent to midnight in this timezone as represented in GMT.
890
-        return strtotime('tomorrow') + (self::get_site_timezone_gmt_offset() * -1);
891
-    }
880
+	/**
881
+	 * This simply returns the timestamp for tomorrow (midnight next day) in this sites timezone.  So it may be midnight
882
+	 * for this sites timezone, but the timestamp could be some other time GMT.
883
+	 */
884
+	public static function tomorrow()
885
+	{
886
+		//The multiplication of -1 ensures that we switch positive offsets to negative and negative offsets to positive
887
+		//before adding to the timestamp.  Why? Because we want tomorrow to be for midnight the next day in THIS timezone
888
+		//not an offset from midnight in UTC.  So if we're starting with UTC 00:00:00, then we want to make sure the
889
+		//final timestamp is equivalent to midnight in this timezone as represented in GMT.
890
+		return strtotime('tomorrow') + (self::get_site_timezone_gmt_offset() * -1);
891
+	}
892 892
 
893 893
 
894
-    /**
895
-     * **
896
-     * Gives a nicely-formatted list of timezone strings.
897
-     * Copied from the core wp function by the same name so we could customize to remove UTC offsets.
898
-     *
899
-     * @since     4.9.40.rc.008
900
-     * @staticvar bool $mo_loaded
901
-     * @staticvar string $locale_loaded
902
-     * @param string $selected_zone Selected timezone.
903
-     * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
904
-     * @return string
905
-     */
906
-    public static function wp_timezone_choice($selected_zone, $locale = null)
907
-    {
908
-        static $mo_loaded = false, $locale_loaded = null;
909
-        $continents = array(
910
-            'Africa',
911
-            'America',
912
-            'Antarctica',
913
-            'Arctic',
914
-            'Asia',
915
-            'Atlantic',
916
-            'Australia',
917
-            'Europe',
918
-            'Indian',
919
-            'Pacific',
920
-        );
921
-        // Load translations for continents and cities.
922
-        if (! $mo_loaded || $locale !== $locale_loaded) {
923
-            $locale_loaded = $locale ? $locale : get_locale();
924
-            $mofile        = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
925
-            unload_textdomain('continents-cities');
926
-            load_textdomain('continents-cities', $mofile);
927
-            $mo_loaded = true;
928
-        }
929
-        $zone_data = array();
930
-        foreach (timezone_identifiers_list() as $zone) {
931
-            $zone = explode('/', $zone);
932
-            if (! in_array($zone[0], $continents, true)) {
933
-                continue;
934
-            }
935
-            // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
936
-            $exists      = array(
937
-                0 => isset($zone[0]) && $zone[0],
938
-                1 => isset($zone[1]) && $zone[1],
939
-                2 => isset($zone[2]) && $zone[2],
940
-            );
941
-            $exists[3]   = $exists[0] && $zone[0] !== 'Etc';
942
-            $exists[4]   = $exists[1] && $exists[3];
943
-            $exists[5]   = $exists[2] && $exists[3];
944
-            $zone_data[] = array(
945
-                'continent'   => $exists[0] ? $zone[0] : '',
946
-                'city'        => $exists[1] ? $zone[1] : '',
947
-                'subcity'     => $exists[2] ? $zone[2] : '',
948
-                't_continent' => $exists[3]
949
-                    ? translate(str_replace('_', ' ', $zone[0]), 'continents-cities')
950
-                    : '',
951
-                't_city'      => $exists[4]
952
-                    ? translate(str_replace('_', ' ', $zone[1]), 'continents-cities')
953
-                    : '',
954
-                't_subcity'   => $exists[5]
955
-                    ? translate(str_replace('_', ' ', $zone[2]), 'continents-cities')
956
-                    : '',
957
-            );
958
-        }
959
-        usort($zone_data, '_wp_timezone_choice_usort_callback');
960
-        $structure = array();
961
-        if (empty($selected_zone)) {
962
-            $structure[] = '<option selected="selected" value="">' . __('Select a city') . '</option>';
963
-        }
964
-        foreach ($zone_data as $key => $zone) {
965
-            // Build value in an array to join later
966
-            $value = array($zone['continent']);
967
-            if (empty($zone['city'])) {
968
-                // It's at the continent level (generally won't happen)
969
-                $display = $zone['t_continent'];
970
-            } else {
971
-                // It's inside a continent group
972
-                // Continent optgroup
973
-                if (! isset($zone_data[ $key - 1 ]) || $zone_data[ $key - 1 ]['continent'] !== $zone['continent']) {
974
-                    $label       = $zone['t_continent'];
975
-                    $structure[] = '<optgroup label="' . esc_attr($label) . '">';
976
-                }
977
-                // Add the city to the value
978
-                $value[] = $zone['city'];
979
-                $display = $zone['t_city'];
980
-                if (! empty($zone['subcity'])) {
981
-                    // Add the subcity to the value
982
-                    $value[] = $zone['subcity'];
983
-                    $display .= ' - ' . $zone['t_subcity'];
984
-                }
985
-            }
986
-            // Build the value
987
-            $value       = implode('/', $value);
988
-            $selected    = $value === $selected_zone ? ' selected="selected"' : '';
989
-            $structure[] = '<option value="' . esc_attr($value) . '"' . $selected . '>'
990
-                           . esc_html($display)
991
-                           . '</option>';
992
-            // Close continent optgroup
993
-            if (! empty($zone['city'])
994
-                && (
995
-                    ! isset($zone_data[ $key + 1 ])
996
-                    || (isset($zone_data[ $key + 1 ]) && $zone_data[ $key + 1 ]['continent'] !== $zone['continent'])
997
-                )
998
-            ) {
999
-                $structure[] = '</optgroup>';
1000
-            }
1001
-        }
1002
-        return implode("\n", $structure);
1003
-    }
894
+	/**
895
+	 * **
896
+	 * Gives a nicely-formatted list of timezone strings.
897
+	 * Copied from the core wp function by the same name so we could customize to remove UTC offsets.
898
+	 *
899
+	 * @since     4.9.40.rc.008
900
+	 * @staticvar bool $mo_loaded
901
+	 * @staticvar string $locale_loaded
902
+	 * @param string $selected_zone Selected timezone.
903
+	 * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
904
+	 * @return string
905
+	 */
906
+	public static function wp_timezone_choice($selected_zone, $locale = null)
907
+	{
908
+		static $mo_loaded = false, $locale_loaded = null;
909
+		$continents = array(
910
+			'Africa',
911
+			'America',
912
+			'Antarctica',
913
+			'Arctic',
914
+			'Asia',
915
+			'Atlantic',
916
+			'Australia',
917
+			'Europe',
918
+			'Indian',
919
+			'Pacific',
920
+		);
921
+		// Load translations for continents and cities.
922
+		if (! $mo_loaded || $locale !== $locale_loaded) {
923
+			$locale_loaded = $locale ? $locale : get_locale();
924
+			$mofile        = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
925
+			unload_textdomain('continents-cities');
926
+			load_textdomain('continents-cities', $mofile);
927
+			$mo_loaded = true;
928
+		}
929
+		$zone_data = array();
930
+		foreach (timezone_identifiers_list() as $zone) {
931
+			$zone = explode('/', $zone);
932
+			if (! in_array($zone[0], $continents, true)) {
933
+				continue;
934
+			}
935
+			// This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
936
+			$exists      = array(
937
+				0 => isset($zone[0]) && $zone[0],
938
+				1 => isset($zone[1]) && $zone[1],
939
+				2 => isset($zone[2]) && $zone[2],
940
+			);
941
+			$exists[3]   = $exists[0] && $zone[0] !== 'Etc';
942
+			$exists[4]   = $exists[1] && $exists[3];
943
+			$exists[5]   = $exists[2] && $exists[3];
944
+			$zone_data[] = array(
945
+				'continent'   => $exists[0] ? $zone[0] : '',
946
+				'city'        => $exists[1] ? $zone[1] : '',
947
+				'subcity'     => $exists[2] ? $zone[2] : '',
948
+				't_continent' => $exists[3]
949
+					? translate(str_replace('_', ' ', $zone[0]), 'continents-cities')
950
+					: '',
951
+				't_city'      => $exists[4]
952
+					? translate(str_replace('_', ' ', $zone[1]), 'continents-cities')
953
+					: '',
954
+				't_subcity'   => $exists[5]
955
+					? translate(str_replace('_', ' ', $zone[2]), 'continents-cities')
956
+					: '',
957
+			);
958
+		}
959
+		usort($zone_data, '_wp_timezone_choice_usort_callback');
960
+		$structure = array();
961
+		if (empty($selected_zone)) {
962
+			$structure[] = '<option selected="selected" value="">' . __('Select a city') . '</option>';
963
+		}
964
+		foreach ($zone_data as $key => $zone) {
965
+			// Build value in an array to join later
966
+			$value = array($zone['continent']);
967
+			if (empty($zone['city'])) {
968
+				// It's at the continent level (generally won't happen)
969
+				$display = $zone['t_continent'];
970
+			} else {
971
+				// It's inside a continent group
972
+				// Continent optgroup
973
+				if (! isset($zone_data[ $key - 1 ]) || $zone_data[ $key - 1 ]['continent'] !== $zone['continent']) {
974
+					$label       = $zone['t_continent'];
975
+					$structure[] = '<optgroup label="' . esc_attr($label) . '">';
976
+				}
977
+				// Add the city to the value
978
+				$value[] = $zone['city'];
979
+				$display = $zone['t_city'];
980
+				if (! empty($zone['subcity'])) {
981
+					// Add the subcity to the value
982
+					$value[] = $zone['subcity'];
983
+					$display .= ' - ' . $zone['t_subcity'];
984
+				}
985
+			}
986
+			// Build the value
987
+			$value       = implode('/', $value);
988
+			$selected    = $value === $selected_zone ? ' selected="selected"' : '';
989
+			$structure[] = '<option value="' . esc_attr($value) . '"' . $selected . '>'
990
+						   . esc_html($display)
991
+						   . '</option>';
992
+			// Close continent optgroup
993
+			if (! empty($zone['city'])
994
+				&& (
995
+					! isset($zone_data[ $key + 1 ])
996
+					|| (isset($zone_data[ $key + 1 ]) && $zone_data[ $key + 1 ]['continent'] !== $zone['continent'])
997
+				)
998
+			) {
999
+				$structure[] = '</optgroup>';
1000
+			}
1001
+		}
1002
+		return implode("\n", $structure);
1003
+	}
1004 1004
 
1005 1005
 
1006
-    /**
1007
-     * Shim for the WP function `get_user_locale` that was added in WordPress 4.7.0
1008
-     *
1009
-     * @param int|WP_User $user_id
1010
-     * @return string
1011
-     */
1012
-    public static function get_user_locale($user_id = 0)
1013
-    {
1014
-        if (function_exists('get_user_locale')) {
1015
-            return get_user_locale($user_id);
1016
-        }
1017
-        return get_locale();
1018
-    }
1006
+	/**
1007
+	 * Shim for the WP function `get_user_locale` that was added in WordPress 4.7.0
1008
+	 *
1009
+	 * @param int|WP_User $user_id
1010
+	 * @return string
1011
+	 */
1012
+	public static function get_user_locale($user_id = 0)
1013
+	{
1014
+		if (function_exists('get_user_locale')) {
1015
+			return get_user_locale($user_id);
1016
+		}
1017
+		return get_locale();
1018
+	}
1019 1019
 
1020 1020
 
1021
-    /**
1022
-     * Return the appropriate helper adapter for DTT related things.
1023
-     *
1024
-     * @return HelperInterface
1025
-     * @throws InvalidArgumentException
1026
-     * @throws InvalidDataTypeException
1027
-     * @throws InvalidInterfaceException
1028
-     */
1029
-    private static function getHelperAdapter() {
1030
-        $dtt_helper_fqcn = PHP_VERSION_ID < 50600
1031
-            ? 'EventEspresso\core\services\helpers\datetime\PhpCompatLessFiveSixHelper'
1032
-            : 'EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper';
1033
-        return LoaderFactory::getLoader()->getShared($dtt_helper_fqcn);
1034
-    }
1021
+	/**
1022
+	 * Return the appropriate helper adapter for DTT related things.
1023
+	 *
1024
+	 * @return HelperInterface
1025
+	 * @throws InvalidArgumentException
1026
+	 * @throws InvalidDataTypeException
1027
+	 * @throws InvalidInterfaceException
1028
+	 */
1029
+	private static function getHelperAdapter() {
1030
+		$dtt_helper_fqcn = PHP_VERSION_ID < 50600
1031
+			? 'EventEspresso\core\services\helpers\datetime\PhpCompatLessFiveSixHelper'
1032
+			: 'EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper';
1033
+		return LoaderFactory::getLoader()->getShared($dtt_helper_fqcn);
1034
+	}
1035 1035
 }
1036 1036
\ No newline at end of file
Please login to merge, or discard this patch.
core/EE_Data_Migration_Manager.core.php 2 patches
Indentation   +71 added lines, -71 removed lines patch added patch discarded remove patch
@@ -136,9 +136,9 @@  discard block
 block discarded – undo
136 136
 	protected $script_migration_versions;
137 137
 
138 138
 	/**
139
-     * 	@var EE_Data_Migration_Manager $_instance
139
+	 * 	@var EE_Data_Migration_Manager $_instance
140 140
 	 * 	@access 	private
141
-     */
141
+	 */
142 142
 	private static $_instance = NULL;
143 143
 
144 144
 
@@ -322,9 +322,9 @@  discard block
 block discarded – undo
322 322
 	 */
323 323
 	public function get_data_migration_script_folders(){
324 324
 		return  apply_filters(
325
-		    'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
326
-            array('Core' => EE_CORE.'data_migration_scripts')
327
-        );
325
+			'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
326
+			array('Core' => EE_CORE.'data_migration_scripts')
327
+		);
328 328
 	}
329 329
 
330 330
 	/**
@@ -337,15 +337,15 @@  discard block
 block discarded – undo
337 337
 	 * @throws EE_Error
338 338
 	 */
339 339
 	public function script_migrates_to_version($migration_script_name, $eeAddonClass = ''){
340
-	    if(isset($this->script_migration_versions[ $migration_script_name ])){
341
-	        return $this->script_migration_versions[ $migration_script_name ];
342
-        }
340
+		if(isset($this->script_migration_versions[ $migration_script_name ])){
341
+			return $this->script_migration_versions[ $migration_script_name ];
342
+		}
343 343
 		$dms_info = $this->parse_dms_classname($migration_script_name);
344
-        $this->script_migration_versions[ $migration_script_name ] = array(
344
+		$this->script_migration_versions[ $migration_script_name ] = array(
345 345
 			'slug'=> $eeAddonClass !== '' ? $eeAddonClass : $dms_info[ 'slug' ],
346 346
 			'version'=> $dms_info[ 'major_version' ] . "." . $dms_info[ 'minor_version' ] . "." . $dms_info[ 'micro_version' ]
347
-        );
348
-        return $this->script_migration_versions[ $migration_script_name ];
347
+		);
348
+		return $this->script_migration_versions[ $migration_script_name ];
349 349
 	}
350 350
 
351 351
 	/**
@@ -736,60 +736,60 @@  discard block
 block discarded – undo
736 736
 	}
737 737
 
738 738
 
739
-    /**
740
-     * Gets all the data migration scripts available in the core folder and folders
741
-     * in addons. Has the side effect of adding them for autoloading
742
-     *
743
-     * @return array keys are expected classnames, values are their filepaths
744
-     * @throws InvalidInterfaceException
745
-     * @throws InvalidDataTypeException
746
-     * @throws EE_Error
747
-     * @throws InvalidArgumentException
748
-     */
749
-    public function get_all_data_migration_scripts_available()
750
-    {
751
-        if (! $this->_data_migration_class_to_filepath_map) {
752
-            $this->_data_migration_class_to_filepath_map = array();
753
-            foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
754
-                // strip any placeholders added to classname to make it a unique array key
755
-                $eeAddonClass = trim($eeAddonClass, '*');
756
-                $eeAddonClass = $eeAddonClass === 'Core' || class_exists($eeAddonClass)
757
-                    ? $eeAddonClass
758
-                    : '';
759
-                $folder_path  = EEH_File::end_with_directory_separator($folder_path);
760
-                $files        = glob($folder_path . '*.dms.php');
761
-                if (empty($files)) {
762
-                    continue;
763
-                }
764
-                foreach ($files as $file) {
765
-                    $pos_of_last_slash = strrpos($file, DS);
766
-                    $classname         = str_replace('.dms.php', '', substr($file, $pos_of_last_slash + 1));
767
-                    $migrates_to       = $this->script_migrates_to_version($classname, $eeAddonClass);
768
-                    $slug              = $migrates_to['slug'];
769
-                    //check that the slug as contained in the DMS is associated with
770
-                    //the slug of an addon or core
771
-                    if ($slug !== 'Core' && EE_Registry::instance()->get_addon_by_name($slug) === null) {
772
-                        EE_Error::doing_it_wrong(
773
-                            __FUNCTION__,
774
-                            sprintf(
775
-                                esc_html__(
776
-                                    'The data migration script "%s" migrates the "%s" data, but there is no EE addon with that name. There is only: %s. ',
777
-                                    'event_espresso'
778
-                                ),
779
-                                $classname,
780
-                                $slug,
781
-                                implode(', ', array_keys(EE_Registry::instance()->get_addons_by_name()))
782
-                            ),
783
-                            '4.3.0.alpha.019'
784
-                        );
785
-                    }
786
-                    $this->_data_migration_class_to_filepath_map[ $classname ] = $file;
787
-                }
788
-            }
789
-            EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
790
-        }
791
-        return $this->_data_migration_class_to_filepath_map;
792
-    }
739
+	/**
740
+	 * Gets all the data migration scripts available in the core folder and folders
741
+	 * in addons. Has the side effect of adding them for autoloading
742
+	 *
743
+	 * @return array keys are expected classnames, values are their filepaths
744
+	 * @throws InvalidInterfaceException
745
+	 * @throws InvalidDataTypeException
746
+	 * @throws EE_Error
747
+	 * @throws InvalidArgumentException
748
+	 */
749
+	public function get_all_data_migration_scripts_available()
750
+	{
751
+		if (! $this->_data_migration_class_to_filepath_map) {
752
+			$this->_data_migration_class_to_filepath_map = array();
753
+			foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
754
+				// strip any placeholders added to classname to make it a unique array key
755
+				$eeAddonClass = trim($eeAddonClass, '*');
756
+				$eeAddonClass = $eeAddonClass === 'Core' || class_exists($eeAddonClass)
757
+					? $eeAddonClass
758
+					: '';
759
+				$folder_path  = EEH_File::end_with_directory_separator($folder_path);
760
+				$files        = glob($folder_path . '*.dms.php');
761
+				if (empty($files)) {
762
+					continue;
763
+				}
764
+				foreach ($files as $file) {
765
+					$pos_of_last_slash = strrpos($file, DS);
766
+					$classname         = str_replace('.dms.php', '', substr($file, $pos_of_last_slash + 1));
767
+					$migrates_to       = $this->script_migrates_to_version($classname, $eeAddonClass);
768
+					$slug              = $migrates_to['slug'];
769
+					//check that the slug as contained in the DMS is associated with
770
+					//the slug of an addon or core
771
+					if ($slug !== 'Core' && EE_Registry::instance()->get_addon_by_name($slug) === null) {
772
+						EE_Error::doing_it_wrong(
773
+							__FUNCTION__,
774
+							sprintf(
775
+								esc_html__(
776
+									'The data migration script "%s" migrates the "%s" data, but there is no EE addon with that name. There is only: %s. ',
777
+									'event_espresso'
778
+								),
779
+								$classname,
780
+								$slug,
781
+								implode(', ', array_keys(EE_Registry::instance()->get_addons_by_name()))
782
+							),
783
+							'4.3.0.alpha.019'
784
+						);
785
+					}
786
+					$this->_data_migration_class_to_filepath_map[ $classname ] = $file;
787
+				}
788
+			}
789
+			EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
790
+		}
791
+		return $this->_data_migration_class_to_filepath_map;
792
+	}
793 793
 
794 794
 
795 795
 
@@ -961,12 +961,12 @@  discard block
 block discarded – undo
961 961
 	}
962 962
 
963 963
 /**
964
-	 * Resets the borked data migration scripts so they're no longer borked
965
-	 * so we can again attempt to migrate
966
-	 *
967
-	 * @return bool
968
-	 * @throws EE_Error
969
-	 */
964
+ * Resets the borked data migration scripts so they're no longer borked
965
+ * so we can again attempt to migrate
966
+ *
967
+ * @return bool
968
+ * @throws EE_Error
969
+ */
970 970
 	public function reattempt(){
971 971
 		//find if the last-ran script was borked
972 972
 		//set it as being non-borked (we shouldn't ever get DMSs that we don't recognize)
Please login to merge, or discard this patch.
Spacing   +198 added lines, -198 removed lines patch added patch discarded remove patch
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
 	 * of this EE installation. Keys should be the name of the version the script upgraded to
86 86
 	 * @var EE_Data_Migration_Script_Base[]
87 87
 	 */
88
-	private $_data_migrations_ran =null;
88
+	private $_data_migrations_ran = null;
89 89
 	/**
90 90
 	 * The last ran script. It's nice to store this somewhere accessible, as its easiest
91 91
 	 * to know which was the last run by which is the newest wp option; but in most of the code
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
 	 */
151 151
 	public static function instance() {
152 152
 		// check if class object is instantiated
153
-		if ( ! self::$_instance instanceof EE_Data_Migration_Manager ) {
153
+		if ( ! self::$_instance instanceof EE_Data_Migration_Manager) {
154 154
 			self::$_instance = new self();
155 155
 		}
156 156
 		return self::$_instance;
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 	 * all new usages of the singleton should be made with Classname::instance()) and returns it
161 161
 	 * @return EE_Data_Migration_Manager
162 162
 	 */
163
-	public static function reset(){
163
+	public static function reset() {
164 164
 		self::$_instance = NULL;
165 165
 		return self::instance();
166 166
 	}
@@ -170,7 +170,7 @@  discard block
 block discarded – undo
170 170
 	/**
171 171
 	 * constructor
172 172
 	 */
173
-	private function __construct(){
173
+	private function __construct() {
174 174
 		$this->stati_that_indicate_to_continue_migrations = array(
175 175
 			self::status_continue,
176 176
 			self::status_completed
@@ -189,13 +189,13 @@  discard block
 block discarded – undo
189 189
 		);
190 190
 		//make sure we've included the base migration script, because we may need the EE_DMS_Unknown_1_0_0 class
191 191
 		//to be defined, because right now it doesn't get autoloaded on its own
192
-		EE_Registry::instance()->load_core( 'Data_Migration_Class_Base', array(), TRUE );
193
-		EE_Registry::instance()->load_core( 'Data_Migration_Script_Base', array(), TRUE );
194
-		EE_Registry::instance()->load_core( 'DMS_Unknown_1_0_0', array(), TRUE );
195
-		EE_Registry::instance()->load_core( 'Data_Migration_Script_Stage', array(), TRUE );
196
-		EE_Registry::instance()->load_core( 'Data_Migration_Script_Stage_Table', array(), TRUE );
197
-		$this->_table_manager = EE_Registry::instance()->create( 'TableManager', array(), true );
198
-		$this->_table_analysis = EE_Registry::instance()->create( 'TableAnalysis', array(), true );
192
+		EE_Registry::instance()->load_core('Data_Migration_Class_Base', array(), TRUE);
193
+		EE_Registry::instance()->load_core('Data_Migration_Script_Base', array(), TRUE);
194
+		EE_Registry::instance()->load_core('DMS_Unknown_1_0_0', array(), TRUE);
195
+		EE_Registry::instance()->load_core('Data_Migration_Script_Stage', array(), TRUE);
196
+		EE_Registry::instance()->load_core('Data_Migration_Script_Stage_Table', array(), TRUE);
197
+		$this->_table_manager = EE_Registry::instance()->create('TableManager', array(), true);
198
+		$this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
199 199
 	}
200 200
 
201 201
 
@@ -208,21 +208,21 @@  discard block
 block discarded – undo
208 208
 	 * @param string $option_name (see EE_Data_Migration_Manage::_save_migrations_ran() where the option name is set)
209 209
 	 * @return array where the first item is the plugin slug (eg 'Core','Calendar',etc) and the 2nd is the version of that plugin (eg '4.1.0')
210 210
 	 */
211
-	private function _get_plugin_slug_and_version_string_from_dms_option_name($option_name){
211
+	private function _get_plugin_slug_and_version_string_from_dms_option_name($option_name) {
212 212
 		$plugin_slug_and_version_string = str_replace(EE_Data_Migration_Manager::data_migration_script_option_prefix, "", $option_name);
213 213
 		//check if $plugin_slug_and_version_string is like '4.1.0' (4.1-style) or 'Core.4.1.0' (4.2-style)
214
-		$parts = explode(".",$plugin_slug_and_version_string);
214
+		$parts = explode(".", $plugin_slug_and_version_string);
215 215
 
216
-		if(count($parts) == 4){
216
+		if (count($parts) == 4) {
217 217
 			//it's 4.2-style.eg Core.4.1.0
218
-			$plugin_slug = $parts[0];//eg Core
218
+			$plugin_slug = $parts[0]; //eg Core
219 219
 			$version_string = $parts[1].".".$parts[2].".".$parts[3]; //eg 4.1.0
220
-		}else{
220
+		} else {
221 221
 			//it's 4.1-style: eg 4.1.0
222 222
 			$plugin_slug = 'Core';
223
-			$version_string = $plugin_slug_and_version_string;//eg 4.1.0
223
+			$version_string = $plugin_slug_and_version_string; //eg 4.1.0
224 224
 		}
225
-		return array($plugin_slug,$version_string);
225
+		return array($plugin_slug, $version_string);
226 226
 	}
227 227
 
228 228
 	/**
@@ -233,21 +233,21 @@  discard block
 block discarded – undo
233 233
 	 * @return EE_Data_Migration_Script_Base
234 234
 	 * @throws EE_Error
235 235
 	 */
236
-	private function _get_dms_class_from_wp_option($dms_option_name,$dms_option_value){
236
+	private function _get_dms_class_from_wp_option($dms_option_name, $dms_option_value) {
237 237
 		$data_migration_data = maybe_unserialize($dms_option_value);
238
-		if(isset($data_migration_data['class']) && class_exists($data_migration_data['class'])){
238
+		if (isset($data_migration_data['class']) && class_exists($data_migration_data['class'])) {
239 239
 			$class = new $data_migration_data['class'];
240
-			if($class instanceof EE_Data_Migration_Script_Base){
240
+			if ($class instanceof EE_Data_Migration_Script_Base) {
241 241
 				$class->instantiate_from_array_of_properties($data_migration_data);
242 242
 				return $class;
243
-			}else{
243
+			} else {
244 244
 				//huh, so its an object but not a data migration script?? that shouldn't happen
245 245
 				//just leave it as an array (which will probably just get ignored)
246
-				throw new EE_Error(sprintf(__("Trying to retrieve DMS class from wp option. No DMS by the name '%s' exists", 'event_espresso'),$data_migration_data['class']));
246
+				throw new EE_Error(sprintf(__("Trying to retrieve DMS class from wp option. No DMS by the name '%s' exists", 'event_espresso'), $data_migration_data['class']));
247 247
 			}
248
-		}else{
248
+		} else {
249 249
 			//so the data doesn't specify a class. So it must either be a legacy array of info or some array (which we'll probably just ignore), or a class that no longer exists
250
-			throw new EE_Error(sprintf(__("The wp option  with key '%s' does not represent a DMS", 'event_espresso'),$dms_option_name));
250
+			throw new EE_Error(sprintf(__("The wp option  with key '%s' does not represent a DMS", 'event_espresso'), $dms_option_name));
251 251
 		}
252 252
 	}
253 253
 	/**
@@ -255,34 +255,34 @@  discard block
 block discarded – undo
255 255
 	 * the last ran which hasn't finished yet
256 256
 	 * @return array where each element should be an array of EE_Data_Migration_Script_Base (but also has a few legacy arrays in there - which should probably be ignored)
257 257
 	 */
258
-	public function get_data_migrations_ran(){
259
-		if( ! $this->_data_migrations_ran ){
258
+	public function get_data_migrations_ran() {
259
+		if ( ! $this->_data_migrations_ran) {
260 260
 			//setup autoloaders for each of the scripts in there
261 261
 			$this->get_all_data_migration_scripts_available();
262
-			$data_migrations_options = $this->get_all_migration_script_options();//get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
262
+			$data_migrations_options = $this->get_all_migration_script_options(); //get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
263 263
 
264 264
 			$data_migrations_ran = array();
265 265
 			//convert into data migration script classes where possible
266
-			foreach($data_migrations_options as $data_migration_option){
267
-				list($plugin_slug,$version_string) = $this->_get_plugin_slug_and_version_string_from_dms_option_name($data_migration_option['option_name']);
266
+			foreach ($data_migrations_options as $data_migration_option) {
267
+				list($plugin_slug, $version_string) = $this->_get_plugin_slug_and_version_string_from_dms_option_name($data_migration_option['option_name']);
268 268
 
269
-				try{
270
-					$class = $this->_get_dms_class_from_wp_option($data_migration_option['option_name'],$data_migration_option['option_value']);
269
+				try {
270
+					$class = $this->_get_dms_class_from_wp_option($data_migration_option['option_name'], $data_migration_option['option_value']);
271 271
 					$data_migrations_ran[$plugin_slug][$version_string] = $class;
272 272
 					//ok so far THIS is the 'last-ran-script'... unless we find another on next iteration
273 273
 					$this->_last_ran_script = $class;
274
-					if( ! $class->is_completed()){
274
+					if ( ! $class->is_completed()) {
275 275
 						//sometimes we also like to know which was the last incomplete script (or if there are any at all)
276 276
 						$this->_last_ran_incomplete_script = $class;
277 277
 					}
278
-				}catch(EE_Error $e){
278
+				} catch (EE_Error $e) {
279 279
 					//ok so its not a DMS. We'll just keep it, although other code will need to expect non-DMSs
280 280
 					$data_migrations_ran[$plugin_slug][$version_string] = maybe_unserialize($data_migration_option['option_value']);
281 281
 				}
282 282
 			}
283 283
 			//so here the array of $data_migrations_ran is actually a mix of classes and a few legacy arrays
284 284
 			$this->_data_migrations_ran = $data_migrations_ran;
285
-			 if ( ! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran) ){
285
+			 if ( ! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
286 286
 				$this->_data_migrations_ran = array();
287 287
 			}
288 288
 		}
@@ -299,7 +299,7 @@  discard block
 block discarded – undo
299 299
 	 * @param        $new_table
300 300
 	 * @return mixed string or int
301 301
 	 */
302
-	public function get_mapping_new_pk( $script_name, $old_table, $old_pk, $new_table){
302
+	public function get_mapping_new_pk($script_name, $old_table, $old_pk, $new_table) {
303 303
 		$script = EE_Registry::instance()->load_dms($script_name);
304 304
 		$mapping = $script->get_mapping_new_pk($old_table, $old_pk, $new_table);
305 305
 		return $mapping;
@@ -310,9 +310,9 @@  discard block
 block discarded – undo
310 310
 	 * option returned in this array is the most-recently ran DMS option
311 311
 	 * @return array
312 312
 	 */
313
-	 public function get_all_migration_script_options(){
313
+	 public function get_all_migration_script_options() {
314 314
 		global $wpdb;
315
-		return $wpdb->get_results("SELECT * FROM {$wpdb->options} WHERE option_name like '".EE_Data_Migration_Manager::data_migration_script_option_prefix."%' ORDER BY option_id ASC",ARRAY_A);
315
+		return $wpdb->get_results("SELECT * FROM {$wpdb->options} WHERE option_name like '".EE_Data_Migration_Manager::data_migration_script_option_prefix."%' ORDER BY option_id ASC", ARRAY_A);
316 316
 	}
317 317
 
318 318
 	/**
@@ -320,7 +320,7 @@  discard block
 block discarded – undo
320 320
 	 * @return array where each value is the full folder path of a folder containing data migration scripts, WITH slashes at the end of the
321 321
 	 * folder name.
322 322
 	 */
323
-	public function get_data_migration_script_folders(){
323
+	public function get_data_migration_script_folders() {
324 324
 		return  apply_filters(
325 325
 		    'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
326 326
             array('Core' => EE_CORE.'data_migration_scripts')
@@ -336,16 +336,16 @@  discard block
 block discarded – undo
336 336
 	 * }
337 337
 	 * @throws EE_Error
338 338
 	 */
339
-	public function script_migrates_to_version($migration_script_name, $eeAddonClass = ''){
340
-	    if(isset($this->script_migration_versions[ $migration_script_name ])){
341
-	        return $this->script_migration_versions[ $migration_script_name ];
339
+	public function script_migrates_to_version($migration_script_name, $eeAddonClass = '') {
340
+	    if (isset($this->script_migration_versions[$migration_script_name])) {
341
+	        return $this->script_migration_versions[$migration_script_name];
342 342
         }
343 343
 		$dms_info = $this->parse_dms_classname($migration_script_name);
344
-        $this->script_migration_versions[ $migration_script_name ] = array(
345
-			'slug'=> $eeAddonClass !== '' ? $eeAddonClass : $dms_info[ 'slug' ],
346
-			'version'=> $dms_info[ 'major_version' ] . "." . $dms_info[ 'minor_version' ] . "." . $dms_info[ 'micro_version' ]
344
+        $this->script_migration_versions[$migration_script_name] = array(
345
+			'slug'=> $eeAddonClass !== '' ? $eeAddonClass : $dms_info['slug'],
346
+			'version'=> $dms_info['major_version'].".".$dms_info['minor_version'].".".$dms_info['micro_version']
347 347
         );
348
-        return $this->script_migration_versions[ $migration_script_name ];
348
+        return $this->script_migration_versions[$migration_script_name];
349 349
 	}
350 350
 
351 351
 	/**
@@ -354,13 +354,13 @@  discard block
 block discarded – undo
354 354
 	 * @return array with keys 'slug','major_version','minor_version', and 'micro_version' (the last 3 are ints)
355 355
 	 * @throws EE_Error
356 356
 	 */
357
-	public function parse_dms_classname($classname){
357
+	public function parse_dms_classname($classname) {
358 358
 		$matches = array();
359
-		preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~',$classname,$matches);
360
-		if( ! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))){
361
-				throw new EE_Error(sprintf(__("%s is not a valid Data Migration Script. The classname should be like EE_DMS_w_x_y_z, where w is either 'Core' or the slug of an addon and x, y and z are numbers, ", "event_espresso"),$classname));
359
+		preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~', $classname, $matches);
360
+		if ( ! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
361
+				throw new EE_Error(sprintf(__("%s is not a valid Data Migration Script. The classname should be like EE_DMS_w_x_y_z, where w is either 'Core' or the slug of an addon and x, y and z are numbers, ", "event_espresso"), $classname));
362 362
 		}
363
-		return array('slug'=>$matches[1],'major_version'=>intval($matches[2]),'minor_version'=>intval($matches[3]),'micro_version'=>intval($matches[4]));
363
+		return array('slug'=>$matches[1], 'major_version'=>intval($matches[2]), 'minor_version'=>intval($matches[3]), 'micro_version'=>intval($matches[4]));
364 364
 	}
365 365
 	/**
366 366
 	 * Ensures that the option indicating the current DB version is set. This should only be
@@ -369,33 +369,33 @@  discard block
 block discarded – undo
369 369
 	 * to 4.1.x.
370 370
 	 * @return string of current db state
371 371
 	 */
372
-	public function ensure_current_database_state_is_set(){
373
-		$espresso_db_core_updates = get_option( 'espresso_db_update', array() );
372
+	public function ensure_current_database_state_is_set() {
373
+		$espresso_db_core_updates = get_option('espresso_db_update', array());
374 374
 		$db_state = get_option(EE_Data_Migration_Manager::current_database_state);
375
-		if( ! $db_state ){
375
+		if ( ! $db_state) {
376 376
 			//mark the DB as being in the state as the last version in there.
377 377
 			//this is done to trigger maintenance mode and do data migration scripts
378 378
 			//if the admin installed this version of EE over 3.1.x or 4.0.x
379 379
 			//otherwise, the normal maintenance mode code is fine
380 380
 			$previous_versions_installed = array_keys($espresso_db_core_updates);
381 381
 			$previous_version_installed = end($previous_versions_installed);
382
-			if(version_compare('4.1.0', $previous_version_installed)){
382
+			if (version_compare('4.1.0', $previous_version_installed)) {
383 383
 				//last installed version was less than 4.1
384 384
 				//so we want the data migrations to happen. SO, we're going to say the DB is at that state
385 385
 //				echo "4.1.0 is greater than $previous_version_installed! update the option";
386 386
 				$db_state = array('Core'=>$previous_version_installed);
387
-			}else{
387
+			} else {
388 388
 //					echo "4.1.0 is SMALLER than $previous_version_installed";
389 389
 					$db_state = array('Core'=>EVENT_ESPRESSO_VERSION);
390 390
 			}
391
-			update_option(EE_Data_Migration_Manager::current_database_state,$db_state);
391
+			update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
392 392
 		}
393 393
 		//in 4.1, $db_state would have only been a simple string like '4.1.0',
394 394
 		//but in 4.2+ it should be an array with at least key 'Core' and the value of that plugin's
395 395
 		//db, and possibly other keys for other addons like 'Calendar','Permissions',etc
396
-		if( ! is_array($db_state)){
396
+		if ( ! is_array($db_state)) {
397 397
 			$db_state = array('Core'=>$db_state);
398
-			update_option(EE_Data_Migration_Manager::current_database_state,$db_state);
398
+			update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
399 399
 		}
400 400
 		return $db_state;
401 401
 	}
@@ -406,7 +406,7 @@  discard block
 block discarded – undo
406 406
 	 * or they don't apply), returns an empty array
407 407
 	 * @return EE_Data_Migration_Script_Base[]
408 408
 	 */
409
-	public function check_for_applicable_data_migration_scripts(){
409
+	public function check_for_applicable_data_migration_scripts() {
410 410
 		//get the option describing what options have already run
411 411
 		$scripts_ran = $this->get_data_migrations_ran();
412 412
 		//$scripts_ran = array('4.1.0.core'=>array('monkey'=>null));
@@ -419,62 +419,62 @@  discard block
 block discarded – undo
419 419
 		$iteration = 0;
420 420
 		$next_database_state_to_consider = $current_database_state;
421 421
 		$theoretical_database_state = NULL;
422
-		do{
422
+		do {
423 423
 			//the next state after the currently-considered one will start off looking the same as the current, but we may make additions...
424 424
 			$theoretical_database_state = $next_database_state_to_consider;
425 425
 			//the next db state to consider is "what would the DB be like had we run all the scripts we found that applied last time?)
426
-			foreach($script_class_and_filepaths_available as $classname => $filepath){
426
+			foreach ($script_class_and_filepaths_available as $classname => $filepath) {
427 427
 
428 428
 				$migrates_to_version = $this->script_migrates_to_version($classname);
429
-				$script_converts_plugin_slug = $migrates_to_version[ 'slug' ];
430
-				$script_converts_to_version = $migrates_to_version[ 'version' ];
429
+				$script_converts_plugin_slug = $migrates_to_version['slug'];
430
+				$script_converts_to_version = $migrates_to_version['version'];
431 431
 				//check if this version script is DONE or not; or if it's never been ran
432
-				if(		! $scripts_ran ||
432
+				if ( ! $scripts_ran ||
433 433
 						! isset($scripts_ran[$script_converts_plugin_slug]) ||
434
-						! isset($scripts_ran[$script_converts_plugin_slug][$script_converts_to_version])){
434
+						! isset($scripts_ran[$script_converts_plugin_slug][$script_converts_to_version])) {
435 435
 					//we haven't ran this conversion script before
436 436
 					//now check if it applies... note that we've added an autoloader for it on get_all_data_migration_scripts_available
437
-					$script = new $classname( $this->_get_table_manager(), $this->_get_table_analysis() );
437
+					$script = new $classname($this->_get_table_manager(), $this->_get_table_analysis());
438 438
 					/* @var $script EE_Data_Migration_Script_Base */
439 439
 					$can_migrate = $script->can_migrate_from_version($theoretical_database_state);
440
-					if($can_migrate){
440
+					if ($can_migrate) {
441 441
 						$script_classes_that_should_run_per_iteration[$iteration][$script->priority()][] = $script;
442 442
 						$migrates_to_version = $script->migrates_to_version();
443
-						$next_database_state_to_consider[ $migrates_to_version[ 'slug' ] ] = $migrates_to_version[ 'version' ];
443
+						$next_database_state_to_consider[$migrates_to_version['slug']] = $migrates_to_version['version'];
444 444
 						unset($script_class_and_filepaths_available[$classname]);
445 445
 					}
446
-				} elseif($scripts_ran[$script_converts_plugin_slug][$script_converts_to_version] instanceof EE_Data_Migration_Script_Base){
446
+				} elseif ($scripts_ran[$script_converts_plugin_slug][$script_converts_to_version] instanceof EE_Data_Migration_Script_Base) {
447 447
 					//this script has been ran, or at least started
448 448
 					$script = $scripts_ran[$script_converts_plugin_slug][$script_converts_to_version];
449
-					if( $script->get_status() != self::status_completed){
449
+					if ($script->get_status() != self::status_completed) {
450 450
 						//this script is already underway... keep going with it
451 451
 						$script_classes_that_should_run_per_iteration[$iteration][$script->priority()][] = $script;
452 452
 						$migrates_to_version = $script->migrates_to_version();
453
-						$next_database_state_to_consider[ $migrates_to_version[ 'slug' ] ] = $migrates_to_version[ 'version' ];
453
+						$next_database_state_to_consider[$migrates_to_version['slug']] = $migrates_to_version['version'];
454 454
 						unset($script_class_and_filepaths_available[$classname]);
455
-					}else{
455
+					} else {
456 456
 						//it must have a status that indicates it has finished, so we don't want to try and run it again
457 457
 					}
458
-				}else{
458
+				} else {
459 459
 					//it exists but it's not  a proper data migration script
460 460
 					//maybe the script got renamed? or was simply removed from EE?
461 461
 					//either way, its certainly not runnable!
462 462
 				}
463 463
 			}
464 464
 			$iteration++;
465
-		}while( $next_database_state_to_consider != $theoretical_database_state && $iteration<6);
465
+		}while ($next_database_state_to_consider != $theoretical_database_state && $iteration < 6);
466 466
 		//ok we have all the scripts that should run, now let's make them into flat array
467 467
 		$scripts_that_should_run = array();
468
-		foreach($script_classes_that_should_run_per_iteration as $scripts_at_priority){
468
+		foreach ($script_classes_that_should_run_per_iteration as $scripts_at_priority) {
469 469
 			ksort($scripts_at_priority);
470
-			foreach($scripts_at_priority as $scripts){
471
-				foreach($scripts as $script){
470
+			foreach ($scripts_at_priority as $scripts) {
471
+				foreach ($scripts as $script) {
472 472
 					$scripts_that_should_run[get_class($script)] = $script;
473 473
 				}
474 474
 			}
475 475
 		}
476 476
 
477
-		do_action( 'AHEE__EE_Data_Migration_Manager__check_for_applicable_data_migration_scripts__scripts_that_should_run', $scripts_that_should_run );
477
+		do_action('AHEE__EE_Data_Migration_Manager__check_for_applicable_data_migration_scripts__scripts_that_should_run', $scripts_that_should_run);
478 478
 		return $scripts_that_should_run;
479 479
 	}
480 480
 
@@ -488,14 +488,14 @@  discard block
 block discarded – undo
488 488
 	 * @param bool $include_completed_scripts
489 489
 	 * @return EE_Data_Migration_Script_Base
490 490
 	 */
491
-	public function get_last_ran_script($include_completed_scripts = false){
491
+	public function get_last_ran_script($include_completed_scripts = false) {
492 492
 		//make sure we've setup the class properties _last_ran_script and _last_ran_incomplete_script
493
-		if( ! $this->_data_migrations_ran){
493
+		if ( ! $this->_data_migrations_ran) {
494 494
 			$this->get_data_migrations_ran();
495 495
 		}
496
-		if($include_completed_scripts){
496
+		if ($include_completed_scripts) {
497 497
 			return $this->_last_ran_script;
498
-		}else{
498
+		} else {
499 499
 			return $this->_last_ran_incomplete_script;
500 500
 		}
501 501
 	}
@@ -518,19 +518,19 @@  discard block
 block discarded – undo
518 518
 	 * 		@type string $message string describing what was done during this step
519 519
 	 * }
520 520
 	 */
521
-	public function migration_step( $step_size = 0 ){
521
+	public function migration_step($step_size = 0) {
522 522
 
523 523
 		//bandaid fix for issue https://events.codebasehq.com/projects/event-espresso/tickets/7535
524
-		if ( class_exists( 'EE_CPT_Strategy' ) ) {
525
-			remove_action( 'pre_get_posts', array( EE_CPT_Strategy::instance(), 'pre_get_posts' ), 5 );
524
+		if (class_exists('EE_CPT_Strategy')) {
525
+			remove_action('pre_get_posts', array(EE_CPT_Strategy::instance(), 'pre_get_posts'), 5);
526 526
 		}
527 527
 
528
-		try{
528
+		try {
529 529
 			$currently_executing_script = $this->get_last_ran_script();
530
-			if( ! $currently_executing_script){
530
+			if ( ! $currently_executing_script) {
531 531
 				//Find the next script that needs to execute
532 532
 				$scripts = $this->check_for_applicable_data_migration_scripts();
533
-				if( ! $scripts ){
533
+				if ( ! $scripts) {
534 534
 					//huh, no more scripts to run... apparently we're done!
535 535
 					//but dont forget to make sure initial data is there
536 536
 					//we should be good to allow them to exit maintenance mode now
@@ -551,18 +551,18 @@  discard block
 block discarded – undo
551 551
 				//and add to the array/wp option showing the scripts ran
552 552
 //				$this->_data_migrations_ran[$this->script_migrates_to_version(get_class($currently_executing_script))] = $currently_executing_script;
553 553
 				$migrates_to = $this->script_migrates_to_version(get_class($currently_executing_script));
554
-				$plugin_slug = $migrates_to[ 'slug' ];
555
-				$version = $migrates_to[ 'version' ];
554
+				$plugin_slug = $migrates_to['slug'];
555
+				$version = $migrates_to['version'];
556 556
 				$this->_data_migrations_ran[$plugin_slug][$version] = $currently_executing_script;
557 557
 			}
558 558
 			$current_script_name = get_class($currently_executing_script);
559
-		}catch(Exception $e){
559
+		} catch (Exception $e) {
560 560
 			//an exception occurred while trying to get migration scripts
561 561
 
562
-			$message =  sprintf( __("Error Message: %sStack Trace:%s", "event_espresso"), $e->getMessage() . '<br>', $e->getTraceAsString() );
562
+			$message = sprintf(__("Error Message: %sStack Trace:%s", "event_espresso"), $e->getMessage().'<br>', $e->getTraceAsString());
563 563
 			//record it on the array of data migration scripts ran. This will be overwritten next time we try and try to run data migrations
564 564
 			//but that's ok-- it's just an FYI to support that we couldn't even run any data migrations
565
-			$this->add_error_to_migrations_ran(sprintf(__("Could not run data migrations because: %s", "event_espresso"),$message));
565
+			$this->add_error_to_migrations_ran(sprintf(__("Could not run data migrations because: %s", "event_espresso"), $message));
566 566
 			return array(
567 567
 				'records_to_migrate'=>1,
568 568
 				'records_migrated'=>0,
@@ -572,16 +572,16 @@  discard block
 block discarded – undo
572 572
 			);
573 573
 		}
574 574
 		//ok so we definitely have a data migration script
575
-		try{
575
+		try {
576 576
 			//how big of a bite do we want to take? Allow users to easily override via their wp-config
577
-			if( ! absint( $step_size ) > 0 ){
578
-				$step_size = defined( 'EE_MIGRATION_STEP_SIZE' ) && absint( EE_MIGRATION_STEP_SIZE ) ? EE_MIGRATION_STEP_SIZE : EE_Data_Migration_Manager::step_size;
577
+			if ( ! absint($step_size) > 0) {
578
+				$step_size = defined('EE_MIGRATION_STEP_SIZE') && absint(EE_MIGRATION_STEP_SIZE) ? EE_MIGRATION_STEP_SIZE : EE_Data_Migration_Manager::step_size;
579 579
 			}
580 580
 			//do what we came to do!
581 581
 			$currently_executing_script->migration_step($step_size);
582 582
 			//can we wrap it up and verify default data?
583 583
 			$init_dbs = false;
584
-			switch($currently_executing_script->get_status()){
584
+			switch ($currently_executing_script->get_status()) {
585 585
 				case EE_Data_Migration_Manager::status_continue:
586 586
 					$response_array = array(
587 587
 						'records_to_migrate'=>$currently_executing_script->count_records_to_migrate(),
@@ -593,16 +593,16 @@  discard block
 block discarded – undo
593 593
 				case EE_Data_Migration_Manager::status_completed:
594 594
 					//ok so THAT script has completed
595 595
 					$this->update_current_database_state_to($this->script_migrates_to_version($current_script_name));
596
-					$response_array =  array(
596
+					$response_array = array(
597 597
 							'records_to_migrate'=>$currently_executing_script->count_records_to_migrate(),
598 598
 							'records_migrated'=>$currently_executing_script->count_records_migrated(),
599 599
 							'status'=> EE_Data_Migration_Manager::status_completed,
600 600
 							'message'=>$currently_executing_script->get_feedback_message(),
601
-							'script'=> sprintf(__("%s Completed",'event_espresso'),$currently_executing_script->pretty_name())
601
+							'script'=> sprintf(__("%s Completed", 'event_espresso'), $currently_executing_script->pretty_name())
602 602
 						);
603 603
 					//check if there are any more after this one.
604 604
 					$scripts_remaining = $this->check_for_applicable_data_migration_scripts();
605
-					if( ! $scripts_remaining ){
605
+					if ( ! $scripts_remaining) {
606 606
 						//we should be good to allow them to exit maintenance mode now
607 607
 						EE_Maintenance_Mode::instance()->set_maintenance_level(intval(EE_Maintenance_Mode::level_0_not_in_maintenance));
608 608
 						////huh, no more scripts to run... apparently we're done!
@@ -616,39 +616,39 @@  discard block
 block discarded – undo
616 616
 						'records_to_migrate'=>$currently_executing_script->count_records_to_migrate(),
617 617
 						'records_migrated'=>$currently_executing_script->count_records_migrated(),
618 618
 						'status'=> $currently_executing_script->get_status(),
619
-						'message'=>  sprintf(__("Minor errors occurred during %s: %s", "event_espresso"), $currently_executing_script->pretty_name(), implode(", ",$currently_executing_script->get_errors())),
619
+						'message'=>  sprintf(__("Minor errors occurred during %s: %s", "event_espresso"), $currently_executing_script->pretty_name(), implode(", ", $currently_executing_script->get_errors())),
620 620
 						'script'=>$currently_executing_script->pretty_name()
621 621
 					);
622 622
 					break;
623 623
 			}
624
-		}catch(Exception $e){
624
+		} catch (Exception $e) {
625 625
 			//ok so some exception was thrown which killed the data migration script
626 626
 			//double-check we have a real script
627
-			if($currently_executing_script instanceof EE_Data_Migration_Script_Base){
627
+			if ($currently_executing_script instanceof EE_Data_Migration_Script_Base) {
628 628
 				$script_name = $currently_executing_script->pretty_name();
629 629
 				$currently_executing_script->set_broken();
630 630
 				$currently_executing_script->add_error($e->getMessage());
631
-			}else{
631
+			} else {
632 632
 				$script_name = __("Error getting Migration Script", "event_espresso");
633 633
 			}
634 634
 			$response_array = array(
635 635
 				'records_to_migrate'=>1,
636 636
 				'records_migrated'=>0,
637 637
 				'status'=>self::status_fatal_error,
638
-				'message'=>  sprintf(__("A fatal error occurred during the migration: %s", "event_espresso"),$e->getMessage()),
638
+				'message'=>  sprintf(__("A fatal error occurred during the migration: %s", "event_espresso"), $e->getMessage()),
639 639
 				'script'=>$script_name
640 640
 			);
641 641
 		}
642 642
 		$successful_save = $this->_save_migrations_ran();
643
-		if($successful_save !== TRUE){
643
+		if ($successful_save !== TRUE) {
644 644
 			//ok so the current wp option didn't save. that's tricky, because we'd like to update it
645 645
 			//and mark it as having a fatal error, but remember- WE CAN'T SAVE THIS WP OPTION!
646 646
 			//however, if we throw an exception, and return that, then the next request
647 647
 			//won't have as much info in it, and it may be able to save
648
-			throw new EE_Error(sprintf(__("The error '%s' occurred updating the status of the migration. This is a FATAL ERROR, but the error is preventing the system from remembering that. Please contact event espresso support.", "event_espresso"),$successful_save));
648
+			throw new EE_Error(sprintf(__("The error '%s' occurred updating the status of the migration. This is a FATAL ERROR, but the error is preventing the system from remembering that. Please contact event espresso support.", "event_espresso"), $successful_save));
649 649
 		}
650 650
 		//if we're all done, initialize EE plugins' default data etc.
651
-		if( $init_dbs ) {
651
+		if ($init_dbs) {
652 652
 			$this->initialize_db_for_enqueued_ee_plugins();
653 653
 		}
654 654
 		return $response_array;
@@ -666,23 +666,23 @@  discard block
 block discarded – undo
666 666
 	 * 'message'=>a string, containing any message you want to show to the user. We may decide to split this up into errors, notifications, and successes
667 667
 	 * 'script'=>a pretty name of the script currently running
668 668
 	 */
669
-	public function response_to_migration_ajax_request(){
669
+	public function response_to_migration_ajax_request() {
670 670
 //		//start output buffer just to make sure we don't mess up the json
671 671
 		ob_start();
672
-		try{
672
+		try {
673 673
 			$response = $this->migration_step();
674
-		}catch(Exception $e){
674
+		} catch (Exception $e) {
675 675
 			$response = array(
676 676
 				'records_to_migrate'=>0,
677 677
 				'records_migrated'=>0,
678 678
 				'status'=> EE_Data_Migration_Manager::status_fatal_error,
679
-				'message'=> sprintf(__("Unknown fatal error occurred: %s", "event_espresso"),$e->getMessage()),
679
+				'message'=> sprintf(__("Unknown fatal error occurred: %s", "event_espresso"), $e->getMessage()),
680 680
 				'script'=>'Unknown');
681 681
 			$this->add_error_to_migrations_ran($e->getMessage()."; Stack trace:".$e->getTraceAsString());
682 682
 		}
683 683
 		$warnings_etc = @ob_get_contents();
684 684
 		ob_end_clean();
685
-		$response['message'] .=$warnings_etc;
685
+		$response['message'] .= $warnings_etc;
686 686
 		return $response;
687 687
 	}
688 688
 
@@ -695,14 +695,14 @@  discard block
 block discarded – undo
695 695
 	 * }
696 696
 	 * @return void
697 697
 	 */
698
-	public function update_current_database_state_to($slug_and_version = null){
699
-		if( ! $slug_and_version ){
698
+	public function update_current_database_state_to($slug_and_version = null) {
699
+		if ( ! $slug_and_version) {
700 700
 			//no version was provided, assume it should be at the current code version
701 701
 			$slug_and_version = array('slug' => 'Core', 'version' => espresso_version());
702 702
 		}
703 703
 		$current_database_state = get_option(self::current_database_state);
704
-		$current_database_state[ $slug_and_version[ 'slug' ] ]=$slug_and_version[ 'version' ];
705
-		update_option(self::current_database_state,$current_database_state);
704
+		$current_database_state[$slug_and_version['slug']] = $slug_and_version['version'];
705
+		update_option(self::current_database_state, $current_database_state);
706 706
 	}
707 707
 
708 708
 	/**
@@ -713,20 +713,20 @@  discard block
 block discarded – undo
713 713
 	 * }
714 714
 	 * @return boolean
715 715
 	 */
716
-	public function database_needs_updating_to( $slug_and_version ) {
716
+	public function database_needs_updating_to($slug_and_version) {
717 717
 
718
-		$slug = $slug_and_version[ 'slug' ];
719
-		$version = $slug_and_version[ 'version' ];
718
+		$slug = $slug_and_version['slug'];
719
+		$version = $slug_and_version['version'];
720 720
 		$current_database_state = get_option(self::current_database_state);
721
-		if( ! isset( $current_database_state[ $slug ] ) ) {
721
+		if ( ! isset($current_database_state[$slug])) {
722 722
 			return true;
723
-		}else{
723
+		} else {
724 724
 			//just compare the first 3 parts of version string, eg "4.7.1", not "4.7.1.dev.032" because DBs shouldn't change on nano version changes
725
-			$version_parts_current_db_state = array_slice( explode('.', $current_database_state[ $slug ] ), 0, 3);
726
-			$version_parts_of_provided_db_state = array_slice( explode( '.', $version ), 0, 3 );
725
+			$version_parts_current_db_state = array_slice(explode('.', $current_database_state[$slug]), 0, 3);
726
+			$version_parts_of_provided_db_state = array_slice(explode('.', $version), 0, 3);
727 727
 			$needs_updating = false;
728
-			foreach($version_parts_current_db_state as $offset => $version_part_in_current_db_state ) {
729
-				if( $version_part_in_current_db_state < $version_parts_of_provided_db_state[ $offset ] ) {
728
+			foreach ($version_parts_current_db_state as $offset => $version_part_in_current_db_state) {
729
+				if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[$offset]) {
730 730
 					$needs_updating = true;
731 731
 					break;
732 732
 				}
@@ -748,7 +748,7 @@  discard block
 block discarded – undo
748 748
      */
749 749
     public function get_all_data_migration_scripts_available()
750 750
     {
751
-        if (! $this->_data_migration_class_to_filepath_map) {
751
+        if ( ! $this->_data_migration_class_to_filepath_map) {
752 752
             $this->_data_migration_class_to_filepath_map = array();
753 753
             foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
754 754
                 // strip any placeholders added to classname to make it a unique array key
@@ -757,7 +757,7 @@  discard block
 block discarded – undo
757 757
                     ? $eeAddonClass
758 758
                     : '';
759 759
                 $folder_path  = EEH_File::end_with_directory_separator($folder_path);
760
-                $files        = glob($folder_path . '*.dms.php');
760
+                $files        = glob($folder_path.'*.dms.php');
761 761
                 if (empty($files)) {
762 762
                     continue;
763 763
                 }
@@ -783,7 +783,7 @@  discard block
 block discarded – undo
783 783
                             '4.3.0.alpha.019'
784 784
                         );
785 785
                     }
786
-                    $this->_data_migration_class_to_filepath_map[ $classname ] = $file;
786
+                    $this->_data_migration_class_to_filepath_map[$classname] = $file;
787 787
                 }
788 788
             }
789 789
             EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
@@ -798,7 +798,7 @@  discard block
 block discarded – undo
798 798
 	 * from each addon, and check if they need updating,
799 799
 	 * @return boolean
800 800
 	 */
801
-	public function addons_need_updating(){
801
+	public function addons_need_updating() {
802 802
 		return false;
803 803
 	}
804 804
 	/**
@@ -807,25 +807,25 @@  discard block
 block discarded – undo
807 807
 	 * @param string $error_message
808 808
 	 * @throws EE_Error
809 809
 	 */
810
-	public function add_error_to_migrations_ran($error_message){
810
+	public function add_error_to_migrations_ran($error_message) {
811 811
 		//get last-ran migration script
812 812
 		global $wpdb;
813
-		$last_migration_script_option = $wpdb->get_row("SELECT * FROM $wpdb->options WHERE option_name like '".EE_Data_Migration_Manager::data_migration_script_option_prefix."%' ORDER BY option_id DESC LIMIT 1",ARRAY_A);
813
+		$last_migration_script_option = $wpdb->get_row("SELECT * FROM $wpdb->options WHERE option_name like '".EE_Data_Migration_Manager::data_migration_script_option_prefix."%' ORDER BY option_id DESC LIMIT 1", ARRAY_A);
814 814
 
815 815
 		$last_ran_migration_script_properties = isset($last_migration_script_option['option_value']) ? maybe_unserialize($last_migration_script_option['option_value']) : null;
816 816
 		//now, tread lightly because we're here because a FATAL non-catchable error
817 817
 		//was thrown last time when we were trying to run a data migration script
818 818
 		//so the fatal error could have happened while getting the migration script
819 819
 		//or doing running it...
820
-		$versions_migrated_to = isset($last_migration_script_option['option_name']) ? str_replace(EE_Data_Migration_Manager::data_migration_script_option_prefix,"",$last_migration_script_option['option_name']) : null;
820
+		$versions_migrated_to = isset($last_migration_script_option['option_name']) ? str_replace(EE_Data_Migration_Manager::data_migration_script_option_prefix, "", $last_migration_script_option['option_name']) : null;
821 821
 
822 822
 		//check if it THINKS its a data migration script and especially if it's one that HASN'T finished yet
823 823
 		//because if it has finished, then it obviously couldn't be the cause of this error, right? (because its all done)
824
-		if(isset($last_ran_migration_script_properties['class']) && isset($last_ran_migration_script_properties['_status']) && $last_ran_migration_script_properties['_status'] != self::status_completed){
824
+		if (isset($last_ran_migration_script_properties['class']) && isset($last_ran_migration_script_properties['_status']) && $last_ran_migration_script_properties['_status'] != self::status_completed) {
825 825
 			//ok then just add this error to its list of errors
826 826
 			$last_ran_migration_script_properties['_errors'][] = $error_message;
827 827
 			$last_ran_migration_script_properties['_status'] = self::status_fatal_error;
828
-		}else{
828
+		} else {
829 829
 			//so we don't even know which script was last running
830 830
 			//use the data migration error stub, which is designed specifically for this type of thing
831 831
 			$general_migration_error = new EE_DMS_Unknown_1_0_0();
@@ -835,39 +835,39 @@  discard block
 block discarded – undo
835 835
 			$versions_migrated_to = 'Unknown.1.0.0';
836 836
 			//now just to make sure appears as last (in case the were previously a fatal error like this)
837 837
 			//delete the old one
838
-			delete_option( self::data_migration_script_option_prefix . $versions_migrated_to );
838
+			delete_option(self::data_migration_script_option_prefix.$versions_migrated_to);
839 839
 		}
840
-		update_option(self::data_migration_script_option_prefix.$versions_migrated_to,$last_ran_migration_script_properties);
840
+		update_option(self::data_migration_script_option_prefix.$versions_migrated_to, $last_ran_migration_script_properties);
841 841
 
842 842
 	}
843 843
 	/**
844 844
 	 * saves what data migrations have ran to the database
845 845
 	 * @return mixed TRUE if successfully saved migrations ran, string if an error occurred
846 846
 	 */
847
-	protected function _save_migrations_ran(){
848
-		if($this->_data_migrations_ran == null){
847
+	protected function _save_migrations_ran() {
848
+		if ($this->_data_migrations_ran == null) {
849 849
 			$this->get_data_migrations_ran();
850 850
 		}
851 851
 		//now, we don't want to save actual classes to the DB because that's messy
852 852
 		$successful_updates = true;
853
-		foreach($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin){
854
-			foreach($migrations_ran_for_plugin as $version_string => $array_or_migration_obj){
853
+		foreach ($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin) {
854
+			foreach ($migrations_ran_for_plugin as $version_string => $array_or_migration_obj) {
855 855
 	//			echo "saving migration script to $version_string<br>";
856 856
 				$plugin_slug_for_use_in_option_name = $plugin_slug.".";
857 857
 				$option_name = self::data_migration_script_option_prefix.$plugin_slug_for_use_in_option_name.$version_string;
858 858
 				$old_option_value = get_option($option_name);
859
-				if($array_or_migration_obj instanceof EE_Data_Migration_Script_Base){
859
+				if ($array_or_migration_obj instanceof EE_Data_Migration_Script_Base) {
860 860
 					$script_array_for_saving = $array_or_migration_obj->properties_as_array();
861
-					if( $old_option_value != $script_array_for_saving){
862
-						$successful_updates = update_option($option_name,$script_array_for_saving);
861
+					if ($old_option_value != $script_array_for_saving) {
862
+						$successful_updates = update_option($option_name, $script_array_for_saving);
863 863
 					}
864
-				}else{//we don't know what this array-thing is. So just save it as-is
864
+				} else {//we don't know what this array-thing is. So just save it as-is
865 865
 	//				$array_of_migrations[$version_string] = $array_or_migration_obj;
866
-					if($old_option_value != $array_or_migration_obj){
867
-						$successful_updates = update_option($option_name,$array_or_migration_obj);
866
+					if ($old_option_value != $array_or_migration_obj) {
867
+						$successful_updates = update_option($option_name, $array_or_migration_obj);
868 868
 					}
869 869
 				}
870
-				if( ! $successful_updates ){
870
+				if ( ! $successful_updates) {
871 871
 					global $wpdb;
872 872
 					return $wpdb->last_error;
873 873
 				}
@@ -891,17 +891,17 @@  discard block
 block discarded – undo
891 891
 	 * @return EE_Data_Migration_Script_Base
892 892
 	 * @throws EE_Error
893 893
 	 */
894
-	function _instantiate_script_from_properties_array($properties_array){
895
-		if( ! isset($properties_array['class'])){
896
-			throw new EE_Error(sprintf(__("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"),implode(",",$properties_array)));
894
+	function _instantiate_script_from_properties_array($properties_array) {
895
+		if ( ! isset($properties_array['class'])) {
896
+			throw new EE_Error(sprintf(__("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"), implode(",", $properties_array)));
897 897
 		}
898 898
 		$class_name = $properties_array['class'];
899
-		if( ! class_exists($class_name)){
900
-			throw new EE_Error(sprintf(__("There is no migration script named %s", "event_espresso"),$class_name));
899
+		if ( ! class_exists($class_name)) {
900
+			throw new EE_Error(sprintf(__("There is no migration script named %s", "event_espresso"), $class_name));
901 901
 		}
902 902
 		$class = new $class_name;
903
-		if( ! $class instanceof EE_Data_Migration_Script_Base){
904
-			throw new EE_Error(sprintf(__("Class '%s' is supposed to be a migration script. Its not, its a '%s'", "event_espresso"),$class_name,get_class($class)));
903
+		if ( ! $class instanceof EE_Data_Migration_Script_Base) {
904
+			throw new EE_Error(sprintf(__("Class '%s' is supposed to be a migration script. Its not, its a '%s'", "event_espresso"), $class_name, get_class($class)));
905 905
 		}
906 906
 		$class->instantiate_from_array_of_properties($properties_array);
907 907
 		return $class;
@@ -913,25 +913,25 @@  discard block
 block discarded – undo
913 913
 	 * @param string $plugin_slug the slug for the ee plugin we are searching for. Default is 'Core'
914 914
 	 * @return string
915 915
 	 */
916
-	public function get_most_up_to_date_dms($plugin_slug = 'Core'){
916
+	public function get_most_up_to_date_dms($plugin_slug = 'Core') {
917 917
 		$class_to_filepath_map = $this->get_all_data_migration_scripts_available();
918 918
 		$most_up_to_date_dms_classname = NULL;
919
-		foreach($class_to_filepath_map as $classname => $filepath){
920
-			if($most_up_to_date_dms_classname === NULL){
919
+		foreach ($class_to_filepath_map as $classname => $filepath) {
920
+			if ($most_up_to_date_dms_classname === NULL) {
921 921
 				$migrates_to = $this->script_migrates_to_version($classname);
922
-				$this_plugin_slug = $migrates_to[ 'slug' ];
922
+				$this_plugin_slug = $migrates_to['slug'];
923 923
 //				$version_string = $migrates_to[ 'version' ];
924 924
 //				$details = $this->parse_dms_classname($classname);
925
-				if($this_plugin_slug == $plugin_slug){
925
+				if ($this_plugin_slug == $plugin_slug) {
926 926
 					//if it's for core, it wins
927 927
 					$most_up_to_date_dms_classname = $classname;
928 928
 				}
929 929
 				//if it wasn't for core, we must keep searching for one that is!
930 930
 				continue;
931
-			}else{
932
-				$champion_migrates_to= $this->script_migrates_to_version($most_up_to_date_dms_classname);
931
+			} else {
932
+				$champion_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms_classname);
933 933
 				$contender_migrates_to = $this->script_migrates_to_version($classname);
934
-				if($contender_migrates_to[ 'slug' ] == $plugin_slug && version_compare($champion_migrates_to[ 'version' ], $contender_migrates_to[ 'version' ], '<')){
934
+				if ($contender_migrates_to['slug'] == $plugin_slug && version_compare($champion_migrates_to['version'], $contender_migrates_to['version'], '<')) {
935 935
 					//so the contenders version is higher and its for Core
936 936
 					$most_up_to_date_dms_classname = $classname;
937 937
 				}
@@ -951,11 +951,11 @@  discard block
 block discarded – undo
951 951
 	 * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
952 952
 	 * @return EE_Data_Migration_Script_Base
953 953
 	 */
954
-	public function get_migration_ran( $version, $plugin_slug = 'Core' ) {
954
+	public function get_migration_ran($version, $plugin_slug = 'Core') {
955 955
 		$migrations_ran = $this->get_data_migrations_ran();
956
-		if( isset( $migrations_ran[ $plugin_slug ] ) && isset( $migrations_ran[ $plugin_slug ][ $version ] ) ){
957
-			return $migrations_ran[ $plugin_slug ][ $version ];
958
-		}else{
956
+		if (isset($migrations_ran[$plugin_slug]) && isset($migrations_ran[$plugin_slug][$version])) {
957
+			return $migrations_ran[$plugin_slug][$version];
958
+		} else {
959 959
 			return NULL;
960 960
 		}
961 961
 	}
@@ -967,20 +967,20 @@  discard block
 block discarded – undo
967 967
 	 * @return bool
968 968
 	 * @throws EE_Error
969 969
 	 */
970
-	public function reattempt(){
970
+	public function reattempt() {
971 971
 		//find if the last-ran script was borked
972 972
 		//set it as being non-borked (we shouldn't ever get DMSs that we don't recognize)
973 973
 		//add an 'error' saying that we attempted to reset
974 974
 		//does it have a stage that was borked too? if so make it no longer borked
975 975
 		//add an 'error' saying we attempted to reset
976 976
 		$last_ran_script = $this->get_last_ran_script();
977
-		if( $last_ran_script instanceof EE_DMS_Unknown_1_0_0 ){
977
+		if ($last_ran_script instanceof EE_DMS_Unknown_1_0_0) {
978 978
 			//if it was an error DMS, just mark it as complete (if another error occurs it will overwrite it)
979 979
 			$last_ran_script->set_completed();
980
-		}elseif( $last_ran_script instanceof EE_Data_Migration_Script_Base ) {
980
+		}elseif ($last_ran_script instanceof EE_Data_Migration_Script_Base) {
981 981
 			$last_ran_script->reattempt();
982
-		}else{
983
-			throw new EE_Error( sprintf( __( 'Unable to reattempt the last ran migration script because it was not a valid migration script. || It was %s', 'event_espresso' ), print_r( $last_ran_script, true ) ) );
982
+		} else {
983
+			throw new EE_Error(sprintf(__('Unable to reattempt the last ran migration script because it was not a valid migration script. || It was %s', 'event_espresso'), print_r($last_ran_script, true)));
984 984
 		}
985 985
 		return $this->_save_migrations_ran();
986 986
 	}
@@ -990,19 +990,19 @@  discard block
 block discarded – undo
990 990
 	 * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
991 991
 	 * @return boolean
992 992
 	 */
993
-	public function migration_has_ran( $version, $plugin_slug = 'Core' ) {
994
-		return $this->get_migration_ran( $version, $plugin_slug ) !== NULL;
993
+	public function migration_has_ran($version, $plugin_slug = 'Core') {
994
+		return $this->get_migration_ran($version, $plugin_slug) !== NULL;
995 995
 	}
996 996
 	/**
997 997
 	 * Enqueues this ee plugin to have its data initialized
998 998
 	 * @param string $plugin_slug either 'Core' or EE_Addon::name()'s return value
999 999
 	 */
1000
-	public function enqueue_db_initialization_for( $plugin_slug ) {
1000
+	public function enqueue_db_initialization_for($plugin_slug) {
1001 1001
 		$queue = $this->get_db_initialization_queue();
1002
-		if( ! in_array( $plugin_slug, $queue ) ) {
1002
+		if ( ! in_array($plugin_slug, $queue)) {
1003 1003
 			$queue[] = $plugin_slug;
1004 1004
 		}
1005
-		update_option( self::db_init_queue_option_name, $queue );
1005
+		update_option(self::db_init_queue_option_name, $queue);
1006 1006
 	}
1007 1007
 	/**
1008 1008
 	 * Calls EE_Addon::initialize_db_if_no_migrations_required() on each addon
@@ -1012,26 +1012,26 @@  discard block
 block discarded – undo
1012 1012
 	public function initialize_db_for_enqueued_ee_plugins() {
1013 1013
 //		EEH_Debug_Tools::instance()->start_timer( 'initialize_db_for_enqueued_ee_plugins' );
1014 1014
 		$queue = $this->get_db_initialization_queue();
1015
-		foreach( $queue as $plugin_slug ) {
1016
-			$most_up_to_date_dms = $this->get_most_up_to_date_dms( $plugin_slug );
1017
-			if( ! $most_up_to_date_dms ) {
1015
+		foreach ($queue as $plugin_slug) {
1016
+			$most_up_to_date_dms = $this->get_most_up_to_date_dms($plugin_slug);
1017
+			if ( ! $most_up_to_date_dms) {
1018 1018
 				//if there is NO DMS for this plugin, obviously there's no schema to verify anyways
1019 1019
 				$verify_db = false;
1020
-			}else{
1021
-				$most_up_to_date_dms_migrates_to = $this->script_migrates_to_version( $most_up_to_date_dms );
1022
-				$verify_db = $this->database_needs_updating_to( $most_up_to_date_dms_migrates_to );
1020
+			} else {
1021
+				$most_up_to_date_dms_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms);
1022
+				$verify_db = $this->database_needs_updating_to($most_up_to_date_dms_migrates_to);
1023 1023
 			}
1024
-			if( $plugin_slug == 'Core' ){
1024
+			if ($plugin_slug == 'Core') {
1025 1025
 				EE_System::instance()->initialize_db_if_no_migrations_required(
1026 1026
 						false,
1027 1027
 						$verify_db
1028 1028
 					);
1029
-			}else{
1029
+			} else {
1030 1030
 				//just loop through the addons to make sure their database is setup
1031
-				foreach( EE_Registry::instance()->addons as $addon ) {
1032
-					if( $addon->name() == $plugin_slug ) {
1031
+				foreach (EE_Registry::instance()->addons as $addon) {
1032
+					if ($addon->name() == $plugin_slug) {
1033 1033
 
1034
-						$addon->initialize_db_if_no_migrations_required( $verify_db );
1034
+						$addon->initialize_db_if_no_migrations_required($verify_db);
1035 1035
 						break;
1036 1036
 					}
1037 1037
 				}
@@ -1041,7 +1041,7 @@  discard block
 block discarded – undo
1041 1041
 //		EEH_Debug_Tools::instance()->show_times();
1042 1042
 		//because we just initialized the DBs for the enqueued ee plugins
1043 1043
 		//we don't need to keep remembering which ones needed to be initialized
1044
-		delete_option( self::db_init_queue_option_name );
1044
+		delete_option(self::db_init_queue_option_name);
1045 1045
 	}
1046 1046
 
1047 1047
 	/**
@@ -1050,8 +1050,8 @@  discard block
 block discarded – undo
1050 1050
 	 * 'Core', or the return value of EE_Addon::name() for an addon
1051 1051
 	 * @return array
1052 1052
 	 */
1053
-	public function get_db_initialization_queue(){
1054
-		return get_option ( self::db_init_queue_option_name, array() );
1053
+	public function get_db_initialization_queue() {
1054
+		return get_option(self::db_init_queue_option_name, array());
1055 1055
 	}
1056 1056
 
1057 1057
 	/**
@@ -1061,13 +1061,13 @@  discard block
 block discarded – undo
1061 1061
 	 * @throws EE_Error
1062 1062
 	 */
1063 1063
 	protected function _get_table_analysis() {
1064
-		if( $this->_table_analysis instanceof TableAnalysis ) {
1064
+		if ($this->_table_analysis instanceof TableAnalysis) {
1065 1065
 			return $this->_table_analysis;
1066 1066
 		} else {
1067 1067
 			throw new EE_Error(
1068 1068
 				sprintf(
1069
-					__( 'Table analysis class on class %1$s is not set properly.', 'event_espresso'),
1070
-					get_class( $this )
1069
+					__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
1070
+					get_class($this)
1071 1071
 				)
1072 1072
 			);
1073 1073
 		}
@@ -1080,13 +1080,13 @@  discard block
 block discarded – undo
1080 1080
 	 * @throws EE_Error
1081 1081
 	 */
1082 1082
 	protected function _get_table_manager() {
1083
-		if( $this->_table_manager instanceof TableManager ) {
1083
+		if ($this->_table_manager instanceof TableManager) {
1084 1084
 			return $this->_table_manager;
1085 1085
 		} else {
1086 1086
 			throw new EE_Error(
1087 1087
 				sprintf(
1088
-					__( 'Table manager class on class %1$s is not set properly.', 'event_espresso'),
1089
-					get_class( $this )
1088
+					__('Table manager class on class %1$s is not set properly.', 'event_espresso'),
1089
+					get_class($this)
1090 1090
 				)
1091 1091
 			);
1092 1092
 		}
Please login to merge, or discard this patch.
core/libraries/plugin_api/EE_Register_Addon.lib.php 2 patches
Indentation   +1092 added lines, -1092 removed lines patch added patch discarded remove patch
@@ -25,1152 +25,1152 @@
 block discarded – undo
25 25
 class EE_Register_Addon implements EEI_Plugin_API
26 26
 {
27 27
 
28
-    /**
29
-     * possibly truncated version of the EE core version string
30
-     *
31
-     * @var string
32
-     */
33
-    protected static $_core_version = '';
28
+	/**
29
+	 * possibly truncated version of the EE core version string
30
+	 *
31
+	 * @var string
32
+	 */
33
+	protected static $_core_version = '';
34 34
 
35
-    /**
36
-     * Holds values for registered addons
37
-     *
38
-     * @var array
39
-     */
40
-    protected static $_settings = array();
35
+	/**
36
+	 * Holds values for registered addons
37
+	 *
38
+	 * @var array
39
+	 */
40
+	protected static $_settings = array();
41 41
 
42
-    /**
43
-     * @var  array $_incompatible_addons keys are addon SLUGS
44
-     * (first argument passed to EE_Register_Addon::register()), keys are
45
-     * their MINIMUM VERSION (with all 5 parts. Eg 1.2.3.rc.004).
46
-     * Generally this should be used sparingly, as we don't want to muddle up
47
-     * EE core with knowledge of ALL the addons out there.
48
-     * If you want NO versions of an addon to run with a certain version of core,
49
-     * it's usually best to define the addon's "min_core_version" as part of its call
50
-     * to EE_Register_Addon::register(), rather than using this array with a super high value for its
51
-     * minimum plugin version.
52
-     * @access    protected
53
-     */
54
-    protected static $_incompatible_addons = array(
55
-        'Multi_Event_Registration' => '2.0.11.rc.002',
56
-        'Promotions'               => '1.0.0.rc.084',
57
-    );
42
+	/**
43
+	 * @var  array $_incompatible_addons keys are addon SLUGS
44
+	 * (first argument passed to EE_Register_Addon::register()), keys are
45
+	 * their MINIMUM VERSION (with all 5 parts. Eg 1.2.3.rc.004).
46
+	 * Generally this should be used sparingly, as we don't want to muddle up
47
+	 * EE core with knowledge of ALL the addons out there.
48
+	 * If you want NO versions of an addon to run with a certain version of core,
49
+	 * it's usually best to define the addon's "min_core_version" as part of its call
50
+	 * to EE_Register_Addon::register(), rather than using this array with a super high value for its
51
+	 * minimum plugin version.
52
+	 * @access    protected
53
+	 */
54
+	protected static $_incompatible_addons = array(
55
+		'Multi_Event_Registration' => '2.0.11.rc.002',
56
+		'Promotions'               => '1.0.0.rc.084',
57
+	);
58 58
 
59 59
 
60
-    /**
61
-     * We should always be comparing core to a version like '4.3.0.rc.000',
62
-     * not just '4.3.0'.
63
-     * So if the addon developer doesn't provide that full version string,
64
-     * fill in the blanks for them
65
-     *
66
-     * @param string $min_core_version
67
-     * @return string always like '4.3.0.rc.000'
68
-     */
69
-    protected static function _effective_version($min_core_version)
70
-    {
71
-        // versions: 4 . 3 . 1 . p . 123
72
-        // offsets:    0 . 1 . 2 . 3 . 4
73
-        $version_parts = explode('.', $min_core_version);
74
-        //check they specified the micro version (after 2nd period)
75
-        if (! isset($version_parts[2])) {
76
-            $version_parts[2] = '0';
77
-        }
78
-        //if they didn't specify the 'p', or 'rc' part. Just assume the lowest possible
79
-        //soon we can assume that's 'rc', but this current version is 'alpha'
80
-        if (! isset($version_parts[3])) {
81
-            $version_parts[3] = 'dev';
82
-        }
83
-        if (! isset($version_parts[4])) {
84
-            $version_parts[4] = '000';
85
-        }
86
-        return implode('.', $version_parts);
87
-    }
60
+	/**
61
+	 * We should always be comparing core to a version like '4.3.0.rc.000',
62
+	 * not just '4.3.0'.
63
+	 * So if the addon developer doesn't provide that full version string,
64
+	 * fill in the blanks for them
65
+	 *
66
+	 * @param string $min_core_version
67
+	 * @return string always like '4.3.0.rc.000'
68
+	 */
69
+	protected static function _effective_version($min_core_version)
70
+	{
71
+		// versions: 4 . 3 . 1 . p . 123
72
+		// offsets:    0 . 1 . 2 . 3 . 4
73
+		$version_parts = explode('.', $min_core_version);
74
+		//check they specified the micro version (after 2nd period)
75
+		if (! isset($version_parts[2])) {
76
+			$version_parts[2] = '0';
77
+		}
78
+		//if they didn't specify the 'p', or 'rc' part. Just assume the lowest possible
79
+		//soon we can assume that's 'rc', but this current version is 'alpha'
80
+		if (! isset($version_parts[3])) {
81
+			$version_parts[3] = 'dev';
82
+		}
83
+		if (! isset($version_parts[4])) {
84
+			$version_parts[4] = '000';
85
+		}
86
+		return implode('.', $version_parts);
87
+	}
88 88
 
89 89
 
90
-    /**
91
-     * Returns whether or not the min core version requirement of the addon is met
92
-     *
93
-     * @param string $min_core_version    the minimum core version required by the addon
94
-     * @param string $actual_core_version the actual core version, optional
95
-     * @return boolean
96
-     */
97
-    public static function _meets_min_core_version_requirement(
98
-        $min_core_version,
99
-        $actual_core_version = EVENT_ESPRESSO_VERSION
100
-    ) {
101
-        return version_compare(
102
-            self::_effective_version($actual_core_version),
103
-            self::_effective_version($min_core_version),
104
-            '>='
105
-        );
106
-    }
90
+	/**
91
+	 * Returns whether or not the min core version requirement of the addon is met
92
+	 *
93
+	 * @param string $min_core_version    the minimum core version required by the addon
94
+	 * @param string $actual_core_version the actual core version, optional
95
+	 * @return boolean
96
+	 */
97
+	public static function _meets_min_core_version_requirement(
98
+		$min_core_version,
99
+		$actual_core_version = EVENT_ESPRESSO_VERSION
100
+	) {
101
+		return version_compare(
102
+			self::_effective_version($actual_core_version),
103
+			self::_effective_version($min_core_version),
104
+			'>='
105
+		);
106
+	}
107 107
 
108 108
 
109
-    /**
110
-     * Method for registering new EE_Addons.
111
-     * Should be called AFTER AHEE__EE_System__load_espresso_addons but BEFORE
112
-     * AHEE__EE_System___detect_if_activation_or_upgrade__begin in order to register all its components. However, it
113
-     * may also be called after the 'activate_plugin' action (when an addon is activated), because an activating addon
114
-     * won't be loaded by WP until after AHEE__EE_System__load_espresso_addons has fired. If its called after
115
-     * 'activate_plugin', it registers the addon still, but its components are not registered
116
-     * (they shouldn't be needed anyways, because it's just an activation request and they won't have a chance to do
117
-     * anything anyways). Instead, it just sets the newly-activated addon's activation indicator wp option and returns
118
-     * (so that we can detect that the addon has activated on the subsequent request)
119
-     *
120
-     * @since    4.3.0
121
-     * @param string                  $addon_name                       [Required] the EE_Addon's name.
122
-     * @param  array                  $setup_args                       {
123
-     *                                                                  An array of arguments provided for registering
124
-     *                                                                  the message type.
125
-     * @type  string                  $class_name                       the addon's main file name.
126
-     *                                                                  If left blank, generated from the addon name,
127
-     *                                                                  changes something like "calendar" to
128
-     *                                                                  "EE_Calendar"
129
-     * @type string                   $min_core_version                 the minimum version of EE Core that the
130
-     *                                                                  addon will work with. eg "4.8.1.rc.084"
131
-     * @type string                   $version                          the "software" version for the addon. eg
132
-     *                                                                  "1.0.0.p" for a first stable release, or
133
-     *                                                                  "1.0.0.rc.043" for a version in progress
134
-     * @type string                   $main_file_path                   the full server path to the main file
135
-     *                                                                  loaded directly by WP
136
-     * @type string                   $domain_fqcn                      Fully Qualified Class Name
137
-     *                                                                  for the addon's Domain class
138
-     *                                                                  (see EventEspresso\core\domain\Domain)
139
-     * @type string                   $admin_path                       full server path to the folder where the
140
-     *                                                                  addon\'s admin files reside
141
-     * @type string                   $admin_callback                   a method to be called when the EE Admin is
142
-     *                                                                  first invoked, can be used for hooking into
143
-     *                                                                  any admin page
144
-     * @type string                   $config_section                   the section name for this addon's
145
-     *                                                                  configuration settings section
146
-     *                                                                  (defaults to "addons")
147
-     * @type string                   $config_class                     the class name for this addon's
148
-     *                                                                  configuration settings object
149
-     * @type string                   $config_name                      the class name for this addon's
150
-     *                                                                  configuration settings object
151
-     * @type string $autoloader_paths                                   [Required] an array of class names and the full
152
-     *                                                                  server paths to those files.
153
-     * @type string                   $autoloader_folders               an array of  "full server paths" for any
154
-     *                                                                  folders containing classes that might be
155
-     *                                                                  invoked by the addon
156
-     * @type string                   $dms_paths                        [Required] an array of full server paths to
157
-     *                                                                  folders that contain data migration scripts.
158
-     *                                                                  The key should be the EE_Addon class name that
159
-     *                                                                  this set of data migration scripts belongs to.
160
-     *                                                                  If the EE_Addon class is namespaced, then this
161
-     *                                                                  needs to be the Fully Qualified Class Name
162
-     * @type string                   $module_paths                     an array of full server paths to any
163
-     *                                                                  EED_Modules used by the addon
164
-     * @type string                   $shortcode_paths                  an array of full server paths to folders
165
-     *                                                                  that contain EES_Shortcodes
166
-     * @type string                   $widget_paths                     an array of full server paths to folders
167
-     *                                                                  that contain WP_Widgets
168
-     * @type string                   $pue_options
169
-     * @type array                    $capabilities                     an array indexed by role name
170
-     *                                                                  (i.e administrator,author ) and the values
171
-     *                                                                  are an array of caps to add to the role.
172
-     *                                                                  'administrator' => array(
173
-     *                                                                  'read_addon',
174
-     *                                                                  'edit_addon',
175
-     *                                                                  etc.
176
-     *                                                                  ).
177
-     * @type EE_Meta_Capability_Map[] $capability_maps                  an array of EE_Meta_Capability_Map object
178
-     *                                                                  for any addons that need to register any
179
-     *                                                                  special meta mapped capabilities.  Should
180
-     *                                                                  be indexed where the key is the
181
-     *                                                                  EE_Meta_Capability_Map class name and the
182
-     *                                                                  values are the arguments sent to the class.
183
-     * @type array                    $model_paths                      array of folders containing DB models
184
-     * @see      EE_Register_Model
185
-     * @type array                    $class_paths                      array of folders containing DB classes
186
-     * @see      EE_Register_Model
187
-     * @type array                    $model_extension_paths            array of folders containing DB model
188
-     *                                                                  extensions
189
-     * @see      EE_Register_Model_Extension
190
-     * @type array                    $class_extension_paths            array of folders containing DB class
191
-     *                                                                  extensions
192
-     * @see      EE_Register_Model_Extension
193
-     * @type array message_types {
194
-     *                                                                  An array of message types with the key as
195
-     *                                                                  the message type name and the values as
196
-     *                                                                  below:
197
-     * @type string $mtfilename                                         [Required] The filename of the message type
198
-     *                                                                  being registered. This will be the main
199
-     *                                                                  EE_{Message Type Name}_message_type class.
200
-     *                                                                  for example:
201
-     *                                                                  EE_Declined_Registration_message_type.class.php
202
-     * @type array                    $autoloadpaths                    [Required] An array of paths to add to the
203
-     *                                                                  messages autoloader for the new message type.
204
-     * @type array                    $messengers_to_activate_with      An array of messengers that this message
205
-     *                                                                  type should activate with. Each value in
206
-     *                                                                  the
207
-     *                                                                  array
208
-     *                                                                  should match the name property of a
209
-     *                                                                  EE_messenger. Optional.
210
-     * @type array                    $messengers_to_validate_with      An array of messengers that this message
211
-     *                                                                  type should validate with. Each value in
212
-     *                                                                  the
213
-     *                                                                  array
214
-     *                                                                  should match the name property of an
215
-     *                                                                  EE_messenger.
216
-     *                                                                  Optional.
217
-     *                                                                  }
218
-     * @type array                    $custom_post_types
219
-     * @type array                    $custom_taxonomies
220
-     * @type array                    $payment_method_paths             each element is the folder containing the
221
-     *                                                                  EE_PMT_Base child class
222
-     *                                                                  (eg,
223
-     *                                                                  '/wp-content/plugins/my_plugin/Payomatic/'
224
-     *                                                                  which contains the files
225
-     *                                                                  EE_PMT_Payomatic.pm.php)
226
-     * @type array                    $default_terms
227
-     * @type array                    $namespace                        {
228
-     *                                                                  An array with two items for registering the
229
-     *                                                                  addon's namespace. (If, for some reason, you
230
-     *                                                                  require additional namespaces,
231
-     *                                                                  use
232
-     *                                                                  EventEspresso\core\Psr4Autoloader::addNamespace()
233
-     *                                                                  directly)
234
-     * @see      EventEspresso\core\Psr4Autoloader::addNamespace()
235
-     * @type string                   $FQNS                             the namespace prefix
236
-     * @type string                   $DIR                              a base directory for class files in the
237
-     *                                                                  namespace.
238
-     *                                                                  }
239
-     *                                                                  }
240
-     * @return void
241
-     * @throws DomainException
242
-     * @throws EE_Error
243
-     * @throws InvalidArgumentException
244
-     * @throws ReflectionException
245
-     * @throws InvalidDataTypeException
246
-     * @throws InvalidInterfaceException
247
-     */
248
-    public static function register($addon_name = '', $setup_args = array())
249
-    {
250
-        // required fields MUST be present, so let's make sure they are.
251
-        EE_Register_Addon::_verify_parameters($addon_name, $setup_args);
252
-        // get class name for addon
253
-        $class_name = EE_Register_Addon::_parse_class_name($addon_name, $setup_args);
254
-        //setup $_settings array from incoming values.
255
-        $addon_settings = EE_Register_Addon::_get_addon_settings($class_name, $setup_args);
256
-        // setup PUE
257
-        EE_Register_Addon::_parse_pue_options($addon_name, $class_name, $setup_args);
258
-        // does this addon work with this version of core or WordPress ?
259
-        if (! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
260
-            return;
261
-        }
262
-        // register namespaces
263
-        EE_Register_Addon::_setup_namespaces($addon_settings);
264
-        // check if this is an activation request
265
-        if (EE_Register_Addon::_addon_activation($addon_name, $addon_settings)) {
266
-            // dont bother setting up the rest of the addon atm
267
-            return;
268
-        }
269
-        // we need cars
270
-        EE_Register_Addon::_setup_autoloaders($addon_name);
271
-        // register new models and extensions
272
-        EE_Register_Addon::_register_models_and_extensions($addon_name);
273
-        // setup DMS
274
-        EE_Register_Addon::_register_data_migration_scripts($addon_name);
275
-        // if config_class is present let's register config.
276
-        EE_Register_Addon::_register_config($addon_name);
277
-        // register admin pages
278
-        EE_Register_Addon::_register_admin_pages($addon_name);
279
-        // add to list of modules to be registered
280
-        EE_Register_Addon::_register_modules($addon_name);
281
-        // add to list of shortcodes to be registered
282
-        EE_Register_Addon::_register_shortcodes($addon_name);
283
-        // add to list of widgets to be registered
284
-        EE_Register_Addon::_register_widgets($addon_name);
285
-        // register capability related stuff.
286
-        EE_Register_Addon::_register_capabilities($addon_name);
287
-        // any message type to register?
288
-        EE_Register_Addon::_register_message_types($addon_name);
289
-        // any custom post type/ custom capabilities or default terms to register
290
-        EE_Register_Addon::_register_custom_post_types($addon_name);
291
-        // and any payment methods
292
-        EE_Register_Addon::_register_payment_methods($addon_name);
293
-        // load and instantiate main addon class
294
-        $addon = EE_Register_Addon::_load_and_init_addon_class($addon_name);
295
-        //delay calling after_registration hook on each addon until after all add-ons have been registered.
296
-        add_action('AHEE__EE_System__load_espresso_addons__complete', array($addon, 'after_registration'), 999);
297
-    }
109
+	/**
110
+	 * Method for registering new EE_Addons.
111
+	 * Should be called AFTER AHEE__EE_System__load_espresso_addons but BEFORE
112
+	 * AHEE__EE_System___detect_if_activation_or_upgrade__begin in order to register all its components. However, it
113
+	 * may also be called after the 'activate_plugin' action (when an addon is activated), because an activating addon
114
+	 * won't be loaded by WP until after AHEE__EE_System__load_espresso_addons has fired. If its called after
115
+	 * 'activate_plugin', it registers the addon still, but its components are not registered
116
+	 * (they shouldn't be needed anyways, because it's just an activation request and they won't have a chance to do
117
+	 * anything anyways). Instead, it just sets the newly-activated addon's activation indicator wp option and returns
118
+	 * (so that we can detect that the addon has activated on the subsequent request)
119
+	 *
120
+	 * @since    4.3.0
121
+	 * @param string                  $addon_name                       [Required] the EE_Addon's name.
122
+	 * @param  array                  $setup_args                       {
123
+	 *                                                                  An array of arguments provided for registering
124
+	 *                                                                  the message type.
125
+	 * @type  string                  $class_name                       the addon's main file name.
126
+	 *                                                                  If left blank, generated from the addon name,
127
+	 *                                                                  changes something like "calendar" to
128
+	 *                                                                  "EE_Calendar"
129
+	 * @type string                   $min_core_version                 the minimum version of EE Core that the
130
+	 *                                                                  addon will work with. eg "4.8.1.rc.084"
131
+	 * @type string                   $version                          the "software" version for the addon. eg
132
+	 *                                                                  "1.0.0.p" for a first stable release, or
133
+	 *                                                                  "1.0.0.rc.043" for a version in progress
134
+	 * @type string                   $main_file_path                   the full server path to the main file
135
+	 *                                                                  loaded directly by WP
136
+	 * @type string                   $domain_fqcn                      Fully Qualified Class Name
137
+	 *                                                                  for the addon's Domain class
138
+	 *                                                                  (see EventEspresso\core\domain\Domain)
139
+	 * @type string                   $admin_path                       full server path to the folder where the
140
+	 *                                                                  addon\'s admin files reside
141
+	 * @type string                   $admin_callback                   a method to be called when the EE Admin is
142
+	 *                                                                  first invoked, can be used for hooking into
143
+	 *                                                                  any admin page
144
+	 * @type string                   $config_section                   the section name for this addon's
145
+	 *                                                                  configuration settings section
146
+	 *                                                                  (defaults to "addons")
147
+	 * @type string                   $config_class                     the class name for this addon's
148
+	 *                                                                  configuration settings object
149
+	 * @type string                   $config_name                      the class name for this addon's
150
+	 *                                                                  configuration settings object
151
+	 * @type string $autoloader_paths                                   [Required] an array of class names and the full
152
+	 *                                                                  server paths to those files.
153
+	 * @type string                   $autoloader_folders               an array of  "full server paths" for any
154
+	 *                                                                  folders containing classes that might be
155
+	 *                                                                  invoked by the addon
156
+	 * @type string                   $dms_paths                        [Required] an array of full server paths to
157
+	 *                                                                  folders that contain data migration scripts.
158
+	 *                                                                  The key should be the EE_Addon class name that
159
+	 *                                                                  this set of data migration scripts belongs to.
160
+	 *                                                                  If the EE_Addon class is namespaced, then this
161
+	 *                                                                  needs to be the Fully Qualified Class Name
162
+	 * @type string                   $module_paths                     an array of full server paths to any
163
+	 *                                                                  EED_Modules used by the addon
164
+	 * @type string                   $shortcode_paths                  an array of full server paths to folders
165
+	 *                                                                  that contain EES_Shortcodes
166
+	 * @type string                   $widget_paths                     an array of full server paths to folders
167
+	 *                                                                  that contain WP_Widgets
168
+	 * @type string                   $pue_options
169
+	 * @type array                    $capabilities                     an array indexed by role name
170
+	 *                                                                  (i.e administrator,author ) and the values
171
+	 *                                                                  are an array of caps to add to the role.
172
+	 *                                                                  'administrator' => array(
173
+	 *                                                                  'read_addon',
174
+	 *                                                                  'edit_addon',
175
+	 *                                                                  etc.
176
+	 *                                                                  ).
177
+	 * @type EE_Meta_Capability_Map[] $capability_maps                  an array of EE_Meta_Capability_Map object
178
+	 *                                                                  for any addons that need to register any
179
+	 *                                                                  special meta mapped capabilities.  Should
180
+	 *                                                                  be indexed where the key is the
181
+	 *                                                                  EE_Meta_Capability_Map class name and the
182
+	 *                                                                  values are the arguments sent to the class.
183
+	 * @type array                    $model_paths                      array of folders containing DB models
184
+	 * @see      EE_Register_Model
185
+	 * @type array                    $class_paths                      array of folders containing DB classes
186
+	 * @see      EE_Register_Model
187
+	 * @type array                    $model_extension_paths            array of folders containing DB model
188
+	 *                                                                  extensions
189
+	 * @see      EE_Register_Model_Extension
190
+	 * @type array                    $class_extension_paths            array of folders containing DB class
191
+	 *                                                                  extensions
192
+	 * @see      EE_Register_Model_Extension
193
+	 * @type array message_types {
194
+	 *                                                                  An array of message types with the key as
195
+	 *                                                                  the message type name and the values as
196
+	 *                                                                  below:
197
+	 * @type string $mtfilename                                         [Required] The filename of the message type
198
+	 *                                                                  being registered. This will be the main
199
+	 *                                                                  EE_{Message Type Name}_message_type class.
200
+	 *                                                                  for example:
201
+	 *                                                                  EE_Declined_Registration_message_type.class.php
202
+	 * @type array                    $autoloadpaths                    [Required] An array of paths to add to the
203
+	 *                                                                  messages autoloader for the new message type.
204
+	 * @type array                    $messengers_to_activate_with      An array of messengers that this message
205
+	 *                                                                  type should activate with. Each value in
206
+	 *                                                                  the
207
+	 *                                                                  array
208
+	 *                                                                  should match the name property of a
209
+	 *                                                                  EE_messenger. Optional.
210
+	 * @type array                    $messengers_to_validate_with      An array of messengers that this message
211
+	 *                                                                  type should validate with. Each value in
212
+	 *                                                                  the
213
+	 *                                                                  array
214
+	 *                                                                  should match the name property of an
215
+	 *                                                                  EE_messenger.
216
+	 *                                                                  Optional.
217
+	 *                                                                  }
218
+	 * @type array                    $custom_post_types
219
+	 * @type array                    $custom_taxonomies
220
+	 * @type array                    $payment_method_paths             each element is the folder containing the
221
+	 *                                                                  EE_PMT_Base child class
222
+	 *                                                                  (eg,
223
+	 *                                                                  '/wp-content/plugins/my_plugin/Payomatic/'
224
+	 *                                                                  which contains the files
225
+	 *                                                                  EE_PMT_Payomatic.pm.php)
226
+	 * @type array                    $default_terms
227
+	 * @type array                    $namespace                        {
228
+	 *                                                                  An array with two items for registering the
229
+	 *                                                                  addon's namespace. (If, for some reason, you
230
+	 *                                                                  require additional namespaces,
231
+	 *                                                                  use
232
+	 *                                                                  EventEspresso\core\Psr4Autoloader::addNamespace()
233
+	 *                                                                  directly)
234
+	 * @see      EventEspresso\core\Psr4Autoloader::addNamespace()
235
+	 * @type string                   $FQNS                             the namespace prefix
236
+	 * @type string                   $DIR                              a base directory for class files in the
237
+	 *                                                                  namespace.
238
+	 *                                                                  }
239
+	 *                                                                  }
240
+	 * @return void
241
+	 * @throws DomainException
242
+	 * @throws EE_Error
243
+	 * @throws InvalidArgumentException
244
+	 * @throws ReflectionException
245
+	 * @throws InvalidDataTypeException
246
+	 * @throws InvalidInterfaceException
247
+	 */
248
+	public static function register($addon_name = '', $setup_args = array())
249
+	{
250
+		// required fields MUST be present, so let's make sure they are.
251
+		EE_Register_Addon::_verify_parameters($addon_name, $setup_args);
252
+		// get class name for addon
253
+		$class_name = EE_Register_Addon::_parse_class_name($addon_name, $setup_args);
254
+		//setup $_settings array from incoming values.
255
+		$addon_settings = EE_Register_Addon::_get_addon_settings($class_name, $setup_args);
256
+		// setup PUE
257
+		EE_Register_Addon::_parse_pue_options($addon_name, $class_name, $setup_args);
258
+		// does this addon work with this version of core or WordPress ?
259
+		if (! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
260
+			return;
261
+		}
262
+		// register namespaces
263
+		EE_Register_Addon::_setup_namespaces($addon_settings);
264
+		// check if this is an activation request
265
+		if (EE_Register_Addon::_addon_activation($addon_name, $addon_settings)) {
266
+			// dont bother setting up the rest of the addon atm
267
+			return;
268
+		}
269
+		// we need cars
270
+		EE_Register_Addon::_setup_autoloaders($addon_name);
271
+		// register new models and extensions
272
+		EE_Register_Addon::_register_models_and_extensions($addon_name);
273
+		// setup DMS
274
+		EE_Register_Addon::_register_data_migration_scripts($addon_name);
275
+		// if config_class is present let's register config.
276
+		EE_Register_Addon::_register_config($addon_name);
277
+		// register admin pages
278
+		EE_Register_Addon::_register_admin_pages($addon_name);
279
+		// add to list of modules to be registered
280
+		EE_Register_Addon::_register_modules($addon_name);
281
+		// add to list of shortcodes to be registered
282
+		EE_Register_Addon::_register_shortcodes($addon_name);
283
+		// add to list of widgets to be registered
284
+		EE_Register_Addon::_register_widgets($addon_name);
285
+		// register capability related stuff.
286
+		EE_Register_Addon::_register_capabilities($addon_name);
287
+		// any message type to register?
288
+		EE_Register_Addon::_register_message_types($addon_name);
289
+		// any custom post type/ custom capabilities or default terms to register
290
+		EE_Register_Addon::_register_custom_post_types($addon_name);
291
+		// and any payment methods
292
+		EE_Register_Addon::_register_payment_methods($addon_name);
293
+		// load and instantiate main addon class
294
+		$addon = EE_Register_Addon::_load_and_init_addon_class($addon_name);
295
+		//delay calling after_registration hook on each addon until after all add-ons have been registered.
296
+		add_action('AHEE__EE_System__load_espresso_addons__complete', array($addon, 'after_registration'), 999);
297
+	}
298 298
 
299 299
 
300
-    /**
301
-     * @param string $addon_name
302
-     * @param array  $setup_args
303
-     * @return void
304
-     * @throws EE_Error
305
-     */
306
-    private static function _verify_parameters($addon_name, array $setup_args)
307
-    {
308
-        // required fields MUST be present, so let's make sure they are.
309
-        if (empty($addon_name) || ! is_array($setup_args)) {
310
-            throw new EE_Error(
311
-                __(
312
-                    'In order to register an EE_Addon with EE_Register_Addon::register(), you must include the "addon_name" (the name of the addon), and an array of arguments.',
313
-                    'event_espresso'
314
-                )
315
-            );
316
-        }
317
-        if (! isset($setup_args['main_file_path']) || empty($setup_args['main_file_path'])) {
318
-            throw new EE_Error(
319
-                sprintf(
320
-                    __(
321
-                        'When registering an addon, you didn\'t provide the "main_file_path", which is the full path to the main file loaded directly by Wordpress. You only provided %s',
322
-                        'event_espresso'
323
-                    ),
324
-                    implode(',', array_keys($setup_args))
325
-                )
326
-            );
327
-        }
328
-        // check that addon has not already been registered with that name
329
-        if (isset(self::$_settings[ $addon_name ]) && ! did_action('activate_plugin')) {
330
-            throw new EE_Error(
331
-                sprintf(
332
-                    __(
333
-                        'An EE_Addon with the name "%s" has already been registered and each EE_Addon requires a unique name.',
334
-                        'event_espresso'
335
-                    ),
336
-                    $addon_name
337
-                )
338
-            );
339
-        }
340
-    }
300
+	/**
301
+	 * @param string $addon_name
302
+	 * @param array  $setup_args
303
+	 * @return void
304
+	 * @throws EE_Error
305
+	 */
306
+	private static function _verify_parameters($addon_name, array $setup_args)
307
+	{
308
+		// required fields MUST be present, so let's make sure they are.
309
+		if (empty($addon_name) || ! is_array($setup_args)) {
310
+			throw new EE_Error(
311
+				__(
312
+					'In order to register an EE_Addon with EE_Register_Addon::register(), you must include the "addon_name" (the name of the addon), and an array of arguments.',
313
+					'event_espresso'
314
+				)
315
+			);
316
+		}
317
+		if (! isset($setup_args['main_file_path']) || empty($setup_args['main_file_path'])) {
318
+			throw new EE_Error(
319
+				sprintf(
320
+					__(
321
+						'When registering an addon, you didn\'t provide the "main_file_path", which is the full path to the main file loaded directly by Wordpress. You only provided %s',
322
+						'event_espresso'
323
+					),
324
+					implode(',', array_keys($setup_args))
325
+				)
326
+			);
327
+		}
328
+		// check that addon has not already been registered with that name
329
+		if (isset(self::$_settings[ $addon_name ]) && ! did_action('activate_plugin')) {
330
+			throw new EE_Error(
331
+				sprintf(
332
+					__(
333
+						'An EE_Addon with the name "%s" has already been registered and each EE_Addon requires a unique name.',
334
+						'event_espresso'
335
+					),
336
+					$addon_name
337
+				)
338
+			);
339
+		}
340
+	}
341 341
 
342 342
 
343
-    /**
344
-     * @param string $addon_name
345
-     * @param array  $setup_args
346
-     * @return string
347
-     */
348
-    private static function _parse_class_name($addon_name, array $setup_args)
349
-    {
350
-        if (empty($setup_args['class_name'])) {
351
-            // generate one by first separating name with spaces
352
-            $class_name = str_replace(array('-', '_'), ' ', trim($addon_name));
353
-            //capitalize, then replace spaces with underscores
354
-            $class_name = str_replace(' ', '_', ucwords($class_name));
355
-        } else {
356
-            $class_name = $setup_args['class_name'];
357
-        }
358
-        // check if classname is fully  qualified or is a legacy classname already prefixed with 'EE_'
359
-        return strpos($class_name, '\\') || strpos($class_name, 'EE_') === 0
360
-            ? $class_name
361
-            : 'EE_' . $class_name;
362
-    }
343
+	/**
344
+	 * @param string $addon_name
345
+	 * @param array  $setup_args
346
+	 * @return string
347
+	 */
348
+	private static function _parse_class_name($addon_name, array $setup_args)
349
+	{
350
+		if (empty($setup_args['class_name'])) {
351
+			// generate one by first separating name with spaces
352
+			$class_name = str_replace(array('-', '_'), ' ', trim($addon_name));
353
+			//capitalize, then replace spaces with underscores
354
+			$class_name = str_replace(' ', '_', ucwords($class_name));
355
+		} else {
356
+			$class_name = $setup_args['class_name'];
357
+		}
358
+		// check if classname is fully  qualified or is a legacy classname already prefixed with 'EE_'
359
+		return strpos($class_name, '\\') || strpos($class_name, 'EE_') === 0
360
+			? $class_name
361
+			: 'EE_' . $class_name;
362
+	}
363 363
 
364 364
 
365
-    /**
366
-     * @param string $class_name
367
-     * @param array  $setup_args
368
-     * @return array
369
-     */
370
-    private static function _get_addon_settings($class_name, array $setup_args)
371
-    {
372
-        //setup $_settings array from incoming values.
373
-        $addon_settings = array(
374
-            // generated from the addon name, changes something like "calendar" to "EE_Calendar"
375
-            'class_name'            => $class_name,
376
-            // the addon slug for use in URLs, etc
377
-            'plugin_slug'           => isset($setup_args['plugin_slug'])
378
-                ? (string) $setup_args['plugin_slug']
379
-                : '',
380
-            // page slug to be used when generating the "Settings" link on the WP plugin page
381
-            'plugin_action_slug'    => isset($setup_args['plugin_action_slug'])
382
-                ? (string) $setup_args['plugin_action_slug']
383
-                : '',
384
-            // the "software" version for the addon
385
-            'version'               => isset($setup_args['version'])
386
-                ? (string) $setup_args['version']
387
-                : '',
388
-            // the minimum version of EE Core that the addon will work with
389
-            'min_core_version'      => isset($setup_args['min_core_version'])
390
-                ? (string) $setup_args['min_core_version']
391
-                : '',
392
-            // the minimum version of WordPress that the addon will work with
393
-            'min_wp_version'        => isset($setup_args['min_wp_version'])
394
-                ? (string) $setup_args['min_wp_version']
395
-                : EE_MIN_WP_VER_REQUIRED,
396
-            // full server path to main file (file loaded directly by WP)
397
-            'main_file_path'        => isset($setup_args['main_file_path'])
398
-                ? (string) $setup_args['main_file_path']
399
-                : '',
400
-            // Fully Qualified Class Name for the addon's Domain class
401
-            'domain_fqcn'           => isset($setup_args['domain_fqcn'])
402
-                ? (string) $setup_args['domain_fqcn']
403
-                : '',
404
-            // path to folder containing files for integrating with the EE core admin and/or setting up EE admin pages
405
-            'admin_path'            => isset($setup_args['admin_path'])
406
-                ? (string) $setup_args['admin_path'] : '',
407
-            // a method to be called when the EE Admin is first invoked, can be used for hooking into any admin page
408
-            'admin_callback'        => isset($setup_args['admin_callback'])
409
-                ? (string) $setup_args['admin_callback']
410
-                : '',
411
-            // the section name for this addon's configuration settings section (defaults to "addons")
412
-            'config_section'        => isset($setup_args['config_section'])
413
-                ? (string) $setup_args['config_section']
414
-                : 'addons',
415
-            // the class name for this addon's configuration settings object
416
-            'config_class'          => isset($setup_args['config_class'])
417
-                ? (string) $setup_args['config_class'] : '',
418
-            //the name given to the config for this addons' configuration settings object (optional)
419
-            'config_name'           => isset($setup_args['config_name'])
420
-                ? (string) $setup_args['config_name'] : '',
421
-            // an array of "class names" => "full server paths" for any classes that might be invoked by the addon
422
-            'autoloader_paths'      => isset($setup_args['autoloader_paths'])
423
-                ? (array) $setup_args['autoloader_paths']
424
-                : array(),
425
-            // an array of  "full server paths" for any folders containing classes that might be invoked by the addon
426
-            'autoloader_folders'    => isset($setup_args['autoloader_folders'])
427
-                ? (array) $setup_args['autoloader_folders']
428
-                : array(),
429
-            // array of full server paths to any EE_DMS data migration scripts used by the addon.
430
-            // The key should be the EE_Addon class name that this set of data migration scripts belongs to.
431
-            // If the EE_Addon class is namespaced, then this needs to be the Fully Qualified Class Name
432
-            'dms_paths'             => isset($setup_args['dms_paths'])
433
-                ? (array) $setup_args['dms_paths']
434
-                : array(),
435
-            // array of full server paths to any EED_Modules used by the addon
436
-            'module_paths'          => isset($setup_args['module_paths'])
437
-                ? (array) $setup_args['module_paths']
438
-                : array(),
439
-            // array of full server paths to any EES_Shortcodes used by the addon
440
-            'shortcode_paths'       => isset($setup_args['shortcode_paths'])
441
-                ? (array) $setup_args['shortcode_paths']
442
-                : array(),
443
-            'shortcode_fqcns'       => isset($setup_args['shortcode_fqcns'])
444
-                ? (array) $setup_args['shortcode_fqcns']
445
-                : array(),
446
-            // array of full server paths to any WP_Widgets used by the addon
447
-            'widget_paths'          => isset($setup_args['widget_paths'])
448
-                ? (array) $setup_args['widget_paths']
449
-                : array(),
450
-            // array of PUE options used by the addon
451
-            'pue_options'           => isset($setup_args['pue_options'])
452
-                ? (array) $setup_args['pue_options']
453
-                : array(),
454
-            'message_types'         => isset($setup_args['message_types'])
455
-                ? (array) $setup_args['message_types']
456
-                : array(),
457
-            'capabilities'          => isset($setup_args['capabilities'])
458
-                ? (array) $setup_args['capabilities']
459
-                : array(),
460
-            'capability_maps'       => isset($setup_args['capability_maps'])
461
-                ? (array) $setup_args['capability_maps']
462
-                : array(),
463
-            'model_paths'           => isset($setup_args['model_paths'])
464
-                ? (array) $setup_args['model_paths']
465
-                : array(),
466
-            'class_paths'           => isset($setup_args['class_paths'])
467
-                ? (array) $setup_args['class_paths']
468
-                : array(),
469
-            'model_extension_paths' => isset($setup_args['model_extension_paths'])
470
-                ? (array) $setup_args['model_extension_paths']
471
-                : array(),
472
-            'class_extension_paths' => isset($setup_args['class_extension_paths'])
473
-                ? (array) $setup_args['class_extension_paths']
474
-                : array(),
475
-            'custom_post_types'     => isset($setup_args['custom_post_types'])
476
-                ? (array) $setup_args['custom_post_types']
477
-                : array(),
478
-            'custom_taxonomies'     => isset($setup_args['custom_taxonomies'])
479
-                ? (array) $setup_args['custom_taxonomies']
480
-                : array(),
481
-            'payment_method_paths'  => isset($setup_args['payment_method_paths'])
482
-                ? (array) $setup_args['payment_method_paths']
483
-                : array(),
484
-            'default_terms'         => isset($setup_args['default_terms'])
485
-                ? (array) $setup_args['default_terms']
486
-                : array(),
487
-            // if not empty, inserts a new table row after this plugin's row on the WP Plugins page
488
-            // that can be used for adding upgrading/marketing info
489
-            'plugins_page_row'      => isset($setup_args['plugins_page_row'])
490
-                ? $setup_args['plugins_page_row']
491
-                : '',
492
-            'namespace'             => isset(
493
-                $setup_args['namespace']['FQNS'],
494
-                $setup_args['namespace']['DIR']
495
-            )
496
-                ? (array) $setup_args['namespace']
497
-                : array(),
498
-        );
499
-        // if plugin_action_slug is NOT set, but an admin page path IS set,
500
-        // then let's just use the plugin_slug since that will be used for linking to the admin page
501
-        $addon_settings['plugin_action_slug'] = empty($addon_settings['plugin_action_slug'])
502
-                                                && ! empty($addon_settings['admin_path'])
503
-            ? $addon_settings['plugin_slug']
504
-            : $addon_settings['plugin_action_slug'];
505
-        // full server path to main file (file loaded directly by WP)
506
-        $addon_settings['plugin_basename'] = plugin_basename($addon_settings['main_file_path']);
507
-        return $addon_settings;
508
-    }
365
+	/**
366
+	 * @param string $class_name
367
+	 * @param array  $setup_args
368
+	 * @return array
369
+	 */
370
+	private static function _get_addon_settings($class_name, array $setup_args)
371
+	{
372
+		//setup $_settings array from incoming values.
373
+		$addon_settings = array(
374
+			// generated from the addon name, changes something like "calendar" to "EE_Calendar"
375
+			'class_name'            => $class_name,
376
+			// the addon slug for use in URLs, etc
377
+			'plugin_slug'           => isset($setup_args['plugin_slug'])
378
+				? (string) $setup_args['plugin_slug']
379
+				: '',
380
+			// page slug to be used when generating the "Settings" link on the WP plugin page
381
+			'plugin_action_slug'    => isset($setup_args['plugin_action_slug'])
382
+				? (string) $setup_args['plugin_action_slug']
383
+				: '',
384
+			// the "software" version for the addon
385
+			'version'               => isset($setup_args['version'])
386
+				? (string) $setup_args['version']
387
+				: '',
388
+			// the minimum version of EE Core that the addon will work with
389
+			'min_core_version'      => isset($setup_args['min_core_version'])
390
+				? (string) $setup_args['min_core_version']
391
+				: '',
392
+			// the minimum version of WordPress that the addon will work with
393
+			'min_wp_version'        => isset($setup_args['min_wp_version'])
394
+				? (string) $setup_args['min_wp_version']
395
+				: EE_MIN_WP_VER_REQUIRED,
396
+			// full server path to main file (file loaded directly by WP)
397
+			'main_file_path'        => isset($setup_args['main_file_path'])
398
+				? (string) $setup_args['main_file_path']
399
+				: '',
400
+			// Fully Qualified Class Name for the addon's Domain class
401
+			'domain_fqcn'           => isset($setup_args['domain_fqcn'])
402
+				? (string) $setup_args['domain_fqcn']
403
+				: '',
404
+			// path to folder containing files for integrating with the EE core admin and/or setting up EE admin pages
405
+			'admin_path'            => isset($setup_args['admin_path'])
406
+				? (string) $setup_args['admin_path'] : '',
407
+			// a method to be called when the EE Admin is first invoked, can be used for hooking into any admin page
408
+			'admin_callback'        => isset($setup_args['admin_callback'])
409
+				? (string) $setup_args['admin_callback']
410
+				: '',
411
+			// the section name for this addon's configuration settings section (defaults to "addons")
412
+			'config_section'        => isset($setup_args['config_section'])
413
+				? (string) $setup_args['config_section']
414
+				: 'addons',
415
+			// the class name for this addon's configuration settings object
416
+			'config_class'          => isset($setup_args['config_class'])
417
+				? (string) $setup_args['config_class'] : '',
418
+			//the name given to the config for this addons' configuration settings object (optional)
419
+			'config_name'           => isset($setup_args['config_name'])
420
+				? (string) $setup_args['config_name'] : '',
421
+			// an array of "class names" => "full server paths" for any classes that might be invoked by the addon
422
+			'autoloader_paths'      => isset($setup_args['autoloader_paths'])
423
+				? (array) $setup_args['autoloader_paths']
424
+				: array(),
425
+			// an array of  "full server paths" for any folders containing classes that might be invoked by the addon
426
+			'autoloader_folders'    => isset($setup_args['autoloader_folders'])
427
+				? (array) $setup_args['autoloader_folders']
428
+				: array(),
429
+			// array of full server paths to any EE_DMS data migration scripts used by the addon.
430
+			// The key should be the EE_Addon class name that this set of data migration scripts belongs to.
431
+			// If the EE_Addon class is namespaced, then this needs to be the Fully Qualified Class Name
432
+			'dms_paths'             => isset($setup_args['dms_paths'])
433
+				? (array) $setup_args['dms_paths']
434
+				: array(),
435
+			// array of full server paths to any EED_Modules used by the addon
436
+			'module_paths'          => isset($setup_args['module_paths'])
437
+				? (array) $setup_args['module_paths']
438
+				: array(),
439
+			// array of full server paths to any EES_Shortcodes used by the addon
440
+			'shortcode_paths'       => isset($setup_args['shortcode_paths'])
441
+				? (array) $setup_args['shortcode_paths']
442
+				: array(),
443
+			'shortcode_fqcns'       => isset($setup_args['shortcode_fqcns'])
444
+				? (array) $setup_args['shortcode_fqcns']
445
+				: array(),
446
+			// array of full server paths to any WP_Widgets used by the addon
447
+			'widget_paths'          => isset($setup_args['widget_paths'])
448
+				? (array) $setup_args['widget_paths']
449
+				: array(),
450
+			// array of PUE options used by the addon
451
+			'pue_options'           => isset($setup_args['pue_options'])
452
+				? (array) $setup_args['pue_options']
453
+				: array(),
454
+			'message_types'         => isset($setup_args['message_types'])
455
+				? (array) $setup_args['message_types']
456
+				: array(),
457
+			'capabilities'          => isset($setup_args['capabilities'])
458
+				? (array) $setup_args['capabilities']
459
+				: array(),
460
+			'capability_maps'       => isset($setup_args['capability_maps'])
461
+				? (array) $setup_args['capability_maps']
462
+				: array(),
463
+			'model_paths'           => isset($setup_args['model_paths'])
464
+				? (array) $setup_args['model_paths']
465
+				: array(),
466
+			'class_paths'           => isset($setup_args['class_paths'])
467
+				? (array) $setup_args['class_paths']
468
+				: array(),
469
+			'model_extension_paths' => isset($setup_args['model_extension_paths'])
470
+				? (array) $setup_args['model_extension_paths']
471
+				: array(),
472
+			'class_extension_paths' => isset($setup_args['class_extension_paths'])
473
+				? (array) $setup_args['class_extension_paths']
474
+				: array(),
475
+			'custom_post_types'     => isset($setup_args['custom_post_types'])
476
+				? (array) $setup_args['custom_post_types']
477
+				: array(),
478
+			'custom_taxonomies'     => isset($setup_args['custom_taxonomies'])
479
+				? (array) $setup_args['custom_taxonomies']
480
+				: array(),
481
+			'payment_method_paths'  => isset($setup_args['payment_method_paths'])
482
+				? (array) $setup_args['payment_method_paths']
483
+				: array(),
484
+			'default_terms'         => isset($setup_args['default_terms'])
485
+				? (array) $setup_args['default_terms']
486
+				: array(),
487
+			// if not empty, inserts a new table row after this plugin's row on the WP Plugins page
488
+			// that can be used for adding upgrading/marketing info
489
+			'plugins_page_row'      => isset($setup_args['plugins_page_row'])
490
+				? $setup_args['plugins_page_row']
491
+				: '',
492
+			'namespace'             => isset(
493
+				$setup_args['namespace']['FQNS'],
494
+				$setup_args['namespace']['DIR']
495
+			)
496
+				? (array) $setup_args['namespace']
497
+				: array(),
498
+		);
499
+		// if plugin_action_slug is NOT set, but an admin page path IS set,
500
+		// then let's just use the plugin_slug since that will be used for linking to the admin page
501
+		$addon_settings['plugin_action_slug'] = empty($addon_settings['plugin_action_slug'])
502
+												&& ! empty($addon_settings['admin_path'])
503
+			? $addon_settings['plugin_slug']
504
+			: $addon_settings['plugin_action_slug'];
505
+		// full server path to main file (file loaded directly by WP)
506
+		$addon_settings['plugin_basename'] = plugin_basename($addon_settings['main_file_path']);
507
+		return $addon_settings;
508
+	}
509 509
 
510 510
 
511
-    /**
512
-     * @param string $addon_name
513
-     * @param array  $addon_settings
514
-     * @return boolean
515
-     */
516
-    private static function _addon_is_compatible($addon_name, array $addon_settings)
517
-    {
518
-        global $wp_version;
519
-        $incompatibility_message = '';
520
-        //check whether this addon version is compatible with EE core
521
-        if (
522
-            isset(EE_Register_Addon::$_incompatible_addons[ $addon_name ])
523
-            && ! self::_meets_min_core_version_requirement(
524
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
525
-                $addon_settings['version']
526
-            )
527
-        ) {
528
-            $incompatibility_message = sprintf(
529
-                __(
530
-                    '%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon is not compatible with this version of Event Espresso.%2$sPlease upgrade your "%1$s" addon to version %3$s or newer to resolve this issue.'
531
-                ),
532
-                $addon_name,
533
-                '<br />',
534
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
535
-                '<span style="font-weight: bold; color: #D54E21;">',
536
-                '</span><br />'
537
-            );
538
-        } elseif (
539
-        ! self::_meets_min_core_version_requirement($addon_settings['min_core_version'], espresso_version())
540
-        ) {
541
-            $incompatibility_message = sprintf(
542
-                __(
543
-                    '%5$sIMPORTANT!%6$sThe Event Espresso "%1$s" addon requires Event Espresso Core version "%2$s" or higher in order to run.%4$sYour version of Event Espresso Core is currently at "%3$s". Please upgrade Event Espresso Core first and then re-activate "%1$s".',
544
-                    'event_espresso'
545
-                ),
546
-                $addon_name,
547
-                self::_effective_version($addon_settings['min_core_version']),
548
-                self::_effective_version(espresso_version()),
549
-                '<br />',
550
-                '<span style="font-weight: bold; color: #D54E21;">',
551
-                '</span><br />'
552
-            );
553
-        } elseif (version_compare($wp_version, $addon_settings['min_wp_version'], '<')) {
554
-            $incompatibility_message = sprintf(
555
-                __(
556
-                    '%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon requires WordPress version "%2$s" or greater.%3$sPlease update your version of WordPress to use the "%1$s" addon and to keep your site secure.',
557
-                    'event_espresso'
558
-                ),
559
-                $addon_name,
560
-                $addon_settings['min_wp_version'],
561
-                '<br />',
562
-                '<span style="font-weight: bold; color: #D54E21;">',
563
-                '</span><br />'
564
-            );
565
-        }
566
-        if (! empty($incompatibility_message)) {
567
-            // remove 'activate' from the REQUEST
568
-            // so WP doesn't erroneously tell the user the plugin activated fine when it didn't
569
-            unset($_GET['activate'], $_REQUEST['activate']);
570
-            if (current_user_can('activate_plugins')) {
571
-                // show an error message indicating the plugin didn't activate properly
572
-                EE_Error::add_error($incompatibility_message, __FILE__, __FUNCTION__, __LINE__);
573
-            }
574
-            // BAIL FROM THE ADDON REGISTRATION PROCESS
575
-            return false;
576
-        }
577
-        // addon IS compatible
578
-        return true;
579
-    }
511
+	/**
512
+	 * @param string $addon_name
513
+	 * @param array  $addon_settings
514
+	 * @return boolean
515
+	 */
516
+	private static function _addon_is_compatible($addon_name, array $addon_settings)
517
+	{
518
+		global $wp_version;
519
+		$incompatibility_message = '';
520
+		//check whether this addon version is compatible with EE core
521
+		if (
522
+			isset(EE_Register_Addon::$_incompatible_addons[ $addon_name ])
523
+			&& ! self::_meets_min_core_version_requirement(
524
+				EE_Register_Addon::$_incompatible_addons[ $addon_name ],
525
+				$addon_settings['version']
526
+			)
527
+		) {
528
+			$incompatibility_message = sprintf(
529
+				__(
530
+					'%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon is not compatible with this version of Event Espresso.%2$sPlease upgrade your "%1$s" addon to version %3$s or newer to resolve this issue.'
531
+				),
532
+				$addon_name,
533
+				'<br />',
534
+				EE_Register_Addon::$_incompatible_addons[ $addon_name ],
535
+				'<span style="font-weight: bold; color: #D54E21;">',
536
+				'</span><br />'
537
+			);
538
+		} elseif (
539
+		! self::_meets_min_core_version_requirement($addon_settings['min_core_version'], espresso_version())
540
+		) {
541
+			$incompatibility_message = sprintf(
542
+				__(
543
+					'%5$sIMPORTANT!%6$sThe Event Espresso "%1$s" addon requires Event Espresso Core version "%2$s" or higher in order to run.%4$sYour version of Event Espresso Core is currently at "%3$s". Please upgrade Event Espresso Core first and then re-activate "%1$s".',
544
+					'event_espresso'
545
+				),
546
+				$addon_name,
547
+				self::_effective_version($addon_settings['min_core_version']),
548
+				self::_effective_version(espresso_version()),
549
+				'<br />',
550
+				'<span style="font-weight: bold; color: #D54E21;">',
551
+				'</span><br />'
552
+			);
553
+		} elseif (version_compare($wp_version, $addon_settings['min_wp_version'], '<')) {
554
+			$incompatibility_message = sprintf(
555
+				__(
556
+					'%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon requires WordPress version "%2$s" or greater.%3$sPlease update your version of WordPress to use the "%1$s" addon and to keep your site secure.',
557
+					'event_espresso'
558
+				),
559
+				$addon_name,
560
+				$addon_settings['min_wp_version'],
561
+				'<br />',
562
+				'<span style="font-weight: bold; color: #D54E21;">',
563
+				'</span><br />'
564
+			);
565
+		}
566
+		if (! empty($incompatibility_message)) {
567
+			// remove 'activate' from the REQUEST
568
+			// so WP doesn't erroneously tell the user the plugin activated fine when it didn't
569
+			unset($_GET['activate'], $_REQUEST['activate']);
570
+			if (current_user_can('activate_plugins')) {
571
+				// show an error message indicating the plugin didn't activate properly
572
+				EE_Error::add_error($incompatibility_message, __FILE__, __FUNCTION__, __LINE__);
573
+			}
574
+			// BAIL FROM THE ADDON REGISTRATION PROCESS
575
+			return false;
576
+		}
577
+		// addon IS compatible
578
+		return true;
579
+	}
580 580
 
581 581
 
582
-    /**
583
-     * if plugin update engine is being used for auto-updates,
584
-     * then let's set that up now before going any further so that ALL addons can be updated
585
-     * (not needed if PUE is not being used)
586
-     *
587
-     * @param string $addon_name
588
-     * @param string $class_name
589
-     * @param array  $setup_args
590
-     * @return void
591
-     */
592
-    private static function _parse_pue_options($addon_name, $class_name, array $setup_args)
593
-    {
594
-        if (! empty($setup_args['pue_options'])) {
595
-            self::$_settings[ $addon_name ]['pue_options'] = array(
596
-                'pue_plugin_slug' => isset($setup_args['pue_options']['pue_plugin_slug'])
597
-                    ? (string) $setup_args['pue_options']['pue_plugin_slug']
598
-                    : 'espresso_' . strtolower($class_name),
599
-                'plugin_basename' => isset($setup_args['pue_options']['plugin_basename'])
600
-                    ? (string) $setup_args['pue_options']['plugin_basename']
601
-                    : plugin_basename($setup_args['main_file_path']),
602
-                'checkPeriod'     => isset($setup_args['pue_options']['checkPeriod'])
603
-                    ? (string) $setup_args['pue_options']['checkPeriod']
604
-                    : '24',
605
-                'use_wp_update'   => isset($setup_args['pue_options']['use_wp_update'])
606
-                    ? (string) $setup_args['pue_options']['use_wp_update']
607
-                    : false,
608
-            );
609
-            add_action(
610
-                'AHEE__EE_System__brew_espresso__after_pue_init',
611
-                array('EE_Register_Addon', 'load_pue_update')
612
-            );
613
-        }
614
-    }
582
+	/**
583
+	 * if plugin update engine is being used for auto-updates,
584
+	 * then let's set that up now before going any further so that ALL addons can be updated
585
+	 * (not needed if PUE is not being used)
586
+	 *
587
+	 * @param string $addon_name
588
+	 * @param string $class_name
589
+	 * @param array  $setup_args
590
+	 * @return void
591
+	 */
592
+	private static function _parse_pue_options($addon_name, $class_name, array $setup_args)
593
+	{
594
+		if (! empty($setup_args['pue_options'])) {
595
+			self::$_settings[ $addon_name ]['pue_options'] = array(
596
+				'pue_plugin_slug' => isset($setup_args['pue_options']['pue_plugin_slug'])
597
+					? (string) $setup_args['pue_options']['pue_plugin_slug']
598
+					: 'espresso_' . strtolower($class_name),
599
+				'plugin_basename' => isset($setup_args['pue_options']['plugin_basename'])
600
+					? (string) $setup_args['pue_options']['plugin_basename']
601
+					: plugin_basename($setup_args['main_file_path']),
602
+				'checkPeriod'     => isset($setup_args['pue_options']['checkPeriod'])
603
+					? (string) $setup_args['pue_options']['checkPeriod']
604
+					: '24',
605
+				'use_wp_update'   => isset($setup_args['pue_options']['use_wp_update'])
606
+					? (string) $setup_args['pue_options']['use_wp_update']
607
+					: false,
608
+			);
609
+			add_action(
610
+				'AHEE__EE_System__brew_espresso__after_pue_init',
611
+				array('EE_Register_Addon', 'load_pue_update')
612
+			);
613
+		}
614
+	}
615 615
 
616 616
 
617
-    /**
618
-     * register namespaces right away before any other files or classes get loaded, but AFTER the version checks
619
-     *
620
-     * @param array $addon_settings
621
-     * @return void
622
-     */
623
-    private static function _setup_namespaces(array $addon_settings)
624
-    {
625
-        //
626
-        if (
627
-        isset(
628
-            $addon_settings['namespace']['FQNS'],
629
-            $addon_settings['namespace']['DIR']
630
-        )
631
-        ) {
632
-            EE_Psr4AutoloaderInit::psr4_loader()->addNamespace(
633
-                $addon_settings['namespace']['FQNS'],
634
-                $addon_settings['namespace']['DIR']
635
-            );
636
-        }
637
-    }
617
+	/**
618
+	 * register namespaces right away before any other files or classes get loaded, but AFTER the version checks
619
+	 *
620
+	 * @param array $addon_settings
621
+	 * @return void
622
+	 */
623
+	private static function _setup_namespaces(array $addon_settings)
624
+	{
625
+		//
626
+		if (
627
+		isset(
628
+			$addon_settings['namespace']['FQNS'],
629
+			$addon_settings['namespace']['DIR']
630
+		)
631
+		) {
632
+			EE_Psr4AutoloaderInit::psr4_loader()->addNamespace(
633
+				$addon_settings['namespace']['FQNS'],
634
+				$addon_settings['namespace']['DIR']
635
+			);
636
+		}
637
+	}
638 638
 
639 639
 
640
-    /**
641
-     * @param string $addon_name
642
-     * @param array  $addon_settings
643
-     * @return bool
644
-     * @throws EE_Error
645
-     * @throws InvalidArgumentException
646
-     * @throws ReflectionException
647
-     * @throws InvalidDataTypeException
648
-     * @throws InvalidInterfaceException
649
-     */
650
-    private static function _addon_activation($addon_name, array $addon_settings)
651
-    {
652
-        // this is an activation request
653
-        if (did_action('activate_plugin')) {
654
-            //to find if THIS is the addon that was activated, just check if we have already registered it or not
655
-            //(as the newly-activated addon wasn't around the first time addons were registered).
656
-            //Note: the presence of pue_options in the addon registration options will initialize the $_settings
657
-            //property for the add-on, but the add-on is only partially initialized.  Hence, the additional check.
658
-            if (! isset(self::$_settings[ $addon_name ])
659
-                || (isset(self::$_settings[ $addon_name ])
660
-                    && ! isset(self::$_settings[ $addon_name ]['class_name'])
661
-                )
662
-            ) {
663
-                self::$_settings[ $addon_name ] = $addon_settings;
664
-                $addon                          = self::_load_and_init_addon_class($addon_name);
665
-                $addon->set_activation_indicator_option();
666
-                // dont bother setting up the rest of the addon.
667
-                // we know it was just activated and the request will end soon
668
-            }
669
-            return true;
670
-        }
671
-        // make sure this was called in the right place!
672
-        if (
673
-            ! did_action('AHEE__EE_System__load_espresso_addons')
674
-            || did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
675
-        ) {
676
-            EE_Error::doing_it_wrong(
677
-                __METHOD__,
678
-                sprintf(
679
-                    __(
680
-                        'An attempt to register an EE_Addon named "%s" has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register addons.',
681
-                        'event_espresso'
682
-                    ),
683
-                    $addon_name
684
-                ),
685
-                '4.3.0'
686
-            );
687
-        }
688
-        // make sure addon settings are set correctly without overwriting anything existing
689
-        if (isset(self::$_settings[ $addon_name ])) {
690
-            self::$_settings[ $addon_name ] += $addon_settings;
691
-        } else {
692
-            self::$_settings[ $addon_name ] = $addon_settings;
693
-        }
694
-        return false;
695
-    }
640
+	/**
641
+	 * @param string $addon_name
642
+	 * @param array  $addon_settings
643
+	 * @return bool
644
+	 * @throws EE_Error
645
+	 * @throws InvalidArgumentException
646
+	 * @throws ReflectionException
647
+	 * @throws InvalidDataTypeException
648
+	 * @throws InvalidInterfaceException
649
+	 */
650
+	private static function _addon_activation($addon_name, array $addon_settings)
651
+	{
652
+		// this is an activation request
653
+		if (did_action('activate_plugin')) {
654
+			//to find if THIS is the addon that was activated, just check if we have already registered it or not
655
+			//(as the newly-activated addon wasn't around the first time addons were registered).
656
+			//Note: the presence of pue_options in the addon registration options will initialize the $_settings
657
+			//property for the add-on, but the add-on is only partially initialized.  Hence, the additional check.
658
+			if (! isset(self::$_settings[ $addon_name ])
659
+				|| (isset(self::$_settings[ $addon_name ])
660
+					&& ! isset(self::$_settings[ $addon_name ]['class_name'])
661
+				)
662
+			) {
663
+				self::$_settings[ $addon_name ] = $addon_settings;
664
+				$addon                          = self::_load_and_init_addon_class($addon_name);
665
+				$addon->set_activation_indicator_option();
666
+				// dont bother setting up the rest of the addon.
667
+				// we know it was just activated and the request will end soon
668
+			}
669
+			return true;
670
+		}
671
+		// make sure this was called in the right place!
672
+		if (
673
+			! did_action('AHEE__EE_System__load_espresso_addons')
674
+			|| did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
675
+		) {
676
+			EE_Error::doing_it_wrong(
677
+				__METHOD__,
678
+				sprintf(
679
+					__(
680
+						'An attempt to register an EE_Addon named "%s" has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register addons.',
681
+						'event_espresso'
682
+					),
683
+					$addon_name
684
+				),
685
+				'4.3.0'
686
+			);
687
+		}
688
+		// make sure addon settings are set correctly without overwriting anything existing
689
+		if (isset(self::$_settings[ $addon_name ])) {
690
+			self::$_settings[ $addon_name ] += $addon_settings;
691
+		} else {
692
+			self::$_settings[ $addon_name ] = $addon_settings;
693
+		}
694
+		return false;
695
+	}
696 696
 
697 697
 
698
-    /**
699
-     * @param string $addon_name
700
-     * @return void
701
-     * @throws EE_Error
702
-     */
703
-    private static function _setup_autoloaders($addon_name)
704
-    {
705
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_paths'])) {
706
-            // setup autoloader for single file
707
-            EEH_Autoloader::instance()->register_autoloader(self::$_settings[ $addon_name ]['autoloader_paths']);
708
-        }
709
-        // setup autoloaders for folders
710
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_folders'])) {
711
-            foreach ((array) self::$_settings[ $addon_name ]['autoloader_folders'] as $autoloader_folder) {
712
-                EEH_Autoloader::register_autoloaders_for_each_file_in_folder($autoloader_folder);
713
-            }
714
-        }
715
-    }
698
+	/**
699
+	 * @param string $addon_name
700
+	 * @return void
701
+	 * @throws EE_Error
702
+	 */
703
+	private static function _setup_autoloaders($addon_name)
704
+	{
705
+		if (! empty(self::$_settings[ $addon_name ]['autoloader_paths'])) {
706
+			// setup autoloader for single file
707
+			EEH_Autoloader::instance()->register_autoloader(self::$_settings[ $addon_name ]['autoloader_paths']);
708
+		}
709
+		// setup autoloaders for folders
710
+		if (! empty(self::$_settings[ $addon_name ]['autoloader_folders'])) {
711
+			foreach ((array) self::$_settings[ $addon_name ]['autoloader_folders'] as $autoloader_folder) {
712
+				EEH_Autoloader::register_autoloaders_for_each_file_in_folder($autoloader_folder);
713
+			}
714
+		}
715
+	}
716 716
 
717 717
 
718
-    /**
719
-     * register new models and extensions
720
-     *
721
-     * @param string $addon_name
722
-     * @return void
723
-     * @throws EE_Error
724
-     */
725
-    private static function _register_models_and_extensions($addon_name)
726
-    {
727
-        // register new models
728
-        if (
729
-            ! empty(self::$_settings[ $addon_name ]['model_paths'])
730
-            || ! empty(self::$_settings[ $addon_name ]['class_paths'])
731
-        ) {
732
-            EE_Register_Model::register(
733
-                $addon_name,
734
-                array(
735
-                    'model_paths' => self::$_settings[ $addon_name ]['model_paths'],
736
-                    'class_paths' => self::$_settings[ $addon_name ]['class_paths'],
737
-                )
738
-            );
739
-        }
740
-        // register model extensions
741
-        if (
742
-            ! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
743
-            || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
744
-        ) {
745
-            EE_Register_Model_Extensions::register(
746
-                $addon_name,
747
-                array(
748
-                    'model_extension_paths' => self::$_settings[ $addon_name ]['model_extension_paths'],
749
-                    'class_extension_paths' => self::$_settings[ $addon_name ]['class_extension_paths'],
750
-                )
751
-            );
752
-        }
753
-    }
718
+	/**
719
+	 * register new models and extensions
720
+	 *
721
+	 * @param string $addon_name
722
+	 * @return void
723
+	 * @throws EE_Error
724
+	 */
725
+	private static function _register_models_and_extensions($addon_name)
726
+	{
727
+		// register new models
728
+		if (
729
+			! empty(self::$_settings[ $addon_name ]['model_paths'])
730
+			|| ! empty(self::$_settings[ $addon_name ]['class_paths'])
731
+		) {
732
+			EE_Register_Model::register(
733
+				$addon_name,
734
+				array(
735
+					'model_paths' => self::$_settings[ $addon_name ]['model_paths'],
736
+					'class_paths' => self::$_settings[ $addon_name ]['class_paths'],
737
+				)
738
+			);
739
+		}
740
+		// register model extensions
741
+		if (
742
+			! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
743
+			|| ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
744
+		) {
745
+			EE_Register_Model_Extensions::register(
746
+				$addon_name,
747
+				array(
748
+					'model_extension_paths' => self::$_settings[ $addon_name ]['model_extension_paths'],
749
+					'class_extension_paths' => self::$_settings[ $addon_name ]['class_extension_paths'],
750
+				)
751
+			);
752
+		}
753
+	}
754 754
 
755 755
 
756
-    /**
757
-     * @param string $addon_name
758
-     * @return void
759
-     * @throws EE_Error
760
-     */
761
-    private static function _register_data_migration_scripts($addon_name)
762
-    {
763
-        // setup DMS
764
-        if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
765
-            EE_Register_Data_Migration_Scripts::register(
766
-                $addon_name,
767
-                array('dms_paths' => self::$_settings[ $addon_name ]['dms_paths'])
768
-            );
769
-        }
770
-    }
756
+	/**
757
+	 * @param string $addon_name
758
+	 * @return void
759
+	 * @throws EE_Error
760
+	 */
761
+	private static function _register_data_migration_scripts($addon_name)
762
+	{
763
+		// setup DMS
764
+		if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
765
+			EE_Register_Data_Migration_Scripts::register(
766
+				$addon_name,
767
+				array('dms_paths' => self::$_settings[ $addon_name ]['dms_paths'])
768
+			);
769
+		}
770
+	}
771 771
 
772 772
 
773
-    /**
774
-     * @param string $addon_name
775
-     * @return void
776
-     * @throws EE_Error
777
-     */
778
-    private static function _register_config($addon_name)
779
-    {
780
-        // if config_class is present let's register config.
781
-        if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
782
-            EE_Register_Config::register(
783
-                self::$_settings[ $addon_name ]['config_class'],
784
-                array(
785
-                    'config_section' => self::$_settings[ $addon_name ]['config_section'],
786
-                    'config_name'    => self::$_settings[ $addon_name ]['config_name'],
787
-                )
788
-            );
789
-        }
790
-    }
773
+	/**
774
+	 * @param string $addon_name
775
+	 * @return void
776
+	 * @throws EE_Error
777
+	 */
778
+	private static function _register_config($addon_name)
779
+	{
780
+		// if config_class is present let's register config.
781
+		if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
782
+			EE_Register_Config::register(
783
+				self::$_settings[ $addon_name ]['config_class'],
784
+				array(
785
+					'config_section' => self::$_settings[ $addon_name ]['config_section'],
786
+					'config_name'    => self::$_settings[ $addon_name ]['config_name'],
787
+				)
788
+			);
789
+		}
790
+	}
791 791
 
792 792
 
793
-    /**
794
-     * @param string $addon_name
795
-     * @return void
796
-     * @throws EE_Error
797
-     */
798
-    private static function _register_admin_pages($addon_name)
799
-    {
800
-        if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
801
-            EE_Register_Admin_Page::register(
802
-                $addon_name,
803
-                array('page_path' => self::$_settings[ $addon_name ]['admin_path'])
804
-            );
805
-        }
806
-    }
793
+	/**
794
+	 * @param string $addon_name
795
+	 * @return void
796
+	 * @throws EE_Error
797
+	 */
798
+	private static function _register_admin_pages($addon_name)
799
+	{
800
+		if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
801
+			EE_Register_Admin_Page::register(
802
+				$addon_name,
803
+				array('page_path' => self::$_settings[ $addon_name ]['admin_path'])
804
+			);
805
+		}
806
+	}
807 807
 
808 808
 
809
-    /**
810
-     * @param string $addon_name
811
-     * @return void
812
-     * @throws EE_Error
813
-     */
814
-    private static function _register_modules($addon_name)
815
-    {
816
-        if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
817
-            EE_Register_Module::register(
818
-                $addon_name,
819
-                array('module_paths' => self::$_settings[ $addon_name ]['module_paths'])
820
-            );
821
-        }
822
-    }
809
+	/**
810
+	 * @param string $addon_name
811
+	 * @return void
812
+	 * @throws EE_Error
813
+	 */
814
+	private static function _register_modules($addon_name)
815
+	{
816
+		if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
817
+			EE_Register_Module::register(
818
+				$addon_name,
819
+				array('module_paths' => self::$_settings[ $addon_name ]['module_paths'])
820
+			);
821
+		}
822
+	}
823 823
 
824 824
 
825
-    /**
826
-     * @param string $addon_name
827
-     * @return void
828
-     * @throws EE_Error
829
-     */
830
-    private static function _register_shortcodes($addon_name)
831
-    {
832
-        if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
833
-            || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
834
-        ) {
835
-            EE_Register_Shortcode::register(
836
-                $addon_name,
837
-                array(
838
-                    'shortcode_paths' => isset(self::$_settings[ $addon_name ]['shortcode_paths'])
839
-                        ? self::$_settings[ $addon_name ]['shortcode_paths']
840
-                        : array(),
841
-                    'shortcode_fqcns' => isset(self::$_settings[ $addon_name ]['shortcode_fqcns'])
842
-                        ? self::$_settings[ $addon_name ]['shortcode_fqcns']
843
-                        : array(),
844
-                )
845
-            );
846
-        }
847
-    }
825
+	/**
826
+	 * @param string $addon_name
827
+	 * @return void
828
+	 * @throws EE_Error
829
+	 */
830
+	private static function _register_shortcodes($addon_name)
831
+	{
832
+		if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
833
+			|| ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
834
+		) {
835
+			EE_Register_Shortcode::register(
836
+				$addon_name,
837
+				array(
838
+					'shortcode_paths' => isset(self::$_settings[ $addon_name ]['shortcode_paths'])
839
+						? self::$_settings[ $addon_name ]['shortcode_paths']
840
+						: array(),
841
+					'shortcode_fqcns' => isset(self::$_settings[ $addon_name ]['shortcode_fqcns'])
842
+						? self::$_settings[ $addon_name ]['shortcode_fqcns']
843
+						: array(),
844
+				)
845
+			);
846
+		}
847
+	}
848 848
 
849 849
 
850
-    /**
851
-     * @param string $addon_name
852
-     * @return void
853
-     * @throws EE_Error
854
-     */
855
-    private static function _register_widgets($addon_name)
856
-    {
857
-        if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
858
-            EE_Register_Widget::register(
859
-                $addon_name,
860
-                array('widget_paths' => self::$_settings[ $addon_name ]['widget_paths'])
861
-            );
862
-        }
863
-    }
850
+	/**
851
+	 * @param string $addon_name
852
+	 * @return void
853
+	 * @throws EE_Error
854
+	 */
855
+	private static function _register_widgets($addon_name)
856
+	{
857
+		if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
858
+			EE_Register_Widget::register(
859
+				$addon_name,
860
+				array('widget_paths' => self::$_settings[ $addon_name ]['widget_paths'])
861
+			);
862
+		}
863
+	}
864 864
 
865 865
 
866
-    /**
867
-     * @param string $addon_name
868
-     * @return void
869
-     * @throws EE_Error
870
-     */
871
-    private static function _register_capabilities($addon_name)
872
-    {
873
-        if (! empty(self::$_settings[ $addon_name ]['capabilities'])) {
874
-            EE_Register_Capabilities::register(
875
-                $addon_name,
876
-                array(
877
-                    'capabilities'    => self::$_settings[ $addon_name ]['capabilities'],
878
-                    'capability_maps' => self::$_settings[ $addon_name ]['capability_maps'],
879
-                )
880
-            );
881
-        }
882
-    }
866
+	/**
867
+	 * @param string $addon_name
868
+	 * @return void
869
+	 * @throws EE_Error
870
+	 */
871
+	private static function _register_capabilities($addon_name)
872
+	{
873
+		if (! empty(self::$_settings[ $addon_name ]['capabilities'])) {
874
+			EE_Register_Capabilities::register(
875
+				$addon_name,
876
+				array(
877
+					'capabilities'    => self::$_settings[ $addon_name ]['capabilities'],
878
+					'capability_maps' => self::$_settings[ $addon_name ]['capability_maps'],
879
+				)
880
+			);
881
+		}
882
+	}
883 883
 
884 884
 
885
-    /**
886
-     * @param string $addon_name
887
-     * @return void
888
-     * @throws EE_Error
889
-     */
890
-    private static function _register_message_types($addon_name)
891
-    {
892
-        if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
893
-            add_action(
894
-                'EE_Brewing_Regular___messages_caf',
895
-                array('EE_Register_Addon', 'register_message_types')
896
-            );
897
-        }
898
-    }
885
+	/**
886
+	 * @param string $addon_name
887
+	 * @return void
888
+	 * @throws EE_Error
889
+	 */
890
+	private static function _register_message_types($addon_name)
891
+	{
892
+		if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
893
+			add_action(
894
+				'EE_Brewing_Regular___messages_caf',
895
+				array('EE_Register_Addon', 'register_message_types')
896
+			);
897
+		}
898
+	}
899 899
 
900 900
 
901
-    /**
902
-     * @param string $addon_name
903
-     * @return void
904
-     * @throws EE_Error
905
-     */
906
-    private static function _register_custom_post_types($addon_name)
907
-    {
908
-        if (
909
-            ! empty(self::$_settings[ $addon_name ]['custom_post_types'])
910
-            || ! empty(self::$_settings[ $addon_name ]['custom_taxonomies'])
911
-        ) {
912
-            EE_Register_CPT::register(
913
-                $addon_name,
914
-                array(
915
-                    'cpts'          => self::$_settings[ $addon_name ]['custom_post_types'],
916
-                    'cts'           => self::$_settings[ $addon_name ]['custom_taxonomies'],
917
-                    'default_terms' => self::$_settings[ $addon_name ]['default_terms'],
918
-                )
919
-            );
920
-        }
921
-    }
901
+	/**
902
+	 * @param string $addon_name
903
+	 * @return void
904
+	 * @throws EE_Error
905
+	 */
906
+	private static function _register_custom_post_types($addon_name)
907
+	{
908
+		if (
909
+			! empty(self::$_settings[ $addon_name ]['custom_post_types'])
910
+			|| ! empty(self::$_settings[ $addon_name ]['custom_taxonomies'])
911
+		) {
912
+			EE_Register_CPT::register(
913
+				$addon_name,
914
+				array(
915
+					'cpts'          => self::$_settings[ $addon_name ]['custom_post_types'],
916
+					'cts'           => self::$_settings[ $addon_name ]['custom_taxonomies'],
917
+					'default_terms' => self::$_settings[ $addon_name ]['default_terms'],
918
+				)
919
+			);
920
+		}
921
+	}
922 922
 
923 923
 
924
-    /**
925
-     * @param string $addon_name
926
-     * @return void
927
-     * @throws InvalidArgumentException
928
-     * @throws InvalidInterfaceException
929
-     * @throws InvalidDataTypeException
930
-     * @throws DomainException
931
-     * @throws EE_Error
932
-     */
933
-    private static function _register_payment_methods($addon_name)
934
-    {
935
-        if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
936
-            EE_Register_Payment_Method::register(
937
-                $addon_name,
938
-                array('payment_method_paths' => self::$_settings[ $addon_name ]['payment_method_paths'])
939
-            );
940
-        }
941
-    }
924
+	/**
925
+	 * @param string $addon_name
926
+	 * @return void
927
+	 * @throws InvalidArgumentException
928
+	 * @throws InvalidInterfaceException
929
+	 * @throws InvalidDataTypeException
930
+	 * @throws DomainException
931
+	 * @throws EE_Error
932
+	 */
933
+	private static function _register_payment_methods($addon_name)
934
+	{
935
+		if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
936
+			EE_Register_Payment_Method::register(
937
+				$addon_name,
938
+				array('payment_method_paths' => self::$_settings[ $addon_name ]['payment_method_paths'])
939
+			);
940
+		}
941
+	}
942 942
 
943 943
 
944
-    /**
945
-     * Loads and instantiates the EE_Addon class and adds it onto the registry
946
-     *
947
-     * @param string $addon_name
948
-     * @return EE_Addon
949
-     * @throws InvalidArgumentException
950
-     * @throws InvalidInterfaceException
951
-     * @throws InvalidDataTypeException
952
-     * @throws ReflectionException
953
-     * @throws EE_Error
954
-     */
955
-    private static function _load_and_init_addon_class($addon_name)
956
-    {
957
-        $loader = EventEspresso\core\services\loaders\LoaderFactory::getLoader();
958
-        $addon  = $loader->getShared(
959
-            self::$_settings[ $addon_name ]['class_name'],
960
-            array('EE_Registry::create(addon)' => true)
961
-        );
962
-        // setter inject dep map if required
963
-        if ($addon instanceof RequiresDependencyMapInterface && $addon->dependencyMap() === null) {
964
-            $addon->setDependencyMap($loader->getShared('EE_Dependency_Map'));
965
-        }
966
-        // setter inject domain if required
967
-        if (
968
-            $addon instanceof RequiresDomainInterface
969
-            && self::$_settings[ $addon_name ]['domain_fqcn'] !== ''
970
-            && $addon->domain() === null
971
-        ) {
972
-            $addon->setDomain(
973
-                $loader->getShared(
974
-                    self::$_settings[ $addon_name ]['domain_fqcn'],
975
-                    array(
976
-                        self::$_settings[ $addon_name ]['main_file_path'],
977
-                        self::$_settings[ $addon_name ]['version'],
978
-                    )
979
-                )
980
-            );
981
-        }
982
-        $addon->set_name($addon_name);
983
-        $addon->set_plugin_slug(self::$_settings[ $addon_name ]['plugin_slug']);
984
-        $addon->set_plugin_basename(self::$_settings[ $addon_name ]['plugin_basename']);
985
-        $addon->set_main_plugin_file(self::$_settings[ $addon_name ]['main_file_path']);
986
-        $addon->set_plugin_action_slug(self::$_settings[ $addon_name ]['plugin_action_slug']);
987
-        $addon->set_plugins_page_row(self::$_settings[ $addon_name ]['plugins_page_row']);
988
-        $addon->set_version(self::$_settings[ $addon_name ]['version']);
989
-        $addon->set_min_core_version(self::_effective_version(self::$_settings[ $addon_name ]['min_core_version']));
990
-        $addon->set_config_section(self::$_settings[ $addon_name ]['config_section']);
991
-        $addon->set_config_class(self::$_settings[ $addon_name ]['config_class']);
992
-        $addon->set_config_name(self::$_settings[ $addon_name ]['config_name']);
993
-        //unfortunately this can't be hooked in upon construction, because we don't have
994
-        //the plugin mainfile's path upon construction.
995
-        register_deactivation_hook($addon->get_main_plugin_file(), array($addon, 'deactivation'));
996
-        // call any additional admin_callback functions during load_admin_controller hook
997
-        if (! empty(self::$_settings[ $addon_name ]['admin_callback'])) {
998
-            add_action(
999
-                'AHEE__EE_System__load_controllers__load_admin_controllers',
1000
-                array($addon, self::$_settings[ $addon_name ]['admin_callback'])
1001
-            );
1002
-        }
1003
-        return $addon;
1004
-    }
944
+	/**
945
+	 * Loads and instantiates the EE_Addon class and adds it onto the registry
946
+	 *
947
+	 * @param string $addon_name
948
+	 * @return EE_Addon
949
+	 * @throws InvalidArgumentException
950
+	 * @throws InvalidInterfaceException
951
+	 * @throws InvalidDataTypeException
952
+	 * @throws ReflectionException
953
+	 * @throws EE_Error
954
+	 */
955
+	private static function _load_and_init_addon_class($addon_name)
956
+	{
957
+		$loader = EventEspresso\core\services\loaders\LoaderFactory::getLoader();
958
+		$addon  = $loader->getShared(
959
+			self::$_settings[ $addon_name ]['class_name'],
960
+			array('EE_Registry::create(addon)' => true)
961
+		);
962
+		// setter inject dep map if required
963
+		if ($addon instanceof RequiresDependencyMapInterface && $addon->dependencyMap() === null) {
964
+			$addon->setDependencyMap($loader->getShared('EE_Dependency_Map'));
965
+		}
966
+		// setter inject domain if required
967
+		if (
968
+			$addon instanceof RequiresDomainInterface
969
+			&& self::$_settings[ $addon_name ]['domain_fqcn'] !== ''
970
+			&& $addon->domain() === null
971
+		) {
972
+			$addon->setDomain(
973
+				$loader->getShared(
974
+					self::$_settings[ $addon_name ]['domain_fqcn'],
975
+					array(
976
+						self::$_settings[ $addon_name ]['main_file_path'],
977
+						self::$_settings[ $addon_name ]['version'],
978
+					)
979
+				)
980
+			);
981
+		}
982
+		$addon->set_name($addon_name);
983
+		$addon->set_plugin_slug(self::$_settings[ $addon_name ]['plugin_slug']);
984
+		$addon->set_plugin_basename(self::$_settings[ $addon_name ]['plugin_basename']);
985
+		$addon->set_main_plugin_file(self::$_settings[ $addon_name ]['main_file_path']);
986
+		$addon->set_plugin_action_slug(self::$_settings[ $addon_name ]['plugin_action_slug']);
987
+		$addon->set_plugins_page_row(self::$_settings[ $addon_name ]['plugins_page_row']);
988
+		$addon->set_version(self::$_settings[ $addon_name ]['version']);
989
+		$addon->set_min_core_version(self::_effective_version(self::$_settings[ $addon_name ]['min_core_version']));
990
+		$addon->set_config_section(self::$_settings[ $addon_name ]['config_section']);
991
+		$addon->set_config_class(self::$_settings[ $addon_name ]['config_class']);
992
+		$addon->set_config_name(self::$_settings[ $addon_name ]['config_name']);
993
+		//unfortunately this can't be hooked in upon construction, because we don't have
994
+		//the plugin mainfile's path upon construction.
995
+		register_deactivation_hook($addon->get_main_plugin_file(), array($addon, 'deactivation'));
996
+		// call any additional admin_callback functions during load_admin_controller hook
997
+		if (! empty(self::$_settings[ $addon_name ]['admin_callback'])) {
998
+			add_action(
999
+				'AHEE__EE_System__load_controllers__load_admin_controllers',
1000
+				array($addon, self::$_settings[ $addon_name ]['admin_callback'])
1001
+			);
1002
+		}
1003
+		return $addon;
1004
+	}
1005 1005
 
1006 1006
 
1007
-    /**
1008
-     *    load_pue_update - Update notifications
1009
-     *
1010
-     * @return void
1011
-     * @throws InvalidArgumentException
1012
-     * @throws InvalidDataTypeException
1013
-     * @throws InvalidInterfaceException
1014
-     */
1015
-    public static function load_pue_update()
1016
-    {
1017
-        // load PUE client
1018
-        require_once EE_THIRD_PARTY . 'pue' . DS . 'pue-client.php';
1019
-        // cycle thru settings
1020
-        foreach (self::$_settings as $settings) {
1021
-            if (! empty($settings['pue_options'])) {
1022
-                // initiate the class and start the plugin update engine!
1023
-                new PluginUpdateEngineChecker(
1024
-                // host file URL
1025
-                    'https://eventespresso.com',
1026
-                    // plugin slug(s)
1027
-                    array(
1028
-                        'premium'    => array('p' => $settings['pue_options']['pue_plugin_slug']),
1029
-                        'prerelease' => array('beta' => $settings['pue_options']['pue_plugin_slug'] . '-pr'),
1030
-                    ),
1031
-                    // options
1032
-                    array(
1033
-                        'apikey'            => EE_Registry::instance()->NET_CFG->core->site_license_key,
1034
-                        'lang_domain'       => 'event_espresso',
1035
-                        'checkPeriod'       => $settings['pue_options']['checkPeriod'],
1036
-                        'option_key'        => 'site_license_key',
1037
-                        'options_page_slug' => 'event_espresso',
1038
-                        'plugin_basename'   => $settings['pue_options']['plugin_basename'],
1039
-                        // if use_wp_update is TRUE it means you want FREE versions of the plugin to be updated from WP
1040
-                        'use_wp_update'     => $settings['pue_options']['use_wp_update'],
1041
-                    )
1042
-                );
1043
-            }
1044
-        }
1045
-    }
1007
+	/**
1008
+	 *    load_pue_update - Update notifications
1009
+	 *
1010
+	 * @return void
1011
+	 * @throws InvalidArgumentException
1012
+	 * @throws InvalidDataTypeException
1013
+	 * @throws InvalidInterfaceException
1014
+	 */
1015
+	public static function load_pue_update()
1016
+	{
1017
+		// load PUE client
1018
+		require_once EE_THIRD_PARTY . 'pue' . DS . 'pue-client.php';
1019
+		// cycle thru settings
1020
+		foreach (self::$_settings as $settings) {
1021
+			if (! empty($settings['pue_options'])) {
1022
+				// initiate the class and start the plugin update engine!
1023
+				new PluginUpdateEngineChecker(
1024
+				// host file URL
1025
+					'https://eventespresso.com',
1026
+					// plugin slug(s)
1027
+					array(
1028
+						'premium'    => array('p' => $settings['pue_options']['pue_plugin_slug']),
1029
+						'prerelease' => array('beta' => $settings['pue_options']['pue_plugin_slug'] . '-pr'),
1030
+					),
1031
+					// options
1032
+					array(
1033
+						'apikey'            => EE_Registry::instance()->NET_CFG->core->site_license_key,
1034
+						'lang_domain'       => 'event_espresso',
1035
+						'checkPeriod'       => $settings['pue_options']['checkPeriod'],
1036
+						'option_key'        => 'site_license_key',
1037
+						'options_page_slug' => 'event_espresso',
1038
+						'plugin_basename'   => $settings['pue_options']['plugin_basename'],
1039
+						// if use_wp_update is TRUE it means you want FREE versions of the plugin to be updated from WP
1040
+						'use_wp_update'     => $settings['pue_options']['use_wp_update'],
1041
+					)
1042
+				);
1043
+			}
1044
+		}
1045
+	}
1046 1046
 
1047 1047
 
1048
-    /**
1049
-     * Callback for EE_Brewing_Regular__messages_caf hook used to register message types.
1050
-     *
1051
-     * @since 4.4.0
1052
-     * @return void
1053
-     * @throws EE_Error
1054
-     */
1055
-    public static function register_message_types()
1056
-    {
1057
-        foreach (self::$_settings as $addon_name => $settings) {
1058
-            if (! empty($settings['message_types'])) {
1059
-                foreach ((array) $settings['message_types'] as $message_type => $message_type_settings) {
1060
-                    EE_Register_Message_Type::register($message_type, $message_type_settings);
1061
-                }
1062
-            }
1063
-        }
1064
-    }
1048
+	/**
1049
+	 * Callback for EE_Brewing_Regular__messages_caf hook used to register message types.
1050
+	 *
1051
+	 * @since 4.4.0
1052
+	 * @return void
1053
+	 * @throws EE_Error
1054
+	 */
1055
+	public static function register_message_types()
1056
+	{
1057
+		foreach (self::$_settings as $addon_name => $settings) {
1058
+			if (! empty($settings['message_types'])) {
1059
+				foreach ((array) $settings['message_types'] as $message_type => $message_type_settings) {
1060
+					EE_Register_Message_Type::register($message_type, $message_type_settings);
1061
+				}
1062
+			}
1063
+		}
1064
+	}
1065 1065
 
1066 1066
 
1067
-    /**
1068
-     * This deregisters an addon that was previously registered with a specific addon_name.
1069
-     *
1070
-     * @since    4.3.0
1071
-     * @param string $addon_name the name for the addon that was previously registered
1072
-     * @throws DomainException
1073
-     * @throws EE_Error
1074
-     * @throws InvalidArgumentException
1075
-     * @throws InvalidDataTypeException
1076
-     * @throws InvalidInterfaceException
1077
-     */
1078
-    public static function deregister($addon_name = null)
1079
-    {
1080
-        if (isset(self::$_settings[ $addon_name ]['class_name'])) {
1081
-            try {
1082
-                do_action('AHEE__EE_Register_Addon__deregister__before', $addon_name);
1083
-                $class_name = self::$_settings[ $addon_name ]['class_name'];
1084
-                if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
1085
-                    // setup DMS
1086
-                    EE_Register_Data_Migration_Scripts::deregister($addon_name);
1087
-                }
1088
-                if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
1089
-                    // register admin page
1090
-                    EE_Register_Admin_Page::deregister($addon_name);
1091
-                }
1092
-                if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
1093
-                    // add to list of modules to be registered
1094
-                    EE_Register_Module::deregister($addon_name);
1095
-                }
1096
-                if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
1097
-                    || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
1098
-                ) {
1099
-                    // add to list of shortcodes to be registered
1100
-                    EE_Register_Shortcode::deregister($addon_name);
1101
-                }
1102
-                if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
1103
-                    // if config_class present let's register config.
1104
-                    EE_Register_Config::deregister(self::$_settings[ $addon_name ]['config_class']);
1105
-                }
1106
-                if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
1107
-                    // add to list of widgets to be registered
1108
-                    EE_Register_Widget::deregister($addon_name);
1109
-                }
1110
-                if (! empty(self::$_settings[ $addon_name ]['model_paths'])
1111
-                    || ! empty(self::$_settings[ $addon_name ]['class_paths'])
1112
-                ) {
1113
-                    // add to list of shortcodes to be registered
1114
-                    EE_Register_Model::deregister($addon_name);
1115
-                }
1116
-                if (! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
1117
-                    || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
1118
-                ) {
1119
-                    // add to list of shortcodes to be registered
1120
-                    EE_Register_Model_Extensions::deregister($addon_name);
1121
-                }
1122
-                if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
1123
-                    foreach (
1124
-                        (array) self::$_settings[ $addon_name ]['message_types'] as $message_type =>
1125
-                        $message_type_settings
1126
-                    ) {
1127
-                        EE_Register_Message_Type::deregister($message_type);
1128
-                    }
1129
-                }
1130
-                //deregister capabilities for addon
1131
-                if (
1132
-                    ! empty(self::$_settings[ $addon_name ]['capabilities'])
1133
-                    || ! empty(self::$_settings[ $addon_name ]['capability_maps'])
1134
-                ) {
1135
-                    EE_Register_Capabilities::deregister($addon_name);
1136
-                }
1137
-                //deregister custom_post_types for addon
1138
-                if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])) {
1139
-                    EE_Register_CPT::deregister($addon_name);
1140
-                }
1141
-                if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
1142
-                    EE_Register_Payment_Method::deregister($addon_name);
1143
-                }
1144
-                $addon = EE_Registry::instance()->getAddon($class_name);
1145
-                if ($addon instanceof EE_Addon) {
1146
-                    remove_action(
1147
-                        'deactivate_' . $addon->get_main_plugin_file_basename(),
1148
-                        array($addon, 'deactivation')
1149
-                    );
1150
-                    remove_action(
1151
-                        'AHEE__EE_System__perform_activations_upgrades_and_migrations',
1152
-                        array($addon, 'initialize_db_if_no_migrations_required')
1153
-                    );
1154
-                    //remove `after_registration` call
1155
-                    remove_action(
1156
-                        'AHEE__EE_System__load_espresso_addons__complete',
1157
-                        array($addon, 'after_registration'),
1158
-                        999
1159
-                    );
1160
-                }
1161
-                EE_Registry::instance()->removeAddon($class_name);
1162
-            } catch (OutOfBoundsException $addon_not_yet_registered_exception) {
1163
-                // the add-on was not yet registered in the registry,
1164
-                // so RegistryContainer::__get() throws this exception.
1165
-                // also no need to worry about this or log it,
1166
-                // it's ok to deregister an add-on before its registered in the registry
1167
-            } catch (Exception $e) {
1168
-                new ExceptionLogger($e);
1169
-            }
1170
-            unset(self::$_settings[ $addon_name ]);
1171
-            do_action('AHEE__EE_Register_Addon__deregister__after', $addon_name);
1172
-        }
1173
-    }
1067
+	/**
1068
+	 * This deregisters an addon that was previously registered with a specific addon_name.
1069
+	 *
1070
+	 * @since    4.3.0
1071
+	 * @param string $addon_name the name for the addon that was previously registered
1072
+	 * @throws DomainException
1073
+	 * @throws EE_Error
1074
+	 * @throws InvalidArgumentException
1075
+	 * @throws InvalidDataTypeException
1076
+	 * @throws InvalidInterfaceException
1077
+	 */
1078
+	public static function deregister($addon_name = null)
1079
+	{
1080
+		if (isset(self::$_settings[ $addon_name ]['class_name'])) {
1081
+			try {
1082
+				do_action('AHEE__EE_Register_Addon__deregister__before', $addon_name);
1083
+				$class_name = self::$_settings[ $addon_name ]['class_name'];
1084
+				if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
1085
+					// setup DMS
1086
+					EE_Register_Data_Migration_Scripts::deregister($addon_name);
1087
+				}
1088
+				if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
1089
+					// register admin page
1090
+					EE_Register_Admin_Page::deregister($addon_name);
1091
+				}
1092
+				if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
1093
+					// add to list of modules to be registered
1094
+					EE_Register_Module::deregister($addon_name);
1095
+				}
1096
+				if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
1097
+					|| ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
1098
+				) {
1099
+					// add to list of shortcodes to be registered
1100
+					EE_Register_Shortcode::deregister($addon_name);
1101
+				}
1102
+				if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
1103
+					// if config_class present let's register config.
1104
+					EE_Register_Config::deregister(self::$_settings[ $addon_name ]['config_class']);
1105
+				}
1106
+				if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
1107
+					// add to list of widgets to be registered
1108
+					EE_Register_Widget::deregister($addon_name);
1109
+				}
1110
+				if (! empty(self::$_settings[ $addon_name ]['model_paths'])
1111
+					|| ! empty(self::$_settings[ $addon_name ]['class_paths'])
1112
+				) {
1113
+					// add to list of shortcodes to be registered
1114
+					EE_Register_Model::deregister($addon_name);
1115
+				}
1116
+				if (! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
1117
+					|| ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
1118
+				) {
1119
+					// add to list of shortcodes to be registered
1120
+					EE_Register_Model_Extensions::deregister($addon_name);
1121
+				}
1122
+				if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
1123
+					foreach (
1124
+						(array) self::$_settings[ $addon_name ]['message_types'] as $message_type =>
1125
+						$message_type_settings
1126
+					) {
1127
+						EE_Register_Message_Type::deregister($message_type);
1128
+					}
1129
+				}
1130
+				//deregister capabilities for addon
1131
+				if (
1132
+					! empty(self::$_settings[ $addon_name ]['capabilities'])
1133
+					|| ! empty(self::$_settings[ $addon_name ]['capability_maps'])
1134
+				) {
1135
+					EE_Register_Capabilities::deregister($addon_name);
1136
+				}
1137
+				//deregister custom_post_types for addon
1138
+				if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])) {
1139
+					EE_Register_CPT::deregister($addon_name);
1140
+				}
1141
+				if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
1142
+					EE_Register_Payment_Method::deregister($addon_name);
1143
+				}
1144
+				$addon = EE_Registry::instance()->getAddon($class_name);
1145
+				if ($addon instanceof EE_Addon) {
1146
+					remove_action(
1147
+						'deactivate_' . $addon->get_main_plugin_file_basename(),
1148
+						array($addon, 'deactivation')
1149
+					);
1150
+					remove_action(
1151
+						'AHEE__EE_System__perform_activations_upgrades_and_migrations',
1152
+						array($addon, 'initialize_db_if_no_migrations_required')
1153
+					);
1154
+					//remove `after_registration` call
1155
+					remove_action(
1156
+						'AHEE__EE_System__load_espresso_addons__complete',
1157
+						array($addon, 'after_registration'),
1158
+						999
1159
+					);
1160
+				}
1161
+				EE_Registry::instance()->removeAddon($class_name);
1162
+			} catch (OutOfBoundsException $addon_not_yet_registered_exception) {
1163
+				// the add-on was not yet registered in the registry,
1164
+				// so RegistryContainer::__get() throws this exception.
1165
+				// also no need to worry about this or log it,
1166
+				// it's ok to deregister an add-on before its registered in the registry
1167
+			} catch (Exception $e) {
1168
+				new ExceptionLogger($e);
1169
+			}
1170
+			unset(self::$_settings[ $addon_name ]);
1171
+			do_action('AHEE__EE_Register_Addon__deregister__after', $addon_name);
1172
+		}
1173
+	}
1174 1174
 }
1175 1175
 // End of file EE_Register_Addon.lib.php
1176 1176
 // Location: /core/libraries/plugin_api/EE_Register_Addon.lib.php
Please login to merge, or discard this patch.
Spacing   +105 added lines, -105 removed lines patch added patch discarded remove patch
@@ -72,15 +72,15 @@  discard block
 block discarded – undo
72 72
         // offsets:    0 . 1 . 2 . 3 . 4
73 73
         $version_parts = explode('.', $min_core_version);
74 74
         //check they specified the micro version (after 2nd period)
75
-        if (! isset($version_parts[2])) {
75
+        if ( ! isset($version_parts[2])) {
76 76
             $version_parts[2] = '0';
77 77
         }
78 78
         //if they didn't specify the 'p', or 'rc' part. Just assume the lowest possible
79 79
         //soon we can assume that's 'rc', but this current version is 'alpha'
80
-        if (! isset($version_parts[3])) {
80
+        if ( ! isset($version_parts[3])) {
81 81
             $version_parts[3] = 'dev';
82 82
         }
83
-        if (! isset($version_parts[4])) {
83
+        if ( ! isset($version_parts[4])) {
84 84
             $version_parts[4] = '000';
85 85
         }
86 86
         return implode('.', $version_parts);
@@ -256,7 +256,7 @@  discard block
 block discarded – undo
256 256
         // setup PUE
257 257
         EE_Register_Addon::_parse_pue_options($addon_name, $class_name, $setup_args);
258 258
         // does this addon work with this version of core or WordPress ?
259
-        if (! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
259
+        if ( ! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
260 260
             return;
261 261
         }
262 262
         // register namespaces
@@ -314,7 +314,7 @@  discard block
 block discarded – undo
314 314
                 )
315 315
             );
316 316
         }
317
-        if (! isset($setup_args['main_file_path']) || empty($setup_args['main_file_path'])) {
317
+        if ( ! isset($setup_args['main_file_path']) || empty($setup_args['main_file_path'])) {
318 318
             throw new EE_Error(
319 319
                 sprintf(
320 320
                     __(
@@ -326,7 +326,7 @@  discard block
 block discarded – undo
326 326
             );
327 327
         }
328 328
         // check that addon has not already been registered with that name
329
-        if (isset(self::$_settings[ $addon_name ]) && ! did_action('activate_plugin')) {
329
+        if (isset(self::$_settings[$addon_name]) && ! did_action('activate_plugin')) {
330 330
             throw new EE_Error(
331 331
                 sprintf(
332 332
                     __(
@@ -358,7 +358,7 @@  discard block
 block discarded – undo
358 358
         // check if classname is fully  qualified or is a legacy classname already prefixed with 'EE_'
359 359
         return strpos($class_name, '\\') || strpos($class_name, 'EE_') === 0
360 360
             ? $class_name
361
-            : 'EE_' . $class_name;
361
+            : 'EE_'.$class_name;
362 362
     }
363 363
 
364 364
 
@@ -519,9 +519,9 @@  discard block
 block discarded – undo
519 519
         $incompatibility_message = '';
520 520
         //check whether this addon version is compatible with EE core
521 521
         if (
522
-            isset(EE_Register_Addon::$_incompatible_addons[ $addon_name ])
522
+            isset(EE_Register_Addon::$_incompatible_addons[$addon_name])
523 523
             && ! self::_meets_min_core_version_requirement(
524
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
524
+                EE_Register_Addon::$_incompatible_addons[$addon_name],
525 525
                 $addon_settings['version']
526 526
             )
527 527
         ) {
@@ -531,7 +531,7 @@  discard block
 block discarded – undo
531 531
                 ),
532 532
                 $addon_name,
533 533
                 '<br />',
534
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
534
+                EE_Register_Addon::$_incompatible_addons[$addon_name],
535 535
                 '<span style="font-weight: bold; color: #D54E21;">',
536 536
                 '</span><br />'
537 537
             );
@@ -563,7 +563,7 @@  discard block
 block discarded – undo
563 563
                 '</span><br />'
564 564
             );
565 565
         }
566
-        if (! empty($incompatibility_message)) {
566
+        if ( ! empty($incompatibility_message)) {
567 567
             // remove 'activate' from the REQUEST
568 568
             // so WP doesn't erroneously tell the user the plugin activated fine when it didn't
569 569
             unset($_GET['activate'], $_REQUEST['activate']);
@@ -591,11 +591,11 @@  discard block
 block discarded – undo
591 591
      */
592 592
     private static function _parse_pue_options($addon_name, $class_name, array $setup_args)
593 593
     {
594
-        if (! empty($setup_args['pue_options'])) {
595
-            self::$_settings[ $addon_name ]['pue_options'] = array(
594
+        if ( ! empty($setup_args['pue_options'])) {
595
+            self::$_settings[$addon_name]['pue_options'] = array(
596 596
                 'pue_plugin_slug' => isset($setup_args['pue_options']['pue_plugin_slug'])
597 597
                     ? (string) $setup_args['pue_options']['pue_plugin_slug']
598
-                    : 'espresso_' . strtolower($class_name),
598
+                    : 'espresso_'.strtolower($class_name),
599 599
                 'plugin_basename' => isset($setup_args['pue_options']['plugin_basename'])
600 600
                     ? (string) $setup_args['pue_options']['plugin_basename']
601 601
                     : plugin_basename($setup_args['main_file_path']),
@@ -655,12 +655,12 @@  discard block
 block discarded – undo
655 655
             //(as the newly-activated addon wasn't around the first time addons were registered).
656 656
             //Note: the presence of pue_options in the addon registration options will initialize the $_settings
657 657
             //property for the add-on, but the add-on is only partially initialized.  Hence, the additional check.
658
-            if (! isset(self::$_settings[ $addon_name ])
659
-                || (isset(self::$_settings[ $addon_name ])
660
-                    && ! isset(self::$_settings[ $addon_name ]['class_name'])
658
+            if ( ! isset(self::$_settings[$addon_name])
659
+                || (isset(self::$_settings[$addon_name])
660
+                    && ! isset(self::$_settings[$addon_name]['class_name'])
661 661
                 )
662 662
             ) {
663
-                self::$_settings[ $addon_name ] = $addon_settings;
663
+                self::$_settings[$addon_name] = $addon_settings;
664 664
                 $addon                          = self::_load_and_init_addon_class($addon_name);
665 665
                 $addon->set_activation_indicator_option();
666 666
                 // dont bother setting up the rest of the addon.
@@ -686,10 +686,10 @@  discard block
 block discarded – undo
686 686
             );
687 687
         }
688 688
         // make sure addon settings are set correctly without overwriting anything existing
689
-        if (isset(self::$_settings[ $addon_name ])) {
690
-            self::$_settings[ $addon_name ] += $addon_settings;
689
+        if (isset(self::$_settings[$addon_name])) {
690
+            self::$_settings[$addon_name] += $addon_settings;
691 691
         } else {
692
-            self::$_settings[ $addon_name ] = $addon_settings;
692
+            self::$_settings[$addon_name] = $addon_settings;
693 693
         }
694 694
         return false;
695 695
     }
@@ -702,13 +702,13 @@  discard block
 block discarded – undo
702 702
      */
703 703
     private static function _setup_autoloaders($addon_name)
704 704
     {
705
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_paths'])) {
705
+        if ( ! empty(self::$_settings[$addon_name]['autoloader_paths'])) {
706 706
             // setup autoloader for single file
707
-            EEH_Autoloader::instance()->register_autoloader(self::$_settings[ $addon_name ]['autoloader_paths']);
707
+            EEH_Autoloader::instance()->register_autoloader(self::$_settings[$addon_name]['autoloader_paths']);
708 708
         }
709 709
         // setup autoloaders for folders
710
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_folders'])) {
711
-            foreach ((array) self::$_settings[ $addon_name ]['autoloader_folders'] as $autoloader_folder) {
710
+        if ( ! empty(self::$_settings[$addon_name]['autoloader_folders'])) {
711
+            foreach ((array) self::$_settings[$addon_name]['autoloader_folders'] as $autoloader_folder) {
712 712
                 EEH_Autoloader::register_autoloaders_for_each_file_in_folder($autoloader_folder);
713 713
             }
714 714
         }
@@ -726,27 +726,27 @@  discard block
 block discarded – undo
726 726
     {
727 727
         // register new models
728 728
         if (
729
-            ! empty(self::$_settings[ $addon_name ]['model_paths'])
730
-            || ! empty(self::$_settings[ $addon_name ]['class_paths'])
729
+            ! empty(self::$_settings[$addon_name]['model_paths'])
730
+            || ! empty(self::$_settings[$addon_name]['class_paths'])
731 731
         ) {
732 732
             EE_Register_Model::register(
733 733
                 $addon_name,
734 734
                 array(
735
-                    'model_paths' => self::$_settings[ $addon_name ]['model_paths'],
736
-                    'class_paths' => self::$_settings[ $addon_name ]['class_paths'],
735
+                    'model_paths' => self::$_settings[$addon_name]['model_paths'],
736
+                    'class_paths' => self::$_settings[$addon_name]['class_paths'],
737 737
                 )
738 738
             );
739 739
         }
740 740
         // register model extensions
741 741
         if (
742
-            ! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
743
-            || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
742
+            ! empty(self::$_settings[$addon_name]['model_extension_paths'])
743
+            || ! empty(self::$_settings[$addon_name]['class_extension_paths'])
744 744
         ) {
745 745
             EE_Register_Model_Extensions::register(
746 746
                 $addon_name,
747 747
                 array(
748
-                    'model_extension_paths' => self::$_settings[ $addon_name ]['model_extension_paths'],
749
-                    'class_extension_paths' => self::$_settings[ $addon_name ]['class_extension_paths'],
748
+                    'model_extension_paths' => self::$_settings[$addon_name]['model_extension_paths'],
749
+                    'class_extension_paths' => self::$_settings[$addon_name]['class_extension_paths'],
750 750
                 )
751 751
             );
752 752
         }
@@ -761,10 +761,10 @@  discard block
 block discarded – undo
761 761
     private static function _register_data_migration_scripts($addon_name)
762 762
     {
763 763
         // setup DMS
764
-        if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
764
+        if ( ! empty(self::$_settings[$addon_name]['dms_paths'])) {
765 765
             EE_Register_Data_Migration_Scripts::register(
766 766
                 $addon_name,
767
-                array('dms_paths' => self::$_settings[ $addon_name ]['dms_paths'])
767
+                array('dms_paths' => self::$_settings[$addon_name]['dms_paths'])
768 768
             );
769 769
         }
770 770
     }
@@ -778,12 +778,12 @@  discard block
 block discarded – undo
778 778
     private static function _register_config($addon_name)
779 779
     {
780 780
         // if config_class is present let's register config.
781
-        if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
781
+        if ( ! empty(self::$_settings[$addon_name]['config_class'])) {
782 782
             EE_Register_Config::register(
783
-                self::$_settings[ $addon_name ]['config_class'],
783
+                self::$_settings[$addon_name]['config_class'],
784 784
                 array(
785
-                    'config_section' => self::$_settings[ $addon_name ]['config_section'],
786
-                    'config_name'    => self::$_settings[ $addon_name ]['config_name'],
785
+                    'config_section' => self::$_settings[$addon_name]['config_section'],
786
+                    'config_name'    => self::$_settings[$addon_name]['config_name'],
787 787
                 )
788 788
             );
789 789
         }
@@ -797,10 +797,10 @@  discard block
 block discarded – undo
797 797
      */
798 798
     private static function _register_admin_pages($addon_name)
799 799
     {
800
-        if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
800
+        if ( ! empty(self::$_settings[$addon_name]['admin_path'])) {
801 801
             EE_Register_Admin_Page::register(
802 802
                 $addon_name,
803
-                array('page_path' => self::$_settings[ $addon_name ]['admin_path'])
803
+                array('page_path' => self::$_settings[$addon_name]['admin_path'])
804 804
             );
805 805
         }
806 806
     }
@@ -813,10 +813,10 @@  discard block
 block discarded – undo
813 813
      */
814 814
     private static function _register_modules($addon_name)
815 815
     {
816
-        if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
816
+        if ( ! empty(self::$_settings[$addon_name]['module_paths'])) {
817 817
             EE_Register_Module::register(
818 818
                 $addon_name,
819
-                array('module_paths' => self::$_settings[ $addon_name ]['module_paths'])
819
+                array('module_paths' => self::$_settings[$addon_name]['module_paths'])
820 820
             );
821 821
         }
822 822
     }
@@ -829,17 +829,17 @@  discard block
 block discarded – undo
829 829
      */
830 830
     private static function _register_shortcodes($addon_name)
831 831
     {
832
-        if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
833
-            || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
832
+        if ( ! empty(self::$_settings[$addon_name]['shortcode_paths'])
833
+            || ! empty(self::$_settings[$addon_name]['shortcode_fqcns'])
834 834
         ) {
835 835
             EE_Register_Shortcode::register(
836 836
                 $addon_name,
837 837
                 array(
838
-                    'shortcode_paths' => isset(self::$_settings[ $addon_name ]['shortcode_paths'])
839
-                        ? self::$_settings[ $addon_name ]['shortcode_paths']
838
+                    'shortcode_paths' => isset(self::$_settings[$addon_name]['shortcode_paths'])
839
+                        ? self::$_settings[$addon_name]['shortcode_paths']
840 840
                         : array(),
841
-                    'shortcode_fqcns' => isset(self::$_settings[ $addon_name ]['shortcode_fqcns'])
842
-                        ? self::$_settings[ $addon_name ]['shortcode_fqcns']
841
+                    'shortcode_fqcns' => isset(self::$_settings[$addon_name]['shortcode_fqcns'])
842
+                        ? self::$_settings[$addon_name]['shortcode_fqcns']
843 843
                         : array(),
844 844
                 )
845 845
             );
@@ -854,10 +854,10 @@  discard block
 block discarded – undo
854 854
      */
855 855
     private static function _register_widgets($addon_name)
856 856
     {
857
-        if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
857
+        if ( ! empty(self::$_settings[$addon_name]['widget_paths'])) {
858 858
             EE_Register_Widget::register(
859 859
                 $addon_name,
860
-                array('widget_paths' => self::$_settings[ $addon_name ]['widget_paths'])
860
+                array('widget_paths' => self::$_settings[$addon_name]['widget_paths'])
861 861
             );
862 862
         }
863 863
     }
@@ -870,12 +870,12 @@  discard block
 block discarded – undo
870 870
      */
871 871
     private static function _register_capabilities($addon_name)
872 872
     {
873
-        if (! empty(self::$_settings[ $addon_name ]['capabilities'])) {
873
+        if ( ! empty(self::$_settings[$addon_name]['capabilities'])) {
874 874
             EE_Register_Capabilities::register(
875 875
                 $addon_name,
876 876
                 array(
877
-                    'capabilities'    => self::$_settings[ $addon_name ]['capabilities'],
878
-                    'capability_maps' => self::$_settings[ $addon_name ]['capability_maps'],
877
+                    'capabilities'    => self::$_settings[$addon_name]['capabilities'],
878
+                    'capability_maps' => self::$_settings[$addon_name]['capability_maps'],
879 879
                 )
880 880
             );
881 881
         }
@@ -889,7 +889,7 @@  discard block
 block discarded – undo
889 889
      */
890 890
     private static function _register_message_types($addon_name)
891 891
     {
892
-        if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
892
+        if ( ! empty(self::$_settings[$addon_name]['message_types'])) {
893 893
             add_action(
894 894
                 'EE_Brewing_Regular___messages_caf',
895 895
                 array('EE_Register_Addon', 'register_message_types')
@@ -906,15 +906,15 @@  discard block
 block discarded – undo
906 906
     private static function _register_custom_post_types($addon_name)
907 907
     {
908 908
         if (
909
-            ! empty(self::$_settings[ $addon_name ]['custom_post_types'])
910
-            || ! empty(self::$_settings[ $addon_name ]['custom_taxonomies'])
909
+            ! empty(self::$_settings[$addon_name]['custom_post_types'])
910
+            || ! empty(self::$_settings[$addon_name]['custom_taxonomies'])
911 911
         ) {
912 912
             EE_Register_CPT::register(
913 913
                 $addon_name,
914 914
                 array(
915
-                    'cpts'          => self::$_settings[ $addon_name ]['custom_post_types'],
916
-                    'cts'           => self::$_settings[ $addon_name ]['custom_taxonomies'],
917
-                    'default_terms' => self::$_settings[ $addon_name ]['default_terms'],
915
+                    'cpts'          => self::$_settings[$addon_name]['custom_post_types'],
916
+                    'cts'           => self::$_settings[$addon_name]['custom_taxonomies'],
917
+                    'default_terms' => self::$_settings[$addon_name]['default_terms'],
918 918
                 )
919 919
             );
920 920
         }
@@ -932,10 +932,10 @@  discard block
 block discarded – undo
932 932
      */
933 933
     private static function _register_payment_methods($addon_name)
934 934
     {
935
-        if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
935
+        if ( ! empty(self::$_settings[$addon_name]['payment_method_paths'])) {
936 936
             EE_Register_Payment_Method::register(
937 937
                 $addon_name,
938
-                array('payment_method_paths' => self::$_settings[ $addon_name ]['payment_method_paths'])
938
+                array('payment_method_paths' => self::$_settings[$addon_name]['payment_method_paths'])
939 939
             );
940 940
         }
941 941
     }
@@ -956,7 +956,7 @@  discard block
 block discarded – undo
956 956
     {
957 957
         $loader = EventEspresso\core\services\loaders\LoaderFactory::getLoader();
958 958
         $addon  = $loader->getShared(
959
-            self::$_settings[ $addon_name ]['class_name'],
959
+            self::$_settings[$addon_name]['class_name'],
960 960
             array('EE_Registry::create(addon)' => true)
961 961
         );
962 962
         // setter inject dep map if required
@@ -966,38 +966,38 @@  discard block
 block discarded – undo
966 966
         // setter inject domain if required
967 967
         if (
968 968
             $addon instanceof RequiresDomainInterface
969
-            && self::$_settings[ $addon_name ]['domain_fqcn'] !== ''
969
+            && self::$_settings[$addon_name]['domain_fqcn'] !== ''
970 970
             && $addon->domain() === null
971 971
         ) {
972 972
             $addon->setDomain(
973 973
                 $loader->getShared(
974
-                    self::$_settings[ $addon_name ]['domain_fqcn'],
974
+                    self::$_settings[$addon_name]['domain_fqcn'],
975 975
                     array(
976
-                        self::$_settings[ $addon_name ]['main_file_path'],
977
-                        self::$_settings[ $addon_name ]['version'],
976
+                        self::$_settings[$addon_name]['main_file_path'],
977
+                        self::$_settings[$addon_name]['version'],
978 978
                     )
979 979
                 )
980 980
             );
981 981
         }
982 982
         $addon->set_name($addon_name);
983
-        $addon->set_plugin_slug(self::$_settings[ $addon_name ]['plugin_slug']);
984
-        $addon->set_plugin_basename(self::$_settings[ $addon_name ]['plugin_basename']);
985
-        $addon->set_main_plugin_file(self::$_settings[ $addon_name ]['main_file_path']);
986
-        $addon->set_plugin_action_slug(self::$_settings[ $addon_name ]['plugin_action_slug']);
987
-        $addon->set_plugins_page_row(self::$_settings[ $addon_name ]['plugins_page_row']);
988
-        $addon->set_version(self::$_settings[ $addon_name ]['version']);
989
-        $addon->set_min_core_version(self::_effective_version(self::$_settings[ $addon_name ]['min_core_version']));
990
-        $addon->set_config_section(self::$_settings[ $addon_name ]['config_section']);
991
-        $addon->set_config_class(self::$_settings[ $addon_name ]['config_class']);
992
-        $addon->set_config_name(self::$_settings[ $addon_name ]['config_name']);
983
+        $addon->set_plugin_slug(self::$_settings[$addon_name]['plugin_slug']);
984
+        $addon->set_plugin_basename(self::$_settings[$addon_name]['plugin_basename']);
985
+        $addon->set_main_plugin_file(self::$_settings[$addon_name]['main_file_path']);
986
+        $addon->set_plugin_action_slug(self::$_settings[$addon_name]['plugin_action_slug']);
987
+        $addon->set_plugins_page_row(self::$_settings[$addon_name]['plugins_page_row']);
988
+        $addon->set_version(self::$_settings[$addon_name]['version']);
989
+        $addon->set_min_core_version(self::_effective_version(self::$_settings[$addon_name]['min_core_version']));
990
+        $addon->set_config_section(self::$_settings[$addon_name]['config_section']);
991
+        $addon->set_config_class(self::$_settings[$addon_name]['config_class']);
992
+        $addon->set_config_name(self::$_settings[$addon_name]['config_name']);
993 993
         //unfortunately this can't be hooked in upon construction, because we don't have
994 994
         //the plugin mainfile's path upon construction.
995 995
         register_deactivation_hook($addon->get_main_plugin_file(), array($addon, 'deactivation'));
996 996
         // call any additional admin_callback functions during load_admin_controller hook
997
-        if (! empty(self::$_settings[ $addon_name ]['admin_callback'])) {
997
+        if ( ! empty(self::$_settings[$addon_name]['admin_callback'])) {
998 998
             add_action(
999 999
                 'AHEE__EE_System__load_controllers__load_admin_controllers',
1000
-                array($addon, self::$_settings[ $addon_name ]['admin_callback'])
1000
+                array($addon, self::$_settings[$addon_name]['admin_callback'])
1001 1001
             );
1002 1002
         }
1003 1003
         return $addon;
@@ -1015,10 +1015,10 @@  discard block
 block discarded – undo
1015 1015
     public static function load_pue_update()
1016 1016
     {
1017 1017
         // load PUE client
1018
-        require_once EE_THIRD_PARTY . 'pue' . DS . 'pue-client.php';
1018
+        require_once EE_THIRD_PARTY.'pue'.DS.'pue-client.php';
1019 1019
         // cycle thru settings
1020 1020
         foreach (self::$_settings as $settings) {
1021
-            if (! empty($settings['pue_options'])) {
1021
+            if ( ! empty($settings['pue_options'])) {
1022 1022
                 // initiate the class and start the plugin update engine!
1023 1023
                 new PluginUpdateEngineChecker(
1024 1024
                 // host file URL
@@ -1026,7 +1026,7 @@  discard block
 block discarded – undo
1026 1026
                     // plugin slug(s)
1027 1027
                     array(
1028 1028
                         'premium'    => array('p' => $settings['pue_options']['pue_plugin_slug']),
1029
-                        'prerelease' => array('beta' => $settings['pue_options']['pue_plugin_slug'] . '-pr'),
1029
+                        'prerelease' => array('beta' => $settings['pue_options']['pue_plugin_slug'].'-pr'),
1030 1030
                     ),
1031 1031
                     // options
1032 1032
                     array(
@@ -1055,7 +1055,7 @@  discard block
 block discarded – undo
1055 1055
     public static function register_message_types()
1056 1056
     {
1057 1057
         foreach (self::$_settings as $addon_name => $settings) {
1058
-            if (! empty($settings['message_types'])) {
1058
+            if ( ! empty($settings['message_types'])) {
1059 1059
                 foreach ((array) $settings['message_types'] as $message_type => $message_type_settings) {
1060 1060
                     EE_Register_Message_Type::register($message_type, $message_type_settings);
1061 1061
                 }
@@ -1077,51 +1077,51 @@  discard block
 block discarded – undo
1077 1077
      */
1078 1078
     public static function deregister($addon_name = null)
1079 1079
     {
1080
-        if (isset(self::$_settings[ $addon_name ]['class_name'])) {
1080
+        if (isset(self::$_settings[$addon_name]['class_name'])) {
1081 1081
             try {
1082 1082
                 do_action('AHEE__EE_Register_Addon__deregister__before', $addon_name);
1083
-                $class_name = self::$_settings[ $addon_name ]['class_name'];
1084
-                if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
1083
+                $class_name = self::$_settings[$addon_name]['class_name'];
1084
+                if ( ! empty(self::$_settings[$addon_name]['dms_paths'])) {
1085 1085
                     // setup DMS
1086 1086
                     EE_Register_Data_Migration_Scripts::deregister($addon_name);
1087 1087
                 }
1088
-                if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
1088
+                if ( ! empty(self::$_settings[$addon_name]['admin_path'])) {
1089 1089
                     // register admin page
1090 1090
                     EE_Register_Admin_Page::deregister($addon_name);
1091 1091
                 }
1092
-                if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
1092
+                if ( ! empty(self::$_settings[$addon_name]['module_paths'])) {
1093 1093
                     // add to list of modules to be registered
1094 1094
                     EE_Register_Module::deregister($addon_name);
1095 1095
                 }
1096
-                if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
1097
-                    || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
1096
+                if ( ! empty(self::$_settings[$addon_name]['shortcode_paths'])
1097
+                    || ! empty(self::$_settings[$addon_name]['shortcode_fqcns'])
1098 1098
                 ) {
1099 1099
                     // add to list of shortcodes to be registered
1100 1100
                     EE_Register_Shortcode::deregister($addon_name);
1101 1101
                 }
1102
-                if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
1102
+                if ( ! empty(self::$_settings[$addon_name]['config_class'])) {
1103 1103
                     // if config_class present let's register config.
1104
-                    EE_Register_Config::deregister(self::$_settings[ $addon_name ]['config_class']);
1104
+                    EE_Register_Config::deregister(self::$_settings[$addon_name]['config_class']);
1105 1105
                 }
1106
-                if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
1106
+                if ( ! empty(self::$_settings[$addon_name]['widget_paths'])) {
1107 1107
                     // add to list of widgets to be registered
1108 1108
                     EE_Register_Widget::deregister($addon_name);
1109 1109
                 }
1110
-                if (! empty(self::$_settings[ $addon_name ]['model_paths'])
1111
-                    || ! empty(self::$_settings[ $addon_name ]['class_paths'])
1110
+                if ( ! empty(self::$_settings[$addon_name]['model_paths'])
1111
+                    || ! empty(self::$_settings[$addon_name]['class_paths'])
1112 1112
                 ) {
1113 1113
                     // add to list of shortcodes to be registered
1114 1114
                     EE_Register_Model::deregister($addon_name);
1115 1115
                 }
1116
-                if (! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
1117
-                    || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
1116
+                if ( ! empty(self::$_settings[$addon_name]['model_extension_paths'])
1117
+                    || ! empty(self::$_settings[$addon_name]['class_extension_paths'])
1118 1118
                 ) {
1119 1119
                     // add to list of shortcodes to be registered
1120 1120
                     EE_Register_Model_Extensions::deregister($addon_name);
1121 1121
                 }
1122
-                if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
1122
+                if ( ! empty(self::$_settings[$addon_name]['message_types'])) {
1123 1123
                     foreach (
1124
-                        (array) self::$_settings[ $addon_name ]['message_types'] as $message_type =>
1124
+                        (array) self::$_settings[$addon_name]['message_types'] as $message_type =>
1125 1125
                         $message_type_settings
1126 1126
                     ) {
1127 1127
                         EE_Register_Message_Type::deregister($message_type);
@@ -1129,22 +1129,22 @@  discard block
 block discarded – undo
1129 1129
                 }
1130 1130
                 //deregister capabilities for addon
1131 1131
                 if (
1132
-                    ! empty(self::$_settings[ $addon_name ]['capabilities'])
1133
-                    || ! empty(self::$_settings[ $addon_name ]['capability_maps'])
1132
+                    ! empty(self::$_settings[$addon_name]['capabilities'])
1133
+                    || ! empty(self::$_settings[$addon_name]['capability_maps'])
1134 1134
                 ) {
1135 1135
                     EE_Register_Capabilities::deregister($addon_name);
1136 1136
                 }
1137 1137
                 //deregister custom_post_types for addon
1138
-                if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])) {
1138
+                if ( ! empty(self::$_settings[$addon_name]['custom_post_types'])) {
1139 1139
                     EE_Register_CPT::deregister($addon_name);
1140 1140
                 }
1141
-                if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
1141
+                if ( ! empty(self::$_settings[$addon_name]['payment_method_paths'])) {
1142 1142
                     EE_Register_Payment_Method::deregister($addon_name);
1143 1143
                 }
1144 1144
                 $addon = EE_Registry::instance()->getAddon($class_name);
1145 1145
                 if ($addon instanceof EE_Addon) {
1146 1146
                     remove_action(
1147
-                        'deactivate_' . $addon->get_main_plugin_file_basename(),
1147
+                        'deactivate_'.$addon->get_main_plugin_file_basename(),
1148 1148
                         array($addon, 'deactivation')
1149 1149
                     );
1150 1150
                     remove_action(
@@ -1167,7 +1167,7 @@  discard block
 block discarded – undo
1167 1167
             } catch (Exception $e) {
1168 1168
                 new ExceptionLogger($e);
1169 1169
             }
1170
-            unset(self::$_settings[ $addon_name ]);
1170
+            unset(self::$_settings[$addon_name]);
1171 1171
             do_action('AHEE__EE_Register_Addon__deregister__after', $addon_name);
1172 1172
         }
1173 1173
     }
Please login to merge, or discard this patch.
core/libraries/plugin_api/EE_Register_Data_Migration_Scripts.lib.php 2 patches
Indentation   +87 added lines, -87 removed lines patch added patch discarded remove patch
@@ -18,99 +18,99 @@
 block discarded – undo
18 18
 class EE_Register_Data_Migration_Scripts implements EEI_Plugin_API
19 19
 {
20 20
 
21
-    /**
22
-     * Holds values for registered DMSs
23
-     *
24
-     * @var array[][]
25
-     */
26
-    protected static $_settings = array();
21
+	/**
22
+	 * Holds values for registered DMSs
23
+	 *
24
+	 * @var array[][]
25
+	 */
26
+	protected static $_settings = array();
27 27
 
28 28
 
29
-    /**
30
-     * Method for registering new Data Migration Scripts
31
-     *
32
-     * @since 4.3.0
33
-     * @param string $addon_name EE_Addon class name that this set of data migration scripts belongs to
34
-     *                           If EE_Addon class is namespaced, then this needs to be the Fully Qualified Class Name
35
-     * @param array $setup_args {
36
-     *      @type string  $dms_paths an array of full server paths to folders that contain data migration scripts
37
-     *  }
38
-     * @throws EE_Error
39
-     * @return void
40
-     */
41
-    public static function register($addon_name = '', $setup_args = array())
42
-    {
43
-        //required fields MUST be present, so let's make sure they are.
44
-        if (empty($addon_name) || ! is_array($setup_args) || empty($setup_args['dms_paths'])) {
45
-            throw new EE_Error(
46
-                esc_html__(
47
-                    'In order to register Data Migration Scripts with EE_Register_Data_Migration_Scripts::register(), you must include the EE_Addon class name (used as a unique identifier for this set of data migration scripts), and an array containing the following keys: "dms_paths" (an array of full server paths to folders that contain data migration scripts)',
48
-                    'event_espresso'
49
-                )
50
-            );
51
-        }
52
-        //make sure we don't register twice
53
-        if (isset(self::$_settings[ $addon_name ])) {
54
-            return;
55
-        }
56
-        //make sure this was called in the right place!
57
-        if (! did_action('AHEE__EE_System__load_espresso_addons')
58
-            || did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
59
-        ) {
60
-            EE_Error::doing_it_wrong(
61
-                __METHOD__,
62
-                esc_html__(
63
-                    'An attempt to register Data Migration Scripts has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register Data Migration Scripts.',
64
-                    'event_espresso'
65
-                ),
66
-                '4.3.0'
67
-            );
68
-        }
69
-        //setup $_settings array from incoming values.
70
-        self::$_settings[ $addon_name ] = array(
71
-            'dms_paths' => (array) $setup_args['dms_paths']
72
-        );
73
-        // setup DMS
74
-        add_filter(
75
-            'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
76
-            array('EE_Register_Data_Migration_Scripts', 'add_data_migration_script_folders')
77
-        );
78
-    }
29
+	/**
30
+	 * Method for registering new Data Migration Scripts
31
+	 *
32
+	 * @since 4.3.0
33
+	 * @param string $addon_name EE_Addon class name that this set of data migration scripts belongs to
34
+	 *                           If EE_Addon class is namespaced, then this needs to be the Fully Qualified Class Name
35
+	 * @param array $setup_args {
36
+	 *      @type string  $dms_paths an array of full server paths to folders that contain data migration scripts
37
+	 *  }
38
+	 * @throws EE_Error
39
+	 * @return void
40
+	 */
41
+	public static function register($addon_name = '', $setup_args = array())
42
+	{
43
+		//required fields MUST be present, so let's make sure they are.
44
+		if (empty($addon_name) || ! is_array($setup_args) || empty($setup_args['dms_paths'])) {
45
+			throw new EE_Error(
46
+				esc_html__(
47
+					'In order to register Data Migration Scripts with EE_Register_Data_Migration_Scripts::register(), you must include the EE_Addon class name (used as a unique identifier for this set of data migration scripts), and an array containing the following keys: "dms_paths" (an array of full server paths to folders that contain data migration scripts)',
48
+					'event_espresso'
49
+				)
50
+			);
51
+		}
52
+		//make sure we don't register twice
53
+		if (isset(self::$_settings[ $addon_name ])) {
54
+			return;
55
+		}
56
+		//make sure this was called in the right place!
57
+		if (! did_action('AHEE__EE_System__load_espresso_addons')
58
+			|| did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
59
+		) {
60
+			EE_Error::doing_it_wrong(
61
+				__METHOD__,
62
+				esc_html__(
63
+					'An attempt to register Data Migration Scripts has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register Data Migration Scripts.',
64
+					'event_espresso'
65
+				),
66
+				'4.3.0'
67
+			);
68
+		}
69
+		//setup $_settings array from incoming values.
70
+		self::$_settings[ $addon_name ] = array(
71
+			'dms_paths' => (array) $setup_args['dms_paths']
72
+		);
73
+		// setup DMS
74
+		add_filter(
75
+			'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
76
+			array('EE_Register_Data_Migration_Scripts', 'add_data_migration_script_folders')
77
+		);
78
+	}
79 79
 
80 80
 
81
-    /**
82
-     * @param array $dms_paths
83
-     * @return array
84
-     */
85
-    public static function add_data_migration_script_folders($dms_paths = array())
86
-    {
87
-        foreach (self::$_settings as $addon_name => $settings) {
88
-            $wildcards = 0;
89
-            foreach ($settings['dms_paths'] as $dms_path) {
90
-                // since we are using the addon name for the array key
91
-                // we need to ensure that the key is unique,
92
-                // so if for some reason an addon has multiple dms paths,
93
-                // we append one or more * to the classname
94
-                // which will get stripped out later on
95
-                $dms_paths[ $addon_name . str_repeat('*', $wildcards) ] = $dms_path;
96
-                $wildcards++;
97
-            }
98
-        }
99
-        return $dms_paths;
100
-    }
81
+	/**
82
+	 * @param array $dms_paths
83
+	 * @return array
84
+	 */
85
+	public static function add_data_migration_script_folders($dms_paths = array())
86
+	{
87
+		foreach (self::$_settings as $addon_name => $settings) {
88
+			$wildcards = 0;
89
+			foreach ($settings['dms_paths'] as $dms_path) {
90
+				// since we are using the addon name for the array key
91
+				// we need to ensure that the key is unique,
92
+				// so if for some reason an addon has multiple dms paths,
93
+				// we append one or more * to the classname
94
+				// which will get stripped out later on
95
+				$dms_paths[ $addon_name . str_repeat('*', $wildcards) ] = $dms_path;
96
+				$wildcards++;
97
+			}
98
+		}
99
+		return $dms_paths;
100
+	}
101 101
 
102 102
 
103
-    /**
104
-     * This deregisters a set of Data Migration Scripts that were previously registered with a specific dms_id
105
-     *
106
-     * @since 4.3.0
107
-     * @param string $addon_name EE_Addon class name that this set of data migration scripts belongs to
108
-     * @return void
109
-     */
110
-    public static function deregister($addon_name = '')
111
-    {
112
-        unset(self::$_settings[ $addon_name ]);
113
-    }
103
+	/**
104
+	 * This deregisters a set of Data Migration Scripts that were previously registered with a specific dms_id
105
+	 *
106
+	 * @since 4.3.0
107
+	 * @param string $addon_name EE_Addon class name that this set of data migration scripts belongs to
108
+	 * @return void
109
+	 */
110
+	public static function deregister($addon_name = '')
111
+	{
112
+		unset(self::$_settings[ $addon_name ]);
113
+	}
114 114
 }
115 115
 // End of file EE_Register_Data_Migration_Scripts.lib.php
116 116
 // Location: /core/libraries/plugin_api/EE_Register_Data_Migration_Scripts.lib.php
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -50,11 +50,11 @@  discard block
 block discarded – undo
50 50
             );
51 51
         }
52 52
         //make sure we don't register twice
53
-        if (isset(self::$_settings[ $addon_name ])) {
53
+        if (isset(self::$_settings[$addon_name])) {
54 54
             return;
55 55
         }
56 56
         //make sure this was called in the right place!
57
-        if (! did_action('AHEE__EE_System__load_espresso_addons')
57
+        if ( ! did_action('AHEE__EE_System__load_espresso_addons')
58 58
             || did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
59 59
         ) {
60 60
             EE_Error::doing_it_wrong(
@@ -67,7 +67,7 @@  discard block
 block discarded – undo
67 67
             );
68 68
         }
69 69
         //setup $_settings array from incoming values.
70
-        self::$_settings[ $addon_name ] = array(
70
+        self::$_settings[$addon_name] = array(
71 71
             'dms_paths' => (array) $setup_args['dms_paths']
72 72
         );
73 73
         // setup DMS
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
                 // so if for some reason an addon has multiple dms paths,
93 93
                 // we append one or more * to the classname
94 94
                 // which will get stripped out later on
95
-                $dms_paths[ $addon_name . str_repeat('*', $wildcards) ] = $dms_path;
95
+                $dms_paths[$addon_name.str_repeat('*', $wildcards)] = $dms_path;
96 96
                 $wildcards++;
97 97
             }
98 98
         }
@@ -109,7 +109,7 @@  discard block
 block discarded – undo
109 109
      */
110 110
     public static function deregister($addon_name = '')
111 111
     {
112
-        unset(self::$_settings[ $addon_name ]);
112
+        unset(self::$_settings[$addon_name]);
113 113
     }
114 114
 }
115 115
 // End of file EE_Register_Data_Migration_Scripts.lib.php
Please login to merge, or discard this patch.
caffeinated/admin/new/pricing/espresso_events_Pricing_Hooks.class.php 3 patches
Doc Comments   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -1163,8 +1163,8 @@  discard block
 block discarded – undo
1163 1163
      * @param array       $datetime_tickets
1164 1164
      * @param array       $all_tickets
1165 1165
      * @param bool        $default
1166
-     * @param array       $all_datetimes
1167
-     * @return mixed
1166
+     * @param EE_Datetime[]       $all_datetimes
1167
+     * @return string
1168 1168
      * @throws DomainException
1169 1169
      * @throws EE_Error
1170 1170
      */
@@ -1275,7 +1275,7 @@  discard block
 block discarded – undo
1275 1275
      * @param array       $datetime_tickets
1276 1276
      * @param array       $all_tickets
1277 1277
      * @param bool        $default
1278
-     * @return mixed
1278
+     * @return string
1279 1279
      * @throws DomainException
1280 1280
      * @throws EE_Error
1281 1281
      */
@@ -1343,7 +1343,7 @@  discard block
 block discarded – undo
1343 1343
      * @param EE_Ticket   $ticket
1344 1344
      * @param array       $datetime_tickets
1345 1345
      * @param bool        $default
1346
-     * @return mixed
1346
+     * @return string
1347 1347
      * @throws DomainException
1348 1348
      * @throws EE_Error
1349 1349
      */
@@ -1413,7 +1413,7 @@  discard block
 block discarded – undo
1413 1413
      * @param bool          $default          Whether default row being generated or not.
1414 1414
      * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1415 1415
      *                                        (or empty in the case of defaults)
1416
-     * @return mixed
1416
+     * @return string
1417 1417
      * @throws InvalidArgumentException
1418 1418
      * @throws InvalidInterfaceException
1419 1419
      * @throws InvalidDataTypeException
@@ -1737,7 +1737,7 @@  discard block
 block discarded – undo
1737 1737
      * @param EE_Ticket|null $ticket
1738 1738
      * @param bool           $show_trash
1739 1739
      * @param bool           $show_create
1740
-     * @return mixed
1740
+     * @return string
1741 1741
      * @throws InvalidArgumentException
1742 1742
      * @throws InvalidInterfaceException
1743 1743
      * @throws InvalidDataTypeException
@@ -1840,7 +1840,7 @@  discard block
 block discarded – undo
1840 1840
      * @param EE_Price $price
1841 1841
      * @param bool     $default
1842 1842
      * @param bool     $disabled
1843
-     * @return mixed
1843
+     * @return string
1844 1844
      * @throws ReflectionException
1845 1845
      * @throws InvalidArgumentException
1846 1846
      * @throws InvalidInterfaceException
@@ -1873,7 +1873,7 @@  discard block
 block discarded – undo
1873 1873
      * @param int      $price_row
1874 1874
      * @param EE_Price $price
1875 1875
      * @param bool     $default
1876
-     * @return mixed
1876
+     * @return string
1877 1877
      * @throws DomainException
1878 1878
      * @throws EE_Error
1879 1879
      */
@@ -1910,7 +1910,7 @@  discard block
 block discarded – undo
1910 1910
      * @param EE_Price $price
1911 1911
      * @param bool     $default
1912 1912
      * @param bool     $disabled
1913
-     * @return mixed
1913
+     * @return string
1914 1914
      * @throws ReflectionException
1915 1915
      * @throws InvalidArgumentException
1916 1916
      * @throws InvalidInterfaceException
@@ -2012,7 +2012,7 @@  discard block
 block discarded – undo
2012 2012
      * @param EE_Ticket|null   $ticket
2013 2013
      * @param array            $ticket_datetimes
2014 2014
      * @param bool             $default
2015
-     * @return mixed
2015
+     * @return string
2016 2016
      * @throws DomainException
2017 2017
      * @throws EE_Error
2018 2018
      */
@@ -2065,9 +2065,9 @@  discard block
 block discarded – undo
2065 2065
 
2066 2066
 
2067 2067
     /**
2068
-     * @param array $all_datetimes
2068
+     * @param EE_Datetime[] $all_datetimes
2069 2069
      * @param array $all_tickets
2070
-     * @return mixed
2070
+     * @return string
2071 2071
      * @throws ReflectionException
2072 2072
      * @throws InvalidArgumentException
2073 2073
      * @throws InvalidInterfaceException
Please login to merge, or discard this patch.
Indentation   +2130 added lines, -2130 removed lines patch added patch discarded remove patch
@@ -19,2190 +19,2190 @@
 block discarded – undo
19 19
 class espresso_events_Pricing_Hooks extends EE_Admin_Hooks
20 20
 {
21 21
 
22
-    /**
23
-     * This property is just used to hold the status of whether an event is currently being
24
-     * created (true) or edited (false)
25
-     *
26
-     * @access protected
27
-     * @var bool
28
-     */
29
-    protected $_is_creating_event;
22
+	/**
23
+	 * This property is just used to hold the status of whether an event is currently being
24
+	 * created (true) or edited (false)
25
+	 *
26
+	 * @access protected
27
+	 * @var bool
28
+	 */
29
+	protected $_is_creating_event;
30 30
 
31
-    /**
32
-     * Used to contain the format strings for date and time that will be used for php date and
33
-     * time.
34
-     * Is set in the _set_hooks_properties() method.
35
-     *
36
-     * @var array
37
-     */
38
-    protected $_date_format_strings;
31
+	/**
32
+	 * Used to contain the format strings for date and time that will be used for php date and
33
+	 * time.
34
+	 * Is set in the _set_hooks_properties() method.
35
+	 *
36
+	 * @var array
37
+	 */
38
+	protected $_date_format_strings;
39 39
 
40
-    /**
41
-     * @var string $_date_time_format
42
-     */
43
-    protected $_date_time_format;
40
+	/**
41
+	 * @var string $_date_time_format
42
+	 */
43
+	protected $_date_time_format;
44 44
 
45 45
 
46
-    /**
47
-     * @throws InvalidArgumentException
48
-     * @throws InvalidInterfaceException
49
-     * @throws InvalidDataTypeException
50
-     */
51
-    protected function _set_hooks_properties()
52
-    {
53
-        $this->_name = 'pricing';
54
-        //capability check
55
-        if (! EE_Registry::instance()->CAP->current_user_can(
56
-            'ee_read_default_prices',
57
-            'advanced_ticket_datetime_metabox'
58
-        )) {
59
-            return;
60
-        }
61
-        $this->_setup_metaboxes();
62
-        $this->_set_date_time_formats();
63
-        $this->_validate_format_strings();
64
-        $this->_set_scripts_styles();
65
-        // commented out temporarily until logic is implemented in callback
66
-        // add_action(
67
-        //     'AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_Extend_Events_Admin_Page',
68
-        //     array($this, 'autosave_handling')
69
-        // );
70
-        add_filter(
71
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
72
-            array($this, 'caf_updates')
73
-        );
74
-    }
46
+	/**
47
+	 * @throws InvalidArgumentException
48
+	 * @throws InvalidInterfaceException
49
+	 * @throws InvalidDataTypeException
50
+	 */
51
+	protected function _set_hooks_properties()
52
+	{
53
+		$this->_name = 'pricing';
54
+		//capability check
55
+		if (! EE_Registry::instance()->CAP->current_user_can(
56
+			'ee_read_default_prices',
57
+			'advanced_ticket_datetime_metabox'
58
+		)) {
59
+			return;
60
+		}
61
+		$this->_setup_metaboxes();
62
+		$this->_set_date_time_formats();
63
+		$this->_validate_format_strings();
64
+		$this->_set_scripts_styles();
65
+		// commented out temporarily until logic is implemented in callback
66
+		// add_action(
67
+		//     'AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_Extend_Events_Admin_Page',
68
+		//     array($this, 'autosave_handling')
69
+		// );
70
+		add_filter(
71
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
72
+			array($this, 'caf_updates')
73
+		);
74
+	}
75 75
 
76 76
 
77
-    /**
78
-     * @return void
79
-     */
80
-    protected function _setup_metaboxes()
81
-    {
82
-        //if we were going to add our own metaboxes we'd use the below.
83
-        $this->_metaboxes        = array(
84
-            0 => array(
85
-                'page_route' => array('edit', 'create_new'),
86
-                'func'       => 'pricing_metabox',
87
-                'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
88
-                'priority'   => 'high',
89
-                'context'    => 'normal',
90
-            ),
91
-        );
92
-        $this->_remove_metaboxes = array(
93
-            0 => array(
94
-                'page_route' => array('edit', 'create_new'),
95
-                'id'         => 'espresso_event_editor_tickets',
96
-                'context'    => 'normal',
97
-            ),
98
-        );
99
-    }
77
+	/**
78
+	 * @return void
79
+	 */
80
+	protected function _setup_metaboxes()
81
+	{
82
+		//if we were going to add our own metaboxes we'd use the below.
83
+		$this->_metaboxes        = array(
84
+			0 => array(
85
+				'page_route' => array('edit', 'create_new'),
86
+				'func'       => 'pricing_metabox',
87
+				'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
88
+				'priority'   => 'high',
89
+				'context'    => 'normal',
90
+			),
91
+		);
92
+		$this->_remove_metaboxes = array(
93
+			0 => array(
94
+				'page_route' => array('edit', 'create_new'),
95
+				'id'         => 'espresso_event_editor_tickets',
96
+				'context'    => 'normal',
97
+			),
98
+		);
99
+	}
100 100
 
101 101
 
102
-    /**
103
-     * @return void
104
-     */
105
-    protected function _set_date_time_formats()
106
-    {
107
-        /**
108
-         * Format strings for date and time.  Defaults are existing behaviour from 4.1.
109
-         * Note, that if you return null as the value for 'date', and 'time' in the array, then
110
-         * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
111
-         *
112
-         * @since 4.6.7
113
-         * @var array  Expected an array returned with 'date' and 'time' keys.
114
-         */
115
-        $this->_date_format_strings = apply_filters(
116
-            'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
117
-            array(
118
-                'date' => 'Y-m-d',
119
-                'time' => 'h:i a',
120
-            )
121
-        );
122
-        //validate
123
-        $this->_date_format_strings['date'] = isset($this->_date_format_strings['date'])
124
-            ? $this->_date_format_strings['date']
125
-            : null;
126
-        $this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
127
-            ? $this->_date_format_strings['time']
128
-            : null;
129
-        $this->_date_time_format            = $this->_date_format_strings['date']
130
-                                              . ' '
131
-                                              . $this->_date_format_strings['time'];
132
-    }
102
+	/**
103
+	 * @return void
104
+	 */
105
+	protected function _set_date_time_formats()
106
+	{
107
+		/**
108
+		 * Format strings for date and time.  Defaults are existing behaviour from 4.1.
109
+		 * Note, that if you return null as the value for 'date', and 'time' in the array, then
110
+		 * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
111
+		 *
112
+		 * @since 4.6.7
113
+		 * @var array  Expected an array returned with 'date' and 'time' keys.
114
+		 */
115
+		$this->_date_format_strings = apply_filters(
116
+			'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
117
+			array(
118
+				'date' => 'Y-m-d',
119
+				'time' => 'h:i a',
120
+			)
121
+		);
122
+		//validate
123
+		$this->_date_format_strings['date'] = isset($this->_date_format_strings['date'])
124
+			? $this->_date_format_strings['date']
125
+			: null;
126
+		$this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
127
+			? $this->_date_format_strings['time']
128
+			: null;
129
+		$this->_date_time_format            = $this->_date_format_strings['date']
130
+											  . ' '
131
+											  . $this->_date_format_strings['time'];
132
+	}
133 133
 
134 134
 
135
-    /**
136
-     * @return void
137
-     */
138
-    protected function _validate_format_strings()
139
-    {
140
-        //validate format strings
141
-        $format_validation = EEH_DTT_Helper::validate_format_string(
142
-            $this->_date_time_format
143
-        );
144
-        if (is_array($format_validation)) {
145
-            $msg = '<p>';
146
-            $msg .= sprintf(
147
-                esc_html__(
148
-                    'The format "%s" was likely added via a filter and is invalid for the following reasons:',
149
-                    'event_espresso'
150
-                ),
151
-                $this->_date_time_format
152
-            );
153
-            $msg .= '</p><ul>';
154
-            foreach ($format_validation as $error) {
155
-                $msg .= '<li>' . $error . '</li>';
156
-            }
157
-            $msg .= '</ul><p>';
158
-            $msg .= sprintf(
159
-                esc_html__(
160
-                    '%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
161
-                    'event_espresso'
162
-                ),
163
-                '<span style="color:#D54E21;">',
164
-                '</span>'
165
-            );
166
-            $msg .= '</p>';
167
-            EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
168
-            $this->_date_format_strings = array(
169
-                'date' => 'Y-m-d',
170
-                'time' => 'h:i a',
171
-            );
172
-        }
173
-    }
135
+	/**
136
+	 * @return void
137
+	 */
138
+	protected function _validate_format_strings()
139
+	{
140
+		//validate format strings
141
+		$format_validation = EEH_DTT_Helper::validate_format_string(
142
+			$this->_date_time_format
143
+		);
144
+		if (is_array($format_validation)) {
145
+			$msg = '<p>';
146
+			$msg .= sprintf(
147
+				esc_html__(
148
+					'The format "%s" was likely added via a filter and is invalid for the following reasons:',
149
+					'event_espresso'
150
+				),
151
+				$this->_date_time_format
152
+			);
153
+			$msg .= '</p><ul>';
154
+			foreach ($format_validation as $error) {
155
+				$msg .= '<li>' . $error . '</li>';
156
+			}
157
+			$msg .= '</ul><p>';
158
+			$msg .= sprintf(
159
+				esc_html__(
160
+					'%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
161
+					'event_espresso'
162
+				),
163
+				'<span style="color:#D54E21;">',
164
+				'</span>'
165
+			);
166
+			$msg .= '</p>';
167
+			EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
168
+			$this->_date_format_strings = array(
169
+				'date' => 'Y-m-d',
170
+				'time' => 'h:i a',
171
+			);
172
+		}
173
+	}
174 174
 
175 175
 
176
-    /**
177
-     * @return void
178
-     */
179
-    protected function _set_scripts_styles()
180
-    {
181
-        $this->_scripts_styles = array(
182
-            'registers'   => array(
183
-                'ee-tickets-datetimes-css' => array(
184
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
185
-                    'type' => 'css',
186
-                ),
187
-                'ee-dtt-ticket-metabox'    => array(
188
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
189
-                    'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
190
-                ),
191
-            ),
192
-            'deregisters' => array(
193
-                'event-editor-css'       => array('type' => 'css'),
194
-                'event-datetime-metabox' => array('type' => 'js'),
195
-            ),
196
-            'enqueues'    => array(
197
-                'ee-tickets-datetimes-css' => array('edit', 'create_new'),
198
-                'ee-dtt-ticket-metabox'    => array('edit', 'create_new'),
199
-            ),
200
-            'localize'    => array(
201
-                'ee-dtt-ticket-metabox' => array(
202
-                    'DTT_TRASH_BLOCK'       => array(
203
-                        'main_warning'            => esc_html__(
204
-                            'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
205
-                            'event_espresso'
206
-                        ),
207
-                        'after_warning'           => esc_html__(
208
-                            'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
209
-                            'event_espresso'
210
-                        ),
211
-                        'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
212
-                                                     . esc_html__('Cancel', 'event_espresso') . '</button>',
213
-                        'close_button'            => '<button class="button-secondary ee-modal-cancel">'
214
-                                                     . esc_html__('Close', 'event_espresso') . '</button>',
215
-                        'single_warning_from_tkt' => esc_html__(
216
-                            'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
217
-                            'event_espresso'
218
-                        ),
219
-                        'single_warning_from_dtt' => esc_html__(
220
-                            'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
221
-                            'event_espresso'
222
-                        ),
223
-                        'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
224
-                                                     . esc_html__('Dismiss', 'event_espresso') . '</button>',
225
-                    ),
226
-                    'DTT_ERROR_MSG'         => array(
227
-                        'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
228
-                        'dismiss_button' => '<div class="save-cancel-button-container">'
229
-                                            . '<button class="button-secondary ee-modal-cancel">'
230
-                                            . esc_html__('Dismiss', 'event_espresso')
231
-                                            . '</button></div>',
232
-                    ),
233
-                    'DTT_OVERSELL_WARNING'  => array(
234
-                        'datetime_ticket' => esc_html__(
235
-                            'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
236
-                            'event_espresso'
237
-                        ),
238
-                        'ticket_datetime' => esc_html__(
239
-                            'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
240
-                            'event_espresso'
241
-                        ),
242
-                    ),
243
-                    'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
244
-                        $this->_date_format_strings['date'],
245
-                        $this->_date_format_strings['time']
246
-                    ),
247
-                    'DTT_START_OF_WEEK'     => array('dayValue' => (int) get_option('start_of_week')),
248
-                ),
249
-            ),
250
-        );
251
-    }
176
+	/**
177
+	 * @return void
178
+	 */
179
+	protected function _set_scripts_styles()
180
+	{
181
+		$this->_scripts_styles = array(
182
+			'registers'   => array(
183
+				'ee-tickets-datetimes-css' => array(
184
+					'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
185
+					'type' => 'css',
186
+				),
187
+				'ee-dtt-ticket-metabox'    => array(
188
+					'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
189
+					'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
190
+				),
191
+			),
192
+			'deregisters' => array(
193
+				'event-editor-css'       => array('type' => 'css'),
194
+				'event-datetime-metabox' => array('type' => 'js'),
195
+			),
196
+			'enqueues'    => array(
197
+				'ee-tickets-datetimes-css' => array('edit', 'create_new'),
198
+				'ee-dtt-ticket-metabox'    => array('edit', 'create_new'),
199
+			),
200
+			'localize'    => array(
201
+				'ee-dtt-ticket-metabox' => array(
202
+					'DTT_TRASH_BLOCK'       => array(
203
+						'main_warning'            => esc_html__(
204
+							'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
205
+							'event_espresso'
206
+						),
207
+						'after_warning'           => esc_html__(
208
+							'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
209
+							'event_espresso'
210
+						),
211
+						'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
212
+													 . esc_html__('Cancel', 'event_espresso') . '</button>',
213
+						'close_button'            => '<button class="button-secondary ee-modal-cancel">'
214
+													 . esc_html__('Close', 'event_espresso') . '</button>',
215
+						'single_warning_from_tkt' => esc_html__(
216
+							'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
217
+							'event_espresso'
218
+						),
219
+						'single_warning_from_dtt' => esc_html__(
220
+							'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
221
+							'event_espresso'
222
+						),
223
+						'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
224
+													 . esc_html__('Dismiss', 'event_espresso') . '</button>',
225
+					),
226
+					'DTT_ERROR_MSG'         => array(
227
+						'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
228
+						'dismiss_button' => '<div class="save-cancel-button-container">'
229
+											. '<button class="button-secondary ee-modal-cancel">'
230
+											. esc_html__('Dismiss', 'event_espresso')
231
+											. '</button></div>',
232
+					),
233
+					'DTT_OVERSELL_WARNING'  => array(
234
+						'datetime_ticket' => esc_html__(
235
+							'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
236
+							'event_espresso'
237
+						),
238
+						'ticket_datetime' => esc_html__(
239
+							'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
240
+							'event_espresso'
241
+						),
242
+					),
243
+					'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
244
+						$this->_date_format_strings['date'],
245
+						$this->_date_format_strings['time']
246
+					),
247
+					'DTT_START_OF_WEEK'     => array('dayValue' => (int) get_option('start_of_week')),
248
+				),
249
+			),
250
+		);
251
+	}
252 252
 
253 253
 
254
-    /**
255
-     * @param array $update_callbacks
256
-     * @return array
257
-     */
258
-    public function caf_updates(array $update_callbacks)
259
-    {
260
-        foreach ($update_callbacks as $key => $callback) {
261
-            if ($callback[1] === '_default_tickets_update') {
262
-                unset($update_callbacks[ $key ]);
263
-            }
264
-        }
265
-        $update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
266
-        return $update_callbacks;
267
-    }
254
+	/**
255
+	 * @param array $update_callbacks
256
+	 * @return array
257
+	 */
258
+	public function caf_updates(array $update_callbacks)
259
+	{
260
+		foreach ($update_callbacks as $key => $callback) {
261
+			if ($callback[1] === '_default_tickets_update') {
262
+				unset($update_callbacks[ $key ]);
263
+			}
264
+		}
265
+		$update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
266
+		return $update_callbacks;
267
+	}
268 268
 
269 269
 
270
-    /**
271
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
272
-     *
273
-     * @param  EE_Event $event The Event object we're attaching data to
274
-     * @param  array    $data  The request data from the form
275
-     * @throws ReflectionException
276
-     * @throws Exception
277
-     * @throws InvalidInterfaceException
278
-     * @throws InvalidDataTypeException
279
-     * @throws EE_Error
280
-     * @throws InvalidArgumentException
281
-     */
282
-    public function datetime_and_tickets_caf_update($event, $data)
283
-    {
284
-        //first we need to start with datetimes cause they are the "root" items attached to events.
285
-        $saved_datetimes = $this->_update_datetimes($event, $data);
286
-        //next tackle the tickets (and prices?)
287
-        $this->_update_tickets($event, $saved_datetimes, $data);
288
-    }
270
+	/**
271
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
272
+	 *
273
+	 * @param  EE_Event $event The Event object we're attaching data to
274
+	 * @param  array    $data  The request data from the form
275
+	 * @throws ReflectionException
276
+	 * @throws Exception
277
+	 * @throws InvalidInterfaceException
278
+	 * @throws InvalidDataTypeException
279
+	 * @throws EE_Error
280
+	 * @throws InvalidArgumentException
281
+	 */
282
+	public function datetime_and_tickets_caf_update($event, $data)
283
+	{
284
+		//first we need to start with datetimes cause they are the "root" items attached to events.
285
+		$saved_datetimes = $this->_update_datetimes($event, $data);
286
+		//next tackle the tickets (and prices?)
287
+		$this->_update_tickets($event, $saved_datetimes, $data);
288
+	}
289 289
 
290 290
 
291
-    /**
292
-     * update event_datetimes
293
-     *
294
-     * @param  EE_Event $event Event being updated
295
-     * @param  array    $data  the request data from the form
296
-     * @return EE_Datetime[]
297
-     * @throws Exception
298
-     * @throws ReflectionException
299
-     * @throws InvalidInterfaceException
300
-     * @throws InvalidDataTypeException
301
-     * @throws InvalidArgumentException
302
-     * @throws EE_Error
303
-     */
304
-    protected function _update_datetimes($event, $data)
305
-    {
306
-        $timezone       = isset($data['timezone_string']) ? $data['timezone_string'] : null;
307
-        $saved_dtt_ids  = array();
308
-        $saved_dtt_objs = array();
309
-        if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
310
-            throw new InvalidArgumentException(
311
-                esc_html__(
312
-                    'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
313
-                    'event_espresso'
314
-                )
315
-            );
316
-        }
317
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
318
-            //trim all values to ensure any excess whitespace is removed.
319
-            $datetime_data                = array_map(
320
-                function ($datetime_data)
321
-                {
322
-                    return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
323
-                },
324
-                $datetime_data
325
-            );
326
-            $datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
327
-                                            && ! empty($datetime_data['DTT_EVT_end'])
328
-                ? $datetime_data['DTT_EVT_end']
329
-                : $datetime_data['DTT_EVT_start'];
330
-            $datetime_values              = array(
331
-                'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
332
-                    ? $datetime_data['DTT_ID']
333
-                    : null,
334
-                'DTT_name'        => ! empty($datetime_data['DTT_name'])
335
-                    ? $datetime_data['DTT_name']
336
-                    : '',
337
-                'DTT_description' => ! empty($datetime_data['DTT_description'])
338
-                    ? $datetime_data['DTT_description']
339
-                    : '',
340
-                'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
341
-                'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
342
-                'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
343
-                    ? EE_INF
344
-                    : $datetime_data['DTT_reg_limit'],
345
-                'DTT_order'       => ! isset($datetime_data['DTT_order'])
346
-                    ? $row
347
-                    : $datetime_data['DTT_order'],
348
-            );
349
-            // if we have an id then let's get existing object first and then set the new values.
350
-            // Otherwise we instantiate a new object for save.
351
-            if (! empty($datetime_data['DTT_ID'])) {
352
-                $datetime = EE_Registry::instance()
353
-                                       ->load_model('Datetime', array($timezone))
354
-                                       ->get_one_by_ID($datetime_data['DTT_ID']);
355
-                //set date and time format according to what is set in this class.
356
-                $datetime->set_date_format($this->_date_format_strings['date']);
357
-                $datetime->set_time_format($this->_date_format_strings['time']);
358
-                foreach ($datetime_values as $field => $value) {
359
-                    $datetime->set($field, $value);
360
-                }
361
-                // make sure the $dtt_id here is saved just in case
362
-                // after the add_relation_to() the autosave replaces it.
363
-                // We need to do this so we dont' TRASH the parent DTT.
364
-                // (save the ID for both key and value to avoid duplications)
365
-                $saved_dtt_ids[ $datetime->ID() ] = $datetime->ID();
366
-            } else {
367
-                $datetime = EE_Registry::instance()->load_class(
368
-                    'Datetime',
369
-                    array(
370
-                        $datetime_values,
371
-                        $timezone,
372
-                        array($this->_date_format_strings['date'], $this->_date_format_strings['time']),
373
-                    ),
374
-                    false,
375
-                    false
376
-                );
377
-                foreach ($datetime_values as $field => $value) {
378
-                    $datetime->set($field, $value);
379
-                }
380
-            }
381
-            $datetime->save();
382
-            $datetime = $event->_add_relation_to($datetime, 'Datetime');
383
-            // before going any further make sure our dates are setup correctly
384
-            // so that the end date is always equal or greater than the start date.
385
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
386
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
387
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
388
-                $datetime->save();
389
-            }
390
-            //	now we have to make sure we add the new DTT_ID to the $saved_dtt_ids array
391
-            // because it is possible there was a new one created for the autosave.
392
-            // (save the ID for both key and value to avoid duplications)
393
-            $DTT_ID                   = $datetime->ID();
394
-            $saved_dtt_ids[ $DTT_ID ] = $DTT_ID;
395
-            $saved_dtt_objs[ $row ]   = $datetime;
396
-            //todo if ANY of these updates fail then we want the appropriate global error message.
397
-        }
398
-        $event->save();
399
-        // now we need to REMOVE any datetimes that got deleted.
400
-        // Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
401
-        // So its safe to permanently delete at this point.
402
-        $old_datetimes = explode(',', $data['datetime_IDs']);
403
-        $old_datetimes = $old_datetimes[0] === '' ? array() : $old_datetimes;
404
-        if (is_array($old_datetimes)) {
405
-            $datetimes_to_delete = array_diff($old_datetimes, $saved_dtt_ids);
406
-            foreach ($datetimes_to_delete as $id) {
407
-                $id = absint($id);
408
-                if (empty($id)) {
409
-                    continue;
410
-                }
411
-                $dtt_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
412
-                //remove tkt relationships.
413
-                $related_tickets = $dtt_to_remove->get_many_related('Ticket');
414
-                foreach ($related_tickets as $tkt) {
415
-                    $dtt_to_remove->_remove_relation_to($tkt, 'Ticket');
416
-                }
417
-                $event->_remove_relation_to($id, 'Datetime');
418
-                $dtt_to_remove->refresh_cache_of_related_objects();
419
-            }
420
-        }
421
-        return $saved_dtt_objs;
422
-    }
291
+	/**
292
+	 * update event_datetimes
293
+	 *
294
+	 * @param  EE_Event $event Event being updated
295
+	 * @param  array    $data  the request data from the form
296
+	 * @return EE_Datetime[]
297
+	 * @throws Exception
298
+	 * @throws ReflectionException
299
+	 * @throws InvalidInterfaceException
300
+	 * @throws InvalidDataTypeException
301
+	 * @throws InvalidArgumentException
302
+	 * @throws EE_Error
303
+	 */
304
+	protected function _update_datetimes($event, $data)
305
+	{
306
+		$timezone       = isset($data['timezone_string']) ? $data['timezone_string'] : null;
307
+		$saved_dtt_ids  = array();
308
+		$saved_dtt_objs = array();
309
+		if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
310
+			throw new InvalidArgumentException(
311
+				esc_html__(
312
+					'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
313
+					'event_espresso'
314
+				)
315
+			);
316
+		}
317
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
318
+			//trim all values to ensure any excess whitespace is removed.
319
+			$datetime_data                = array_map(
320
+				function ($datetime_data)
321
+				{
322
+					return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
323
+				},
324
+				$datetime_data
325
+			);
326
+			$datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
327
+											&& ! empty($datetime_data['DTT_EVT_end'])
328
+				? $datetime_data['DTT_EVT_end']
329
+				: $datetime_data['DTT_EVT_start'];
330
+			$datetime_values              = array(
331
+				'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
332
+					? $datetime_data['DTT_ID']
333
+					: null,
334
+				'DTT_name'        => ! empty($datetime_data['DTT_name'])
335
+					? $datetime_data['DTT_name']
336
+					: '',
337
+				'DTT_description' => ! empty($datetime_data['DTT_description'])
338
+					? $datetime_data['DTT_description']
339
+					: '',
340
+				'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
341
+				'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
342
+				'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
343
+					? EE_INF
344
+					: $datetime_data['DTT_reg_limit'],
345
+				'DTT_order'       => ! isset($datetime_data['DTT_order'])
346
+					? $row
347
+					: $datetime_data['DTT_order'],
348
+			);
349
+			// if we have an id then let's get existing object first and then set the new values.
350
+			// Otherwise we instantiate a new object for save.
351
+			if (! empty($datetime_data['DTT_ID'])) {
352
+				$datetime = EE_Registry::instance()
353
+									   ->load_model('Datetime', array($timezone))
354
+									   ->get_one_by_ID($datetime_data['DTT_ID']);
355
+				//set date and time format according to what is set in this class.
356
+				$datetime->set_date_format($this->_date_format_strings['date']);
357
+				$datetime->set_time_format($this->_date_format_strings['time']);
358
+				foreach ($datetime_values as $field => $value) {
359
+					$datetime->set($field, $value);
360
+				}
361
+				// make sure the $dtt_id here is saved just in case
362
+				// after the add_relation_to() the autosave replaces it.
363
+				// We need to do this so we dont' TRASH the parent DTT.
364
+				// (save the ID for both key and value to avoid duplications)
365
+				$saved_dtt_ids[ $datetime->ID() ] = $datetime->ID();
366
+			} else {
367
+				$datetime = EE_Registry::instance()->load_class(
368
+					'Datetime',
369
+					array(
370
+						$datetime_values,
371
+						$timezone,
372
+						array($this->_date_format_strings['date'], $this->_date_format_strings['time']),
373
+					),
374
+					false,
375
+					false
376
+				);
377
+				foreach ($datetime_values as $field => $value) {
378
+					$datetime->set($field, $value);
379
+				}
380
+			}
381
+			$datetime->save();
382
+			$datetime = $event->_add_relation_to($datetime, 'Datetime');
383
+			// before going any further make sure our dates are setup correctly
384
+			// so that the end date is always equal or greater than the start date.
385
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
386
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
387
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
388
+				$datetime->save();
389
+			}
390
+			//	now we have to make sure we add the new DTT_ID to the $saved_dtt_ids array
391
+			// because it is possible there was a new one created for the autosave.
392
+			// (save the ID for both key and value to avoid duplications)
393
+			$DTT_ID                   = $datetime->ID();
394
+			$saved_dtt_ids[ $DTT_ID ] = $DTT_ID;
395
+			$saved_dtt_objs[ $row ]   = $datetime;
396
+			//todo if ANY of these updates fail then we want the appropriate global error message.
397
+		}
398
+		$event->save();
399
+		// now we need to REMOVE any datetimes that got deleted.
400
+		// Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
401
+		// So its safe to permanently delete at this point.
402
+		$old_datetimes = explode(',', $data['datetime_IDs']);
403
+		$old_datetimes = $old_datetimes[0] === '' ? array() : $old_datetimes;
404
+		if (is_array($old_datetimes)) {
405
+			$datetimes_to_delete = array_diff($old_datetimes, $saved_dtt_ids);
406
+			foreach ($datetimes_to_delete as $id) {
407
+				$id = absint($id);
408
+				if (empty($id)) {
409
+					continue;
410
+				}
411
+				$dtt_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
412
+				//remove tkt relationships.
413
+				$related_tickets = $dtt_to_remove->get_many_related('Ticket');
414
+				foreach ($related_tickets as $tkt) {
415
+					$dtt_to_remove->_remove_relation_to($tkt, 'Ticket');
416
+				}
417
+				$event->_remove_relation_to($id, 'Datetime');
418
+				$dtt_to_remove->refresh_cache_of_related_objects();
419
+			}
420
+		}
421
+		return $saved_dtt_objs;
422
+	}
423 423
 
424 424
 
425
-    /**
426
-     * update tickets
427
-     *
428
-     * @param  EE_Event      $event           Event object being updated
429
-     * @param  EE_Datetime[] $saved_datetimes an array of datetime ids being updated
430
-     * @param  array         $data            incoming request data
431
-     * @return EE_Ticket[]
432
-     * @throws Exception
433
-     * @throws ReflectionException
434
-     * @throws InvalidInterfaceException
435
-     * @throws InvalidDataTypeException
436
-     * @throws InvalidArgumentException
437
-     * @throws EE_Error
438
-     */
439
-    protected function _update_tickets($event, $saved_datetimes, $data)
440
-    {
441
-        $new_tkt     = null;
442
-        $new_default = null;
443
-        //stripslashes because WP filtered the $_POST ($data) array to add slashes
444
-        $data          = stripslashes_deep($data);
445
-        $timezone      = isset($data['timezone_string']) ? $data['timezone_string'] : null;
446
-        $saved_tickets = $datetimes_on_existing = array();
447
-        $old_tickets   = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
448
-        if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
449
-            throw new InvalidArgumentException(
450
-                esc_html__(
451
-                    'The "edit_tickets" array is invalid therefore the event can not be updated.',
452
-                    'event_espresso'
453
-                )
454
-            );
455
-        }
456
-        foreach ($data['edit_tickets'] as $row => $tkt) {
457
-            $update_prices = $create_new_TKT = false;
458
-            // figure out what datetimes were added to the ticket
459
-            // and what datetimes were removed from the ticket in the session.
460
-            $starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
461
-            $tkt_dtt_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
462
-            $datetimes_added       = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
463
-            $datetimes_removed     = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
464
-            // trim inputs to ensure any excess whitespace is removed.
465
-            $tkt = array_map(
466
-                function ($ticket_data)
467
-                {
468
-                    return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
469
-                },
470
-                $tkt
471
-            );
472
-            // note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
473
-            // because we're doing calculations prior to using the models.
474
-            // note incoming ['TKT_price'] value is already in standard notation (via js).
475
-            $ticket_price = isset($tkt['TKT_price'])
476
-                ? round((float) $tkt['TKT_price'], 3)
477
-                : 0;
478
-            //note incoming base price needs converted from localized value.
479
-            $base_price = isset($tkt['TKT_base_price'])
480
-                ? EEH_Money::convert_to_float_from_localized_money($tkt['TKT_base_price'])
481
-                : 0;
482
-            //if ticket price == 0 and $base_price != 0 then ticket price == base_price
483
-            $ticket_price  = $ticket_price === 0 && $base_price !== 0
484
-                ? $base_price
485
-                : $ticket_price;
486
-            $base_price_id = isset($tkt['TKT_base_price_ID'])
487
-                ? $tkt['TKT_base_price_ID']
488
-                : 0;
489
-            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
490
-                ? $data['edit_prices'][ $row ]
491
-                : array();
492
-            $now           = null;
493
-            if (empty($tkt['TKT_start_date'])) {
494
-                //lets' use now in the set timezone.
495
-                $now                   = new DateTime('now', new DateTimeZone($event->get_timezone()));
496
-                $tkt['TKT_start_date'] = $now->format($this->_date_time_format);
497
-            }
498
-            if (empty($tkt['TKT_end_date'])) {
499
-                /**
500
-                 * set the TKT_end_date to the first datetime attached to the ticket.
501
-                 */
502
-                $first_dtt           = $saved_datetimes[ reset($tkt_dtt_rows) ];
503
-                $tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
504
-            }
505
-            $TKT_values = array(
506
-                'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
507
-                'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
508
-                'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
509
-                'TKT_description' => ! empty($tkt['TKT_description'])
510
-                                     && $tkt['TKT_description'] !== esc_html__(
511
-                    'You can modify this description',
512
-                    'event_espresso'
513
-                )
514
-                    ? $tkt['TKT_description']
515
-                    : '',
516
-                'TKT_start_date'  => $tkt['TKT_start_date'],
517
-                'TKT_end_date'    => $tkt['TKT_end_date'],
518
-                'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === ''
519
-                    ? EE_INF
520
-                    : $tkt['TKT_qty'],
521
-                'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === ''
522
-                    ? EE_INF
523
-                    : $tkt['TKT_uses'],
524
-                'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
525
-                'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
526
-                'TKT_row'         => $row,
527
-                'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : 0,
528
-                'TKT_taxable'     => ! empty($tkt['TKT_taxable']) ? 1 : 0,
529
-                'TKT_required'    => ! empty($tkt['TKT_required']) ? 1 : 0,
530
-                'TKT_price'       => $ticket_price,
531
-            );
532
-            // if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
533
-            // which means in turn that the prices will become new prices as well.
534
-            if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
535
-                $TKT_values['TKT_ID']         = 0;
536
-                $TKT_values['TKT_is_default'] = 0;
537
-                $update_prices                = true;
538
-            }
539
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
540
-            // we actually do our saves ahead of doing any add_relations to
541
-            // because its entirely possible that this ticket wasn't removed or added to any datetime in the session
542
-            // but DID have it's items modified.
543
-            // keep in mind that if the TKT has been sold (and we have changed pricing information),
544
-            // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
545
-            if (absint($TKT_values['TKT_ID'])) {
546
-                $ticket = EE_Registry::instance()
547
-                                     ->load_model('Ticket', array($timezone))
548
-                                     ->get_one_by_ID($tkt['TKT_ID']);
549
-                if ($ticket instanceof EE_Ticket) {
550
-                    $ticket = $this->_update_ticket_datetimes(
551
-                        $ticket,
552
-                        $saved_datetimes,
553
-                        $datetimes_added,
554
-                        $datetimes_removed
555
-                    );
556
-                    // are there any registrations using this ticket ?
557
-                    $tickets_sold = $ticket->count_related(
558
-                        'Registration',
559
-                        array(
560
-                            array(
561
-                                'STS_ID' => array('NOT IN', array(EEM_Registration::status_id_incomplete)),
562
-                            ),
563
-                        )
564
-                    );
565
-                    //set ticket formats
566
-                    $ticket->set_date_format($this->_date_format_strings['date']);
567
-                    $ticket->set_time_format($this->_date_format_strings['time']);
568
-                    // let's just check the total price for the existing ticket
569
-                    // and determine if it matches the new total price.
570
-                    // if they are different then we create a new ticket (if tickets sold)
571
-                    // if they aren't different then we go ahead and modify existing ticket.
572
-                    $create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
573
-                    //set new values
574
-                    foreach ($TKT_values as $field => $value) {
575
-                        if ($field === 'TKT_qty') {
576
-                            $ticket->set_qty($value);
577
-                        } else {
578
-                            $ticket->set($field, $value);
579
-                        }
580
-                    }
581
-                    // if $create_new_TKT is false then we can safely update the existing ticket.
582
-                    // Otherwise we have to create a new ticket.
583
-                    if ($create_new_TKT) {
584
-                        $new_tkt = $this->_duplicate_ticket(
585
-                            $ticket,
586
-                            $price_rows,
587
-                            $ticket_price,
588
-                            $base_price,
589
-                            $base_price_id
590
-                        );
591
-                    }
592
-                }
593
-            } else {
594
-                // no TKT_id so a new TKT
595
-                $ticket = EE_Ticket::new_instance(
596
-                    $TKT_values,
597
-                    $timezone,
598
-                    array($this->_date_format_strings['date'], $this->_date_format_strings['time'])
599
-                );
600
-                if ($ticket instanceof EE_Ticket) {
601
-                    // make sure ticket has an ID of setting relations won't work
602
-                    $ticket->save();
603
-                    $ticket        = $this->_update_ticket_datetimes(
604
-                        $ticket,
605
-                        $saved_datetimes,
606
-                        $datetimes_added,
607
-                        $datetimes_removed
608
-                    );
609
-                    $update_prices = true;
610
-                }
611
-            }
612
-            //make sure any current values have been saved.
613
-            //$ticket->save();
614
-            // before going any further make sure our dates are setup correctly
615
-            // so that the end date is always equal or greater than the start date.
616
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
617
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
618
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
619
-            }
620
-            //let's make sure the base price is handled
621
-            $ticket = ! $create_new_TKT
622
-                ? $this->_add_prices_to_ticket(
623
-                    array(),
624
-                    $ticket,
625
-                    $update_prices,
626
-                    $base_price,
627
-                    $base_price_id
628
-                )
629
-                : $ticket;
630
-            //add/update price_modifiers
631
-            $ticket = ! $create_new_TKT
632
-                ? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices)
633
-                : $ticket;
634
-            //need to make sue that the TKT_price is accurate after saving the prices.
635
-            $ticket->ensure_TKT_Price_correct();
636
-            //handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
637
-            if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
638
-                $update_prices = true;
639
-                $new_default   = clone $ticket;
640
-                $new_default->set('TKT_ID', 0);
641
-                $new_default->set('TKT_is_default', 1);
642
-                $new_default->set('TKT_row', 1);
643
-                $new_default->set('TKT_price', $ticket_price);
644
-                // remove any dtt relations cause we DON'T want dtt relations attached
645
-                // (note this is just removing the cached relations in the object)
646
-                $new_default->_remove_relations('Datetime');
647
-                //todo we need to add the current attached prices as new prices to the new default ticket.
648
-                $new_default = $this->_add_prices_to_ticket(
649
-                    $price_rows,
650
-                    $new_default,
651
-                    $update_prices
652
-                );
653
-                //don't forget the base price!
654
-                $new_default = $this->_add_prices_to_ticket(
655
-                    array(),
656
-                    $new_default,
657
-                    $update_prices,
658
-                    $base_price,
659
-                    $base_price_id
660
-                );
661
-                $new_default->save();
662
-                do_action(
663
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
664
-                    $new_default,
665
-                    $row,
666
-                    $ticket,
667
-                    $data
668
-                );
669
-            }
670
-            // DO ALL dtt relationships for both current tickets and any archived tickets
671
-            // for the given dtt that are related to the current ticket.
672
-            // TODO... not sure exactly how we're going to do this considering we don't know
673
-            // what current ticket the archived tickets are related to
674
-            // (and TKT_parent is used for autosaves so that's not a field we can reliably use).
675
-            //let's assign any tickets that have been setup to the saved_tickets tracker
676
-            //save existing TKT
677
-            $ticket->save();
678
-            if ($create_new_TKT && $new_tkt instanceof EE_Ticket) {
679
-                //save new TKT
680
-                $new_tkt->save();
681
-                //add new ticket to array
682
-                $saved_tickets[ $new_tkt->ID() ] = $new_tkt;
683
-                do_action(
684
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
685
-                    $new_tkt,
686
-                    $row,
687
-                    $tkt,
688
-                    $data
689
-                );
690
-            } else {
691
-                //add tkt to saved tkts
692
-                $saved_tickets[ $ticket->ID() ] = $ticket;
693
-                do_action(
694
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
695
-                    $ticket,
696
-                    $row,
697
-                    $tkt,
698
-                    $data
699
-                );
700
-            }
701
-        }
702
-        // now we need to handle tickets actually "deleted permanently".
703
-        // There are cases where we'd want this to happen
704
-        // (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
705
-        // Or a draft event was saved and in the process of editing a ticket is trashed.
706
-        // No sense in keeping all the related data in the db!
707
-        $old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? array() : $old_tickets;
708
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
709
-        foreach ($tickets_removed as $id) {
710
-            $id = absint($id);
711
-            //get the ticket for this id
712
-            $tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
713
-            //if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
714
-            if ($tkt_to_remove->get('TKT_is_default')) {
715
-                continue;
716
-            }
717
-            // if this tkt has any registrations attached so then we just ARCHIVE
718
-            // because we don't actually permanently delete these tickets.
719
-            if ($tkt_to_remove->count_related('Registration') > 0) {
720
-                $tkt_to_remove->delete();
721
-                continue;
722
-            }
723
-            // need to get all the related datetimes on this ticket and remove from every single one of them
724
-            // (remember this process can ONLY kick off if there are NO tkts_sold)
725
-            $datetimes = $tkt_to_remove->get_many_related('Datetime');
726
-            foreach ($datetimes as $datetime) {
727
-                $tkt_to_remove->_remove_relation_to($datetime, 'Datetime');
728
-            }
729
-            // need to do the same for prices (except these prices can also be deleted because again,
730
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
731
-            $tkt_to_remove->delete_related_permanently('Price');
732
-            do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $tkt_to_remove);
733
-            // finally let's delete this ticket
734
-            // (which should not be blocked at this point b/c we've removed all our relationships)
735
-            $tkt_to_remove->delete_permanently();
736
-        }
737
-        return $saved_tickets;
738
-    }
425
+	/**
426
+	 * update tickets
427
+	 *
428
+	 * @param  EE_Event      $event           Event object being updated
429
+	 * @param  EE_Datetime[] $saved_datetimes an array of datetime ids being updated
430
+	 * @param  array         $data            incoming request data
431
+	 * @return EE_Ticket[]
432
+	 * @throws Exception
433
+	 * @throws ReflectionException
434
+	 * @throws InvalidInterfaceException
435
+	 * @throws InvalidDataTypeException
436
+	 * @throws InvalidArgumentException
437
+	 * @throws EE_Error
438
+	 */
439
+	protected function _update_tickets($event, $saved_datetimes, $data)
440
+	{
441
+		$new_tkt     = null;
442
+		$new_default = null;
443
+		//stripslashes because WP filtered the $_POST ($data) array to add slashes
444
+		$data          = stripslashes_deep($data);
445
+		$timezone      = isset($data['timezone_string']) ? $data['timezone_string'] : null;
446
+		$saved_tickets = $datetimes_on_existing = array();
447
+		$old_tickets   = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
448
+		if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
449
+			throw new InvalidArgumentException(
450
+				esc_html__(
451
+					'The "edit_tickets" array is invalid therefore the event can not be updated.',
452
+					'event_espresso'
453
+				)
454
+			);
455
+		}
456
+		foreach ($data['edit_tickets'] as $row => $tkt) {
457
+			$update_prices = $create_new_TKT = false;
458
+			// figure out what datetimes were added to the ticket
459
+			// and what datetimes were removed from the ticket in the session.
460
+			$starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
461
+			$tkt_dtt_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
462
+			$datetimes_added       = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
463
+			$datetimes_removed     = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
464
+			// trim inputs to ensure any excess whitespace is removed.
465
+			$tkt = array_map(
466
+				function ($ticket_data)
467
+				{
468
+					return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
469
+				},
470
+				$tkt
471
+			);
472
+			// note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
473
+			// because we're doing calculations prior to using the models.
474
+			// note incoming ['TKT_price'] value is already in standard notation (via js).
475
+			$ticket_price = isset($tkt['TKT_price'])
476
+				? round((float) $tkt['TKT_price'], 3)
477
+				: 0;
478
+			//note incoming base price needs converted from localized value.
479
+			$base_price = isset($tkt['TKT_base_price'])
480
+				? EEH_Money::convert_to_float_from_localized_money($tkt['TKT_base_price'])
481
+				: 0;
482
+			//if ticket price == 0 and $base_price != 0 then ticket price == base_price
483
+			$ticket_price  = $ticket_price === 0 && $base_price !== 0
484
+				? $base_price
485
+				: $ticket_price;
486
+			$base_price_id = isset($tkt['TKT_base_price_ID'])
487
+				? $tkt['TKT_base_price_ID']
488
+				: 0;
489
+			$price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
490
+				? $data['edit_prices'][ $row ]
491
+				: array();
492
+			$now           = null;
493
+			if (empty($tkt['TKT_start_date'])) {
494
+				//lets' use now in the set timezone.
495
+				$now                   = new DateTime('now', new DateTimeZone($event->get_timezone()));
496
+				$tkt['TKT_start_date'] = $now->format($this->_date_time_format);
497
+			}
498
+			if (empty($tkt['TKT_end_date'])) {
499
+				/**
500
+				 * set the TKT_end_date to the first datetime attached to the ticket.
501
+				 */
502
+				$first_dtt           = $saved_datetimes[ reset($tkt_dtt_rows) ];
503
+				$tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
504
+			}
505
+			$TKT_values = array(
506
+				'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
507
+				'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
508
+				'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
509
+				'TKT_description' => ! empty($tkt['TKT_description'])
510
+									 && $tkt['TKT_description'] !== esc_html__(
511
+					'You can modify this description',
512
+					'event_espresso'
513
+				)
514
+					? $tkt['TKT_description']
515
+					: '',
516
+				'TKT_start_date'  => $tkt['TKT_start_date'],
517
+				'TKT_end_date'    => $tkt['TKT_end_date'],
518
+				'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === ''
519
+					? EE_INF
520
+					: $tkt['TKT_qty'],
521
+				'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === ''
522
+					? EE_INF
523
+					: $tkt['TKT_uses'],
524
+				'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
525
+				'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
526
+				'TKT_row'         => $row,
527
+				'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : 0,
528
+				'TKT_taxable'     => ! empty($tkt['TKT_taxable']) ? 1 : 0,
529
+				'TKT_required'    => ! empty($tkt['TKT_required']) ? 1 : 0,
530
+				'TKT_price'       => $ticket_price,
531
+			);
532
+			// if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
533
+			// which means in turn that the prices will become new prices as well.
534
+			if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
535
+				$TKT_values['TKT_ID']         = 0;
536
+				$TKT_values['TKT_is_default'] = 0;
537
+				$update_prices                = true;
538
+			}
539
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
540
+			// we actually do our saves ahead of doing any add_relations to
541
+			// because its entirely possible that this ticket wasn't removed or added to any datetime in the session
542
+			// but DID have it's items modified.
543
+			// keep in mind that if the TKT has been sold (and we have changed pricing information),
544
+			// then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
545
+			if (absint($TKT_values['TKT_ID'])) {
546
+				$ticket = EE_Registry::instance()
547
+									 ->load_model('Ticket', array($timezone))
548
+									 ->get_one_by_ID($tkt['TKT_ID']);
549
+				if ($ticket instanceof EE_Ticket) {
550
+					$ticket = $this->_update_ticket_datetimes(
551
+						$ticket,
552
+						$saved_datetimes,
553
+						$datetimes_added,
554
+						$datetimes_removed
555
+					);
556
+					// are there any registrations using this ticket ?
557
+					$tickets_sold = $ticket->count_related(
558
+						'Registration',
559
+						array(
560
+							array(
561
+								'STS_ID' => array('NOT IN', array(EEM_Registration::status_id_incomplete)),
562
+							),
563
+						)
564
+					);
565
+					//set ticket formats
566
+					$ticket->set_date_format($this->_date_format_strings['date']);
567
+					$ticket->set_time_format($this->_date_format_strings['time']);
568
+					// let's just check the total price for the existing ticket
569
+					// and determine if it matches the new total price.
570
+					// if they are different then we create a new ticket (if tickets sold)
571
+					// if they aren't different then we go ahead and modify existing ticket.
572
+					$create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
573
+					//set new values
574
+					foreach ($TKT_values as $field => $value) {
575
+						if ($field === 'TKT_qty') {
576
+							$ticket->set_qty($value);
577
+						} else {
578
+							$ticket->set($field, $value);
579
+						}
580
+					}
581
+					// if $create_new_TKT is false then we can safely update the existing ticket.
582
+					// Otherwise we have to create a new ticket.
583
+					if ($create_new_TKT) {
584
+						$new_tkt = $this->_duplicate_ticket(
585
+							$ticket,
586
+							$price_rows,
587
+							$ticket_price,
588
+							$base_price,
589
+							$base_price_id
590
+						);
591
+					}
592
+				}
593
+			} else {
594
+				// no TKT_id so a new TKT
595
+				$ticket = EE_Ticket::new_instance(
596
+					$TKT_values,
597
+					$timezone,
598
+					array($this->_date_format_strings['date'], $this->_date_format_strings['time'])
599
+				);
600
+				if ($ticket instanceof EE_Ticket) {
601
+					// make sure ticket has an ID of setting relations won't work
602
+					$ticket->save();
603
+					$ticket        = $this->_update_ticket_datetimes(
604
+						$ticket,
605
+						$saved_datetimes,
606
+						$datetimes_added,
607
+						$datetimes_removed
608
+					);
609
+					$update_prices = true;
610
+				}
611
+			}
612
+			//make sure any current values have been saved.
613
+			//$ticket->save();
614
+			// before going any further make sure our dates are setup correctly
615
+			// so that the end date is always equal or greater than the start date.
616
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
617
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
618
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
619
+			}
620
+			//let's make sure the base price is handled
621
+			$ticket = ! $create_new_TKT
622
+				? $this->_add_prices_to_ticket(
623
+					array(),
624
+					$ticket,
625
+					$update_prices,
626
+					$base_price,
627
+					$base_price_id
628
+				)
629
+				: $ticket;
630
+			//add/update price_modifiers
631
+			$ticket = ! $create_new_TKT
632
+				? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices)
633
+				: $ticket;
634
+			//need to make sue that the TKT_price is accurate after saving the prices.
635
+			$ticket->ensure_TKT_Price_correct();
636
+			//handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
637
+			if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
638
+				$update_prices = true;
639
+				$new_default   = clone $ticket;
640
+				$new_default->set('TKT_ID', 0);
641
+				$new_default->set('TKT_is_default', 1);
642
+				$new_default->set('TKT_row', 1);
643
+				$new_default->set('TKT_price', $ticket_price);
644
+				// remove any dtt relations cause we DON'T want dtt relations attached
645
+				// (note this is just removing the cached relations in the object)
646
+				$new_default->_remove_relations('Datetime');
647
+				//todo we need to add the current attached prices as new prices to the new default ticket.
648
+				$new_default = $this->_add_prices_to_ticket(
649
+					$price_rows,
650
+					$new_default,
651
+					$update_prices
652
+				);
653
+				//don't forget the base price!
654
+				$new_default = $this->_add_prices_to_ticket(
655
+					array(),
656
+					$new_default,
657
+					$update_prices,
658
+					$base_price,
659
+					$base_price_id
660
+				);
661
+				$new_default->save();
662
+				do_action(
663
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
664
+					$new_default,
665
+					$row,
666
+					$ticket,
667
+					$data
668
+				);
669
+			}
670
+			// DO ALL dtt relationships for both current tickets and any archived tickets
671
+			// for the given dtt that are related to the current ticket.
672
+			// TODO... not sure exactly how we're going to do this considering we don't know
673
+			// what current ticket the archived tickets are related to
674
+			// (and TKT_parent is used for autosaves so that's not a field we can reliably use).
675
+			//let's assign any tickets that have been setup to the saved_tickets tracker
676
+			//save existing TKT
677
+			$ticket->save();
678
+			if ($create_new_TKT && $new_tkt instanceof EE_Ticket) {
679
+				//save new TKT
680
+				$new_tkt->save();
681
+				//add new ticket to array
682
+				$saved_tickets[ $new_tkt->ID() ] = $new_tkt;
683
+				do_action(
684
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
685
+					$new_tkt,
686
+					$row,
687
+					$tkt,
688
+					$data
689
+				);
690
+			} else {
691
+				//add tkt to saved tkts
692
+				$saved_tickets[ $ticket->ID() ] = $ticket;
693
+				do_action(
694
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
695
+					$ticket,
696
+					$row,
697
+					$tkt,
698
+					$data
699
+				);
700
+			}
701
+		}
702
+		// now we need to handle tickets actually "deleted permanently".
703
+		// There are cases where we'd want this to happen
704
+		// (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
705
+		// Or a draft event was saved and in the process of editing a ticket is trashed.
706
+		// No sense in keeping all the related data in the db!
707
+		$old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? array() : $old_tickets;
708
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
709
+		foreach ($tickets_removed as $id) {
710
+			$id = absint($id);
711
+			//get the ticket for this id
712
+			$tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
713
+			//if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
714
+			if ($tkt_to_remove->get('TKT_is_default')) {
715
+				continue;
716
+			}
717
+			// if this tkt has any registrations attached so then we just ARCHIVE
718
+			// because we don't actually permanently delete these tickets.
719
+			if ($tkt_to_remove->count_related('Registration') > 0) {
720
+				$tkt_to_remove->delete();
721
+				continue;
722
+			}
723
+			// need to get all the related datetimes on this ticket and remove from every single one of them
724
+			// (remember this process can ONLY kick off if there are NO tkts_sold)
725
+			$datetimes = $tkt_to_remove->get_many_related('Datetime');
726
+			foreach ($datetimes as $datetime) {
727
+				$tkt_to_remove->_remove_relation_to($datetime, 'Datetime');
728
+			}
729
+			// need to do the same for prices (except these prices can also be deleted because again,
730
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
731
+			$tkt_to_remove->delete_related_permanently('Price');
732
+			do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $tkt_to_remove);
733
+			// finally let's delete this ticket
734
+			// (which should not be blocked at this point b/c we've removed all our relationships)
735
+			$tkt_to_remove->delete_permanently();
736
+		}
737
+		return $saved_tickets;
738
+	}
739 739
 
740 740
 
741
-    /**
742
-     * @access  protected
743
-     * @param EE_Ticket      $ticket
744
-     * @param \EE_Datetime[] $saved_datetimes
745
-     * @param \EE_Datetime[] $added_datetimes
746
-     * @param \EE_Datetime[] $removed_datetimes
747
-     * @return EE_Ticket
748
-     * @throws EE_Error
749
-     */
750
-    protected function _update_ticket_datetimes(
751
-        EE_Ticket $ticket,
752
-        $saved_datetimes = array(),
753
-        $added_datetimes = array(),
754
-        $removed_datetimes = array()
755
-    ) {
756
-        // to start we have to add the ticket to all the datetimes its supposed to be with,
757
-        // and removing the ticket from datetimes it got removed from.
758
-        // first let's add datetimes
759
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
760
-            foreach ($added_datetimes as $row_id) {
761
-                $row_id = (int) $row_id;
762
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
763
-                    $ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
764
-                    // Is this an existing ticket (has an ID) and does it have any sold?
765
-                    // If so, then we need to add that to the DTT sold because this DTT is getting added.
766
-                    if ($ticket->ID() && $ticket->sold() > 0) {
767
-                        $saved_datetimes[ $row_id ]->increase_sold($ticket->sold());
768
-                        $saved_datetimes[ $row_id ]->save();
769
-                    }
770
-                }
771
-            }
772
-        }
773
-        // then remove datetimes
774
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
775
-            foreach ($removed_datetimes as $row_id) {
776
-                $row_id = (int) $row_id;
777
-                // its entirely possible that a datetime got deleted (instead of just removed from relationship.
778
-                // So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
779
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
780
-                    $ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
781
-                    // Is this an existing ticket (has an ID) and does it have any sold?
782
-                    // If so, then we need to remove it's sold from the DTT_sold.
783
-                    if ($ticket->ID() && $ticket->sold() > 0) {
784
-                        $saved_datetimes[ $row_id ]->decrease_sold($ticket->sold());
785
-                        $saved_datetimes[ $row_id ]->save();
786
-                    }
787
-                }
788
-            }
789
-        }
790
-        // cap ticket qty by datetime reg limits
791
-        $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
792
-        return $ticket;
793
-    }
741
+	/**
742
+	 * @access  protected
743
+	 * @param EE_Ticket      $ticket
744
+	 * @param \EE_Datetime[] $saved_datetimes
745
+	 * @param \EE_Datetime[] $added_datetimes
746
+	 * @param \EE_Datetime[] $removed_datetimes
747
+	 * @return EE_Ticket
748
+	 * @throws EE_Error
749
+	 */
750
+	protected function _update_ticket_datetimes(
751
+		EE_Ticket $ticket,
752
+		$saved_datetimes = array(),
753
+		$added_datetimes = array(),
754
+		$removed_datetimes = array()
755
+	) {
756
+		// to start we have to add the ticket to all the datetimes its supposed to be with,
757
+		// and removing the ticket from datetimes it got removed from.
758
+		// first let's add datetimes
759
+		if (! empty($added_datetimes) && is_array($added_datetimes)) {
760
+			foreach ($added_datetimes as $row_id) {
761
+				$row_id = (int) $row_id;
762
+				if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
763
+					$ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
764
+					// Is this an existing ticket (has an ID) and does it have any sold?
765
+					// If so, then we need to add that to the DTT sold because this DTT is getting added.
766
+					if ($ticket->ID() && $ticket->sold() > 0) {
767
+						$saved_datetimes[ $row_id ]->increase_sold($ticket->sold());
768
+						$saved_datetimes[ $row_id ]->save();
769
+					}
770
+				}
771
+			}
772
+		}
773
+		// then remove datetimes
774
+		if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
775
+			foreach ($removed_datetimes as $row_id) {
776
+				$row_id = (int) $row_id;
777
+				// its entirely possible that a datetime got deleted (instead of just removed from relationship.
778
+				// So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
779
+				if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
780
+					$ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
781
+					// Is this an existing ticket (has an ID) and does it have any sold?
782
+					// If so, then we need to remove it's sold from the DTT_sold.
783
+					if ($ticket->ID() && $ticket->sold() > 0) {
784
+						$saved_datetimes[ $row_id ]->decrease_sold($ticket->sold());
785
+						$saved_datetimes[ $row_id ]->save();
786
+					}
787
+				}
788
+			}
789
+		}
790
+		// cap ticket qty by datetime reg limits
791
+		$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
792
+		return $ticket;
793
+	}
794 794
 
795 795
 
796
-    /**
797
-     * @access  protected
798
-     * @param EE_Ticket $ticket
799
-     * @param array     $price_rows
800
-     * @param int       $ticket_price
801
-     * @param int       $base_price
802
-     * @param int       $base_price_id
803
-     * @return EE_Ticket
804
-     * @throws ReflectionException
805
-     * @throws InvalidArgumentException
806
-     * @throws InvalidInterfaceException
807
-     * @throws InvalidDataTypeException
808
-     * @throws EE_Error
809
-     */
810
-    protected function _duplicate_ticket(
811
-        EE_Ticket $ticket,
812
-        $price_rows = array(),
813
-        $ticket_price = 0,
814
-        $base_price = 0,
815
-        $base_price_id = 0
816
-    ) {
817
-        // create new ticket that's a copy of the existing
818
-        // except a new id of course (and not archived)
819
-        // AND has the new TKT_price associated with it.
820
-        $new_ticket = clone $ticket;
821
-        $new_ticket->set('TKT_ID', 0);
822
-        $new_ticket->set_deleted(0);
823
-        $new_ticket->set_price($ticket_price);
824
-        $new_ticket->set_sold(0);
825
-        // let's get a new ID for this ticket
826
-        $new_ticket->save();
827
-        // we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
828
-        $datetimes_on_existing = $ticket->datetimes();
829
-        $new_ticket            = $this->_update_ticket_datetimes(
830
-            $new_ticket,
831
-            $datetimes_on_existing,
832
-            array_keys($datetimes_on_existing)
833
-        );
834
-        // $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
835
-        // if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
836
-        // available.
837
-        if ($ticket->sold() > 0) {
838
-            $new_qty = $ticket->qty() - $ticket->sold();
839
-            $new_ticket->set_qty($new_qty);
840
-        }
841
-        //now we update the prices just for this ticket
842
-        $new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
843
-        //and we update the base price
844
-        $new_ticket = $this->_add_prices_to_ticket(
845
-            array(),
846
-            $new_ticket,
847
-            true,
848
-            $base_price,
849
-            $base_price_id
850
-        );
851
-        return $new_ticket;
852
-    }
796
+	/**
797
+	 * @access  protected
798
+	 * @param EE_Ticket $ticket
799
+	 * @param array     $price_rows
800
+	 * @param int       $ticket_price
801
+	 * @param int       $base_price
802
+	 * @param int       $base_price_id
803
+	 * @return EE_Ticket
804
+	 * @throws ReflectionException
805
+	 * @throws InvalidArgumentException
806
+	 * @throws InvalidInterfaceException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws EE_Error
809
+	 */
810
+	protected function _duplicate_ticket(
811
+		EE_Ticket $ticket,
812
+		$price_rows = array(),
813
+		$ticket_price = 0,
814
+		$base_price = 0,
815
+		$base_price_id = 0
816
+	) {
817
+		// create new ticket that's a copy of the existing
818
+		// except a new id of course (and not archived)
819
+		// AND has the new TKT_price associated with it.
820
+		$new_ticket = clone $ticket;
821
+		$new_ticket->set('TKT_ID', 0);
822
+		$new_ticket->set_deleted(0);
823
+		$new_ticket->set_price($ticket_price);
824
+		$new_ticket->set_sold(0);
825
+		// let's get a new ID for this ticket
826
+		$new_ticket->save();
827
+		// we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
828
+		$datetimes_on_existing = $ticket->datetimes();
829
+		$new_ticket            = $this->_update_ticket_datetimes(
830
+			$new_ticket,
831
+			$datetimes_on_existing,
832
+			array_keys($datetimes_on_existing)
833
+		);
834
+		// $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
835
+		// if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
836
+		// available.
837
+		if ($ticket->sold() > 0) {
838
+			$new_qty = $ticket->qty() - $ticket->sold();
839
+			$new_ticket->set_qty($new_qty);
840
+		}
841
+		//now we update the prices just for this ticket
842
+		$new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
843
+		//and we update the base price
844
+		$new_ticket = $this->_add_prices_to_ticket(
845
+			array(),
846
+			$new_ticket,
847
+			true,
848
+			$base_price,
849
+			$base_price_id
850
+		);
851
+		return $new_ticket;
852
+	}
853 853
 
854 854
 
855
-    /**
856
-     * This attaches a list of given prices to a ticket.
857
-     * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
858
-     * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
859
-     * price info and prices are automatically "archived" via the ticket.
860
-     *
861
-     * @access  private
862
-     * @param array     $prices        Array of prices from the form.
863
-     * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
864
-     * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
865
-     * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
866
-     * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
867
-     * @return EE_Ticket
868
-     * @throws ReflectionException
869
-     * @throws InvalidArgumentException
870
-     * @throws InvalidInterfaceException
871
-     * @throws InvalidDataTypeException
872
-     * @throws EE_Error
873
-     */
874
-    protected function _add_prices_to_ticket(
875
-        $prices = array(),
876
-        EE_Ticket $ticket,
877
-        $new_prices = false,
878
-        $base_price = false,
879
-        $base_price_id = false
880
-    ) {
881
-        // let's just get any current prices that may exist on the given ticket
882
-        // so we can remove any prices that got trashed in this session.
883
-        $current_prices_on_ticket = $base_price !== false
884
-            ? $ticket->base_price(true)
885
-            : $ticket->price_modifiers();
886
-        $updated_prices           = array();
887
-        // if $base_price ! FALSE then updating a base price.
888
-        if ($base_price !== false) {
889
-            $prices[1] = array(
890
-                'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
891
-                'PRT_ID'     => 1,
892
-                'PRC_amount' => $base_price,
893
-                'PRC_name'   => $ticket->get('TKT_name'),
894
-                'PRC_desc'   => $ticket->get('TKT_description'),
895
-            );
896
-        }
897
-        //possibly need to save tkt
898
-        if (! $ticket->ID()) {
899
-            $ticket->save();
900
-        }
901
-        foreach ($prices as $row => $prc) {
902
-            $prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
903
-            if (empty($prt_id)) {
904
-                continue;
905
-            } //prices MUST have a price type id.
906
-            $PRC_values = array(
907
-                'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
908
-                'PRT_ID'         => $prt_id,
909
-                'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
910
-                'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
911
-                'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
912
-                'PRC_is_default' => false,
913
-                //make sure we set PRC_is_default to false for all ticket saves from event_editor
914
-                'PRC_order'      => $row,
915
-            );
916
-            if ($new_prices || empty($PRC_values['PRC_ID'])) {
917
-                $PRC_values['PRC_ID'] = 0;
918
-                $price                = EE_Registry::instance()->load_class(
919
-                    'Price',
920
-                    array($PRC_values),
921
-                    false,
922
-                    false
923
-                );
924
-            } else {
925
-                $price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
926
-                //update this price with new values
927
-                foreach ($PRC_values as $field => $value) {
928
-                    $price->set($field, $value);
929
-                }
930
-            }
931
-            $price->save();
932
-            $updated_prices[ $price->ID() ] = $price;
933
-            $ticket->_add_relation_to($price, 'Price');
934
-        }
935
-        //now let's remove any prices that got removed from the ticket
936
-        if (! empty ($current_prices_on_ticket)) {
937
-            $current          = array_keys($current_prices_on_ticket);
938
-            $updated          = array_keys($updated_prices);
939
-            $prices_to_remove = array_diff($current, $updated);
940
-            if (! empty($prices_to_remove)) {
941
-                foreach ($prices_to_remove as $prc_id) {
942
-                    $p = $current_prices_on_ticket[ $prc_id ];
943
-                    $ticket->_remove_relation_to($p, 'Price');
944
-                    //delete permanently the price
945
-                    $p->delete_permanently();
946
-                }
947
-            }
948
-        }
949
-        return $ticket;
950
-    }
855
+	/**
856
+	 * This attaches a list of given prices to a ticket.
857
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
858
+	 * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
859
+	 * price info and prices are automatically "archived" via the ticket.
860
+	 *
861
+	 * @access  private
862
+	 * @param array     $prices        Array of prices from the form.
863
+	 * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
864
+	 * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
865
+	 * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
866
+	 * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
867
+	 * @return EE_Ticket
868
+	 * @throws ReflectionException
869
+	 * @throws InvalidArgumentException
870
+	 * @throws InvalidInterfaceException
871
+	 * @throws InvalidDataTypeException
872
+	 * @throws EE_Error
873
+	 */
874
+	protected function _add_prices_to_ticket(
875
+		$prices = array(),
876
+		EE_Ticket $ticket,
877
+		$new_prices = false,
878
+		$base_price = false,
879
+		$base_price_id = false
880
+	) {
881
+		// let's just get any current prices that may exist on the given ticket
882
+		// so we can remove any prices that got trashed in this session.
883
+		$current_prices_on_ticket = $base_price !== false
884
+			? $ticket->base_price(true)
885
+			: $ticket->price_modifiers();
886
+		$updated_prices           = array();
887
+		// if $base_price ! FALSE then updating a base price.
888
+		if ($base_price !== false) {
889
+			$prices[1] = array(
890
+				'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
891
+				'PRT_ID'     => 1,
892
+				'PRC_amount' => $base_price,
893
+				'PRC_name'   => $ticket->get('TKT_name'),
894
+				'PRC_desc'   => $ticket->get('TKT_description'),
895
+			);
896
+		}
897
+		//possibly need to save tkt
898
+		if (! $ticket->ID()) {
899
+			$ticket->save();
900
+		}
901
+		foreach ($prices as $row => $prc) {
902
+			$prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
903
+			if (empty($prt_id)) {
904
+				continue;
905
+			} //prices MUST have a price type id.
906
+			$PRC_values = array(
907
+				'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
908
+				'PRT_ID'         => $prt_id,
909
+				'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
910
+				'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
911
+				'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
912
+				'PRC_is_default' => false,
913
+				//make sure we set PRC_is_default to false for all ticket saves from event_editor
914
+				'PRC_order'      => $row,
915
+			);
916
+			if ($new_prices || empty($PRC_values['PRC_ID'])) {
917
+				$PRC_values['PRC_ID'] = 0;
918
+				$price                = EE_Registry::instance()->load_class(
919
+					'Price',
920
+					array($PRC_values),
921
+					false,
922
+					false
923
+				);
924
+			} else {
925
+				$price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
926
+				//update this price with new values
927
+				foreach ($PRC_values as $field => $value) {
928
+					$price->set($field, $value);
929
+				}
930
+			}
931
+			$price->save();
932
+			$updated_prices[ $price->ID() ] = $price;
933
+			$ticket->_add_relation_to($price, 'Price');
934
+		}
935
+		//now let's remove any prices that got removed from the ticket
936
+		if (! empty ($current_prices_on_ticket)) {
937
+			$current          = array_keys($current_prices_on_ticket);
938
+			$updated          = array_keys($updated_prices);
939
+			$prices_to_remove = array_diff($current, $updated);
940
+			if (! empty($prices_to_remove)) {
941
+				foreach ($prices_to_remove as $prc_id) {
942
+					$p = $current_prices_on_ticket[ $prc_id ];
943
+					$ticket->_remove_relation_to($p, 'Price');
944
+					//delete permanently the price
945
+					$p->delete_permanently();
946
+				}
947
+			}
948
+		}
949
+		return $ticket;
950
+	}
951 951
 
952 952
 
953
-    /**
954
-     * @param Events_Admin_Page $event_admin_obj
955
-     * @return Events_Admin_Page
956
-     */
957
-    public function autosave_handling(Events_Admin_Page $event_admin_obj)
958
-    {
959
-        return $event_admin_obj;
960
-        //doing nothing for the moment.
961
-        // todo when I get to this remember that I need to set the template args on the $event_admin_obj
962
-        // (use the set_template_args() method)
963
-        /**
964
-         * need to remember to handle TICKET DEFAULT saves correctly:  I've got two input fields in the dom:
965
-         * 1. TKT_is_default_selector (visible)
966
-         * 2. TKT_is_default (hidden)
967
-         * I think we'll use the TKT_is_default for recording whether the ticket displayed IS a default ticket
968
-         * (on new event creations). Whereas the TKT_is_default_selector is for the user to indicate they want
969
-         * this ticket to be saved as a default.
970
-         * The tricky part is, on an initial display on create or edit (or after manually updating),
971
-         * the TKT_is_default_selector will always be unselected and the TKT_is_default will only be true
972
-         * if this is a create.  However, after an autosave, users will want some sort of indicator that
973
-         * the TKT HAS been saved as a default..
974
-         * in other words we don't want to remove the check on TKT_is_default_selector. So here's what I'm thinking.
975
-         * On Autosave:
976
-         * 1. If TKT_is_default is true: we create a new TKT, send back the new id and add id to related elements,
977
-         * then set the TKT_is_default to false.
978
-         * 2. If TKT_is_default_selector is true: we create/edit existing ticket (following conditions above as well).
979
-         *  We do NOT create a new default ticket.  The checkbox stays selected after autosave.
980
-         * 3. only on MANUAL update do we check for the selection and if selected create the new default ticket.
981
-         */
982
-    }
953
+	/**
954
+	 * @param Events_Admin_Page $event_admin_obj
955
+	 * @return Events_Admin_Page
956
+	 */
957
+	public function autosave_handling(Events_Admin_Page $event_admin_obj)
958
+	{
959
+		return $event_admin_obj;
960
+		//doing nothing for the moment.
961
+		// todo when I get to this remember that I need to set the template args on the $event_admin_obj
962
+		// (use the set_template_args() method)
963
+		/**
964
+		 * need to remember to handle TICKET DEFAULT saves correctly:  I've got two input fields in the dom:
965
+		 * 1. TKT_is_default_selector (visible)
966
+		 * 2. TKT_is_default (hidden)
967
+		 * I think we'll use the TKT_is_default for recording whether the ticket displayed IS a default ticket
968
+		 * (on new event creations). Whereas the TKT_is_default_selector is for the user to indicate they want
969
+		 * this ticket to be saved as a default.
970
+		 * The tricky part is, on an initial display on create or edit (or after manually updating),
971
+		 * the TKT_is_default_selector will always be unselected and the TKT_is_default will only be true
972
+		 * if this is a create.  However, after an autosave, users will want some sort of indicator that
973
+		 * the TKT HAS been saved as a default..
974
+		 * in other words we don't want to remove the check on TKT_is_default_selector. So here's what I'm thinking.
975
+		 * On Autosave:
976
+		 * 1. If TKT_is_default is true: we create a new TKT, send back the new id and add id to related elements,
977
+		 * then set the TKT_is_default to false.
978
+		 * 2. If TKT_is_default_selector is true: we create/edit existing ticket (following conditions above as well).
979
+		 *  We do NOT create a new default ticket.  The checkbox stays selected after autosave.
980
+		 * 3. only on MANUAL update do we check for the selection and if selected create the new default ticket.
981
+		 */
982
+	}
983 983
 
984 984
 
985
-    /**
986
-     * @throws ReflectionException
987
-     * @throws InvalidArgumentException
988
-     * @throws InvalidInterfaceException
989
-     * @throws InvalidDataTypeException
990
-     * @throws DomainException
991
-     * @throws EE_Error
992
-     */
993
-    public function pricing_metabox()
994
-    {
995
-        $existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = array();
996
-        $event                 = $this->_adminpage_obj->get_cpt_model_obj();
997
-        //set is_creating_event property.
998
-        $EVT_ID                   = $event->ID();
999
-        $this->_is_creating_event = absint($EVT_ID) === 0;
1000
-        //default main template args
1001
-        $main_template_args = array(
1002
-            'event_datetime_help_link' => EEH_Template::get_help_tab_link(
1003
-                'event_editor_event_datetimes_help_tab',
1004
-                $this->_adminpage_obj->page_slug,
1005
-                $this->_adminpage_obj->get_req_action(),
1006
-                false,
1007
-                false
1008
-            ),
1009
-            // todo need to add a filter to the template for the help text
1010
-            // in the Events_Admin_Page core file so we can add further help
1011
-            'existing_datetime_ids'    => '',
1012
-            'total_dtt_rows'           => 1,
1013
-            'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
1014
-                'add_new_dtt_info',
1015
-                $this->_adminpage_obj->page_slug,
1016
-                $this->_adminpage_obj->get_req_action(),
1017
-                false,
1018
-                false
1019
-            ),
1020
-            //todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1021
-            'datetime_rows'            => '',
1022
-            'show_tickets_container'   => '',
1023
-            //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 1 ? ' style="display:none;"' : '',
1024
-            'ticket_rows'              => '',
1025
-            'existing_ticket_ids'      => '',
1026
-            'total_ticket_rows'        => 1,
1027
-            'ticket_js_structure'      => '',
1028
-            'ee_collapsible_status'    => ' ee-collapsible-open'
1029
-            //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
1030
-        );
1031
-        $timezone           = $event instanceof EE_Event ? $event->timezone_string() : null;
1032
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1033
-        /**
1034
-         * 1. Start with retrieving Datetimes
1035
-         * 2. For each datetime get related tickets
1036
-         * 3. For each ticket get related prices
1037
-         */
1038
-        /** @var EEM_Datetime $datetime_model */
1039
-        $datetime_model                       = EE_Registry::instance()->load_model('Datetime', array($timezone));
1040
-        $datetimes                            = $datetime_model->get_all_event_dates($EVT_ID);
1041
-        $main_template_args['total_dtt_rows'] = count($datetimes);
1042
-        /**
1043
-         * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
1044
-         * for why we are counting $datetime_row and then setting that on the Datetime object
1045
-         */
1046
-        $datetime_row = 1;
1047
-        foreach ($datetimes as $datetime) {
1048
-            $DTT_ID = $datetime->get('DTT_ID');
1049
-            $datetime->set('DTT_order', $datetime_row);
1050
-            $existing_datetime_ids[] = $DTT_ID;
1051
-            //tickets attached
1052
-            $related_tickets = $datetime->ID() > 0
1053
-                ? $datetime->get_many_related(
1054
-                    'Ticket',
1055
-                    array(
1056
-                        array(
1057
-                            'OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0),
1058
-                        ),
1059
-                        'default_where_conditions' => 'none',
1060
-                        'order_by'                 => array('TKT_order' => 'ASC'),
1061
-                    )
1062
-                )
1063
-                : array();
1064
-            //if there are no related tickets this is likely a new event OR autodraft
1065
-            // event so we need to generate the default tickets because datetimes
1066
-            // ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1067
-            // datetime on the event.
1068
-            if (empty ($related_tickets) && count($datetimes) < 2) {
1069
-                /** @var EEM_Ticket $ticket_model */
1070
-                $ticket_model    = EE_Registry::instance()->load_model('Ticket');
1071
-                $related_tickets = $ticket_model->get_all_default_tickets();
1072
-                // this should be ordered by TKT_ID, so let's grab the first default ticket
1073
-                // (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1074
-                $default_prices      = EEM_Price::instance()->get_all_default_prices();
1075
-                $main_default_ticket = reset($related_tickets);
1076
-                if ($main_default_ticket instanceof EE_Ticket) {
1077
-                    foreach ($default_prices as $default_price) {
1078
-                        if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1079
-                            continue;
1080
-                        }
1081
-                        $main_default_ticket->cache('Price', $default_price);
1082
-                    }
1083
-                }
1084
-            }
1085
-            // we can't actually setup rows in this loop yet cause we don't know all
1086
-            // the unique tickets for this event yet (tickets are linked through all datetimes).
1087
-            // So we're going to temporarily cache some of that information.
1088
-            //loop through and setup the ticket rows and make sure the order is set.
1089
-            foreach ($related_tickets as $ticket) {
1090
-                $TKT_ID     = $ticket->get('TKT_ID');
1091
-                $ticket_row = $ticket->get('TKT_row');
1092
-                //we only want unique tickets in our final display!!
1093
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1094
-                    $existing_ticket_ids[] = $TKT_ID;
1095
-                    $all_tickets[]         = $ticket;
1096
-                }
1097
-                //temporary cache of this ticket info for this datetime for later processing of datetime rows.
1098
-                $datetime_tickets[ $DTT_ID ][] = $ticket_row;
1099
-                //temporary cache of this datetime info for this ticket for later processing of ticket rows.
1100
-                if (
1101
-                    ! isset($ticket_datetimes[ $TKT_ID ])
1102
-                    || ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1103
-                ) {
1104
-                    $ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1105
-                }
1106
-            }
1107
-            $datetime_row++;
1108
-        }
1109
-        $main_template_args['total_ticket_rows']     = count($existing_ticket_ids);
1110
-        $main_template_args['existing_ticket_ids']   = implode(',', $existing_ticket_ids);
1111
-        $main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1112
-        //sort $all_tickets by order
1113
-        usort(
1114
-            $all_tickets,
1115
-            function (EE_Ticket $a, EE_Ticket $b)
1116
-            {
1117
-                $a_order = (int) $a->get('TKT_order');
1118
-                $b_order = (int) $b->get('TKT_order');
1119
-                if ($a_order === $b_order) {
1120
-                    return 0;
1121
-                }
1122
-                return ($a_order < $b_order) ? -1 : 1;
1123
-            }
1124
-        );
1125
-        // k NOW we have all the data we need for setting up the dtt rows
1126
-        // and ticket rows so we start our dtt loop again.
1127
-        $datetime_row = 1;
1128
-        foreach ($datetimes as $datetime) {
1129
-            $main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1130
-                $datetime_row,
1131
-                $datetime,
1132
-                $datetime_tickets,
1133
-                $all_tickets,
1134
-                false,
1135
-                $datetimes
1136
-            );
1137
-            $datetime_row++;
1138
-        }
1139
-        //then loop through all tickets for the ticket rows.
1140
-        $ticket_row = 1;
1141
-        foreach ($all_tickets as $ticket) {
1142
-            $main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1143
-                $ticket_row,
1144
-                $ticket,
1145
-                $ticket_datetimes,
1146
-                $datetimes,
1147
-                false,
1148
-                $all_tickets
1149
-            );
1150
-            $ticket_row++;
1151
-        }
1152
-        $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1153
-        EEH_Template::display_template(
1154
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1155
-            $main_template_args
1156
-        );
1157
-    }
985
+	/**
986
+	 * @throws ReflectionException
987
+	 * @throws InvalidArgumentException
988
+	 * @throws InvalidInterfaceException
989
+	 * @throws InvalidDataTypeException
990
+	 * @throws DomainException
991
+	 * @throws EE_Error
992
+	 */
993
+	public function pricing_metabox()
994
+	{
995
+		$existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = array();
996
+		$event                 = $this->_adminpage_obj->get_cpt_model_obj();
997
+		//set is_creating_event property.
998
+		$EVT_ID                   = $event->ID();
999
+		$this->_is_creating_event = absint($EVT_ID) === 0;
1000
+		//default main template args
1001
+		$main_template_args = array(
1002
+			'event_datetime_help_link' => EEH_Template::get_help_tab_link(
1003
+				'event_editor_event_datetimes_help_tab',
1004
+				$this->_adminpage_obj->page_slug,
1005
+				$this->_adminpage_obj->get_req_action(),
1006
+				false,
1007
+				false
1008
+			),
1009
+			// todo need to add a filter to the template for the help text
1010
+			// in the Events_Admin_Page core file so we can add further help
1011
+			'existing_datetime_ids'    => '',
1012
+			'total_dtt_rows'           => 1,
1013
+			'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
1014
+				'add_new_dtt_info',
1015
+				$this->_adminpage_obj->page_slug,
1016
+				$this->_adminpage_obj->get_req_action(),
1017
+				false,
1018
+				false
1019
+			),
1020
+			//todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1021
+			'datetime_rows'            => '',
1022
+			'show_tickets_container'   => '',
1023
+			//$this->_adminpage_obj->get_cpt_model_obj()->ID() > 1 ? ' style="display:none;"' : '',
1024
+			'ticket_rows'              => '',
1025
+			'existing_ticket_ids'      => '',
1026
+			'total_ticket_rows'        => 1,
1027
+			'ticket_js_structure'      => '',
1028
+			'ee_collapsible_status'    => ' ee-collapsible-open'
1029
+			//$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
1030
+		);
1031
+		$timezone           = $event instanceof EE_Event ? $event->timezone_string() : null;
1032
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1033
+		/**
1034
+		 * 1. Start with retrieving Datetimes
1035
+		 * 2. For each datetime get related tickets
1036
+		 * 3. For each ticket get related prices
1037
+		 */
1038
+		/** @var EEM_Datetime $datetime_model */
1039
+		$datetime_model                       = EE_Registry::instance()->load_model('Datetime', array($timezone));
1040
+		$datetimes                            = $datetime_model->get_all_event_dates($EVT_ID);
1041
+		$main_template_args['total_dtt_rows'] = count($datetimes);
1042
+		/**
1043
+		 * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
1044
+		 * for why we are counting $datetime_row and then setting that on the Datetime object
1045
+		 */
1046
+		$datetime_row = 1;
1047
+		foreach ($datetimes as $datetime) {
1048
+			$DTT_ID = $datetime->get('DTT_ID');
1049
+			$datetime->set('DTT_order', $datetime_row);
1050
+			$existing_datetime_ids[] = $DTT_ID;
1051
+			//tickets attached
1052
+			$related_tickets = $datetime->ID() > 0
1053
+				? $datetime->get_many_related(
1054
+					'Ticket',
1055
+					array(
1056
+						array(
1057
+							'OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0),
1058
+						),
1059
+						'default_where_conditions' => 'none',
1060
+						'order_by'                 => array('TKT_order' => 'ASC'),
1061
+					)
1062
+				)
1063
+				: array();
1064
+			//if there are no related tickets this is likely a new event OR autodraft
1065
+			// event so we need to generate the default tickets because datetimes
1066
+			// ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1067
+			// datetime on the event.
1068
+			if (empty ($related_tickets) && count($datetimes) < 2) {
1069
+				/** @var EEM_Ticket $ticket_model */
1070
+				$ticket_model    = EE_Registry::instance()->load_model('Ticket');
1071
+				$related_tickets = $ticket_model->get_all_default_tickets();
1072
+				// this should be ordered by TKT_ID, so let's grab the first default ticket
1073
+				// (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1074
+				$default_prices      = EEM_Price::instance()->get_all_default_prices();
1075
+				$main_default_ticket = reset($related_tickets);
1076
+				if ($main_default_ticket instanceof EE_Ticket) {
1077
+					foreach ($default_prices as $default_price) {
1078
+						if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1079
+							continue;
1080
+						}
1081
+						$main_default_ticket->cache('Price', $default_price);
1082
+					}
1083
+				}
1084
+			}
1085
+			// we can't actually setup rows in this loop yet cause we don't know all
1086
+			// the unique tickets for this event yet (tickets are linked through all datetimes).
1087
+			// So we're going to temporarily cache some of that information.
1088
+			//loop through and setup the ticket rows and make sure the order is set.
1089
+			foreach ($related_tickets as $ticket) {
1090
+				$TKT_ID     = $ticket->get('TKT_ID');
1091
+				$ticket_row = $ticket->get('TKT_row');
1092
+				//we only want unique tickets in our final display!!
1093
+				if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1094
+					$existing_ticket_ids[] = $TKT_ID;
1095
+					$all_tickets[]         = $ticket;
1096
+				}
1097
+				//temporary cache of this ticket info for this datetime for later processing of datetime rows.
1098
+				$datetime_tickets[ $DTT_ID ][] = $ticket_row;
1099
+				//temporary cache of this datetime info for this ticket for later processing of ticket rows.
1100
+				if (
1101
+					! isset($ticket_datetimes[ $TKT_ID ])
1102
+					|| ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1103
+				) {
1104
+					$ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1105
+				}
1106
+			}
1107
+			$datetime_row++;
1108
+		}
1109
+		$main_template_args['total_ticket_rows']     = count($existing_ticket_ids);
1110
+		$main_template_args['existing_ticket_ids']   = implode(',', $existing_ticket_ids);
1111
+		$main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1112
+		//sort $all_tickets by order
1113
+		usort(
1114
+			$all_tickets,
1115
+			function (EE_Ticket $a, EE_Ticket $b)
1116
+			{
1117
+				$a_order = (int) $a->get('TKT_order');
1118
+				$b_order = (int) $b->get('TKT_order');
1119
+				if ($a_order === $b_order) {
1120
+					return 0;
1121
+				}
1122
+				return ($a_order < $b_order) ? -1 : 1;
1123
+			}
1124
+		);
1125
+		// k NOW we have all the data we need for setting up the dtt rows
1126
+		// and ticket rows so we start our dtt loop again.
1127
+		$datetime_row = 1;
1128
+		foreach ($datetimes as $datetime) {
1129
+			$main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1130
+				$datetime_row,
1131
+				$datetime,
1132
+				$datetime_tickets,
1133
+				$all_tickets,
1134
+				false,
1135
+				$datetimes
1136
+			);
1137
+			$datetime_row++;
1138
+		}
1139
+		//then loop through all tickets for the ticket rows.
1140
+		$ticket_row = 1;
1141
+		foreach ($all_tickets as $ticket) {
1142
+			$main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1143
+				$ticket_row,
1144
+				$ticket,
1145
+				$ticket_datetimes,
1146
+				$datetimes,
1147
+				false,
1148
+				$all_tickets
1149
+			);
1150
+			$ticket_row++;
1151
+		}
1152
+		$main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1153
+		EEH_Template::display_template(
1154
+			PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1155
+			$main_template_args
1156
+		);
1157
+	}
1158 1158
 
1159 1159
 
1160
-    /**
1161
-     * @param int         $datetime_row
1162
-     * @param EE_Datetime $datetime
1163
-     * @param array       $datetime_tickets
1164
-     * @param array       $all_tickets
1165
-     * @param bool        $default
1166
-     * @param array       $all_datetimes
1167
-     * @return mixed
1168
-     * @throws DomainException
1169
-     * @throws EE_Error
1170
-     */
1171
-    protected function _get_datetime_row(
1172
-        $datetime_row,
1173
-        EE_Datetime $datetime,
1174
-        $datetime_tickets = array(),
1175
-        $all_tickets = array(),
1176
-        $default = false,
1177
-        $all_datetimes = array()
1178
-    ) {
1179
-        $dtt_display_template_args = array(
1180
-            'dtt_edit_row'             => $this->_get_dtt_edit_row(
1181
-                $datetime_row,
1182
-                $datetime,
1183
-                $default,
1184
-                $all_datetimes
1185
-            ),
1186
-            'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1187
-                $datetime_row,
1188
-                $datetime,
1189
-                $datetime_tickets,
1190
-                $all_tickets,
1191
-                $default
1192
-            ),
1193
-            'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1194
-        );
1195
-        return EEH_Template::display_template(
1196
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1197
-            $dtt_display_template_args,
1198
-            true
1199
-        );
1200
-    }
1160
+	/**
1161
+	 * @param int         $datetime_row
1162
+	 * @param EE_Datetime $datetime
1163
+	 * @param array       $datetime_tickets
1164
+	 * @param array       $all_tickets
1165
+	 * @param bool        $default
1166
+	 * @param array       $all_datetimes
1167
+	 * @return mixed
1168
+	 * @throws DomainException
1169
+	 * @throws EE_Error
1170
+	 */
1171
+	protected function _get_datetime_row(
1172
+		$datetime_row,
1173
+		EE_Datetime $datetime,
1174
+		$datetime_tickets = array(),
1175
+		$all_tickets = array(),
1176
+		$default = false,
1177
+		$all_datetimes = array()
1178
+	) {
1179
+		$dtt_display_template_args = array(
1180
+			'dtt_edit_row'             => $this->_get_dtt_edit_row(
1181
+				$datetime_row,
1182
+				$datetime,
1183
+				$default,
1184
+				$all_datetimes
1185
+			),
1186
+			'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1187
+				$datetime_row,
1188
+				$datetime,
1189
+				$datetime_tickets,
1190
+				$all_tickets,
1191
+				$default
1192
+			),
1193
+			'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1194
+		);
1195
+		return EEH_Template::display_template(
1196
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1197
+			$dtt_display_template_args,
1198
+			true
1199
+		);
1200
+	}
1201 1201
 
1202 1202
 
1203
-    /**
1204
-     * This method is used to generate a dtt fields  edit row.
1205
-     * The same row is used to generate a row with valid DTT objects
1206
-     * and the default row that is used as the skeleton by the js.
1207
-     *
1208
-     * @param int           $datetime_row  The row number for the row being generated.
1209
-     * @param EE_Datetime   $datetime
1210
-     * @param bool          $default       Whether a default row is being generated or not.
1211
-     * @param EE_Datetime[] $all_datetimes This is the array of all datetimes used in the editor.
1212
-     * @return string
1213
-     * @throws DomainException
1214
-     * @throws EE_Error
1215
-     */
1216
-    protected function _get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes)
1217
-    {
1218
-        // if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1219
-        $default                     = ! $datetime instanceof EE_Datetime ? true : $default;
1220
-        $template_args               = array(
1221
-            'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1222
-            'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1223
-            'edit_dtt_expanded'    => '',
1224
-            'DTT_ID'               => $default ? '' : $datetime->ID(),
1225
-            'DTT_name'             => $default ? '' : $datetime->get_f('DTT_name'),
1226
-            'DTT_description'      => $default ? '' : $datetime->get_f('DTT_description'),
1227
-            'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1228
-            'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1229
-            'DTT_reg_limit'        => $default
1230
-                ? ''
1231
-                : $datetime->get_pretty(
1232
-                    'DTT_reg_limit',
1233
-                    'input'
1234
-                ),
1235
-            'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1236
-            'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1237
-            'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1238
-            'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1239
-                ? ''
1240
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1241
-            'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1242
-                ? 'ee-lock-icon'
1243
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1244
-            'reg_list_url'         => $default || ! $datetime->event() instanceof \EE_Event
1245
-                ? ''
1246
-                : EE_Admin_Page::add_query_args_and_nonce(
1247
-                    array('event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()),
1248
-                    REG_ADMIN_URL
1249
-                ),
1250
-        );
1251
-        $template_args['show_trash'] = count($all_datetimes) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1252
-            ? ' style="display:none"'
1253
-            : '';
1254
-        //allow filtering of template args at this point.
1255
-        $template_args = apply_filters(
1256
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1257
-            $template_args,
1258
-            $datetime_row,
1259
-            $datetime,
1260
-            $default,
1261
-            $all_datetimes,
1262
-            $this->_is_creating_event
1263
-        );
1264
-        return EEH_Template::display_template(
1265
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1266
-            $template_args,
1267
-            true
1268
-        );
1269
-    }
1203
+	/**
1204
+	 * This method is used to generate a dtt fields  edit row.
1205
+	 * The same row is used to generate a row with valid DTT objects
1206
+	 * and the default row that is used as the skeleton by the js.
1207
+	 *
1208
+	 * @param int           $datetime_row  The row number for the row being generated.
1209
+	 * @param EE_Datetime   $datetime
1210
+	 * @param bool          $default       Whether a default row is being generated or not.
1211
+	 * @param EE_Datetime[] $all_datetimes This is the array of all datetimes used in the editor.
1212
+	 * @return string
1213
+	 * @throws DomainException
1214
+	 * @throws EE_Error
1215
+	 */
1216
+	protected function _get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes)
1217
+	{
1218
+		// if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1219
+		$default                     = ! $datetime instanceof EE_Datetime ? true : $default;
1220
+		$template_args               = array(
1221
+			'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1222
+			'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1223
+			'edit_dtt_expanded'    => '',
1224
+			'DTT_ID'               => $default ? '' : $datetime->ID(),
1225
+			'DTT_name'             => $default ? '' : $datetime->get_f('DTT_name'),
1226
+			'DTT_description'      => $default ? '' : $datetime->get_f('DTT_description'),
1227
+			'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1228
+			'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1229
+			'DTT_reg_limit'        => $default
1230
+				? ''
1231
+				: $datetime->get_pretty(
1232
+					'DTT_reg_limit',
1233
+					'input'
1234
+				),
1235
+			'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1236
+			'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1237
+			'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1238
+			'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1239
+				? ''
1240
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1241
+			'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1242
+				? 'ee-lock-icon'
1243
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1244
+			'reg_list_url'         => $default || ! $datetime->event() instanceof \EE_Event
1245
+				? ''
1246
+				: EE_Admin_Page::add_query_args_and_nonce(
1247
+					array('event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()),
1248
+					REG_ADMIN_URL
1249
+				),
1250
+		);
1251
+		$template_args['show_trash'] = count($all_datetimes) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1252
+			? ' style="display:none"'
1253
+			: '';
1254
+		//allow filtering of template args at this point.
1255
+		$template_args = apply_filters(
1256
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1257
+			$template_args,
1258
+			$datetime_row,
1259
+			$datetime,
1260
+			$default,
1261
+			$all_datetimes,
1262
+			$this->_is_creating_event
1263
+		);
1264
+		return EEH_Template::display_template(
1265
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1266
+			$template_args,
1267
+			true
1268
+		);
1269
+	}
1270 1270
 
1271 1271
 
1272
-    /**
1273
-     * @param int         $datetime_row
1274
-     * @param EE_Datetime $datetime
1275
-     * @param array       $datetime_tickets
1276
-     * @param array       $all_tickets
1277
-     * @param bool        $default
1278
-     * @return mixed
1279
-     * @throws DomainException
1280
-     * @throws EE_Error
1281
-     */
1282
-    protected function _get_dtt_attached_tickets_row(
1283
-        $datetime_row,
1284
-        $datetime,
1285
-        $datetime_tickets = array(),
1286
-        $all_tickets = array(),
1287
-        $default
1288
-    ) {
1289
-        $template_args = array(
1290
-            'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1291
-            'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1292
-            'DTT_description'                   => $default ? '' : $datetime->get_f('DTT_description'),
1293
-            'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1294
-            'show_tickets_row'                  => ' style="display:none;"',
1295
-            'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1296
-                'add_new_ticket_via_datetime',
1297
-                $this->_adminpage_obj->page_slug,
1298
-                $this->_adminpage_obj->get_req_action(),
1299
-                false,
1300
-                false
1301
-            ),
1302
-            //todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1303
-            'DTT_ID'                            => $default ? '' : $datetime->ID(),
1304
-        );
1305
-        //need to setup the list items (but only if this isn't a default skeleton setup)
1306
-        if (! $default) {
1307
-            $ticket_row = 1;
1308
-            foreach ($all_tickets as $ticket) {
1309
-                $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1310
-                    $datetime_row,
1311
-                    $ticket_row,
1312
-                    $datetime,
1313
-                    $ticket,
1314
-                    $datetime_tickets,
1315
-                    $default
1316
-                );
1317
-                $ticket_row++;
1318
-            }
1319
-        }
1320
-        //filter template args at this point
1321
-        $template_args = apply_filters(
1322
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1323
-            $template_args,
1324
-            $datetime_row,
1325
-            $datetime,
1326
-            $datetime_tickets,
1327
-            $all_tickets,
1328
-            $default,
1329
-            $this->_is_creating_event
1330
-        );
1331
-        return EEH_Template::display_template(
1332
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1333
-            $template_args,
1334
-            true
1335
-        );
1336
-    }
1272
+	/**
1273
+	 * @param int         $datetime_row
1274
+	 * @param EE_Datetime $datetime
1275
+	 * @param array       $datetime_tickets
1276
+	 * @param array       $all_tickets
1277
+	 * @param bool        $default
1278
+	 * @return mixed
1279
+	 * @throws DomainException
1280
+	 * @throws EE_Error
1281
+	 */
1282
+	protected function _get_dtt_attached_tickets_row(
1283
+		$datetime_row,
1284
+		$datetime,
1285
+		$datetime_tickets = array(),
1286
+		$all_tickets = array(),
1287
+		$default
1288
+	) {
1289
+		$template_args = array(
1290
+			'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1291
+			'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1292
+			'DTT_description'                   => $default ? '' : $datetime->get_f('DTT_description'),
1293
+			'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1294
+			'show_tickets_row'                  => ' style="display:none;"',
1295
+			'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1296
+				'add_new_ticket_via_datetime',
1297
+				$this->_adminpage_obj->page_slug,
1298
+				$this->_adminpage_obj->get_req_action(),
1299
+				false,
1300
+				false
1301
+			),
1302
+			//todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1303
+			'DTT_ID'                            => $default ? '' : $datetime->ID(),
1304
+		);
1305
+		//need to setup the list items (but only if this isn't a default skeleton setup)
1306
+		if (! $default) {
1307
+			$ticket_row = 1;
1308
+			foreach ($all_tickets as $ticket) {
1309
+				$template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1310
+					$datetime_row,
1311
+					$ticket_row,
1312
+					$datetime,
1313
+					$ticket,
1314
+					$datetime_tickets,
1315
+					$default
1316
+				);
1317
+				$ticket_row++;
1318
+			}
1319
+		}
1320
+		//filter template args at this point
1321
+		$template_args = apply_filters(
1322
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1323
+			$template_args,
1324
+			$datetime_row,
1325
+			$datetime,
1326
+			$datetime_tickets,
1327
+			$all_tickets,
1328
+			$default,
1329
+			$this->_is_creating_event
1330
+		);
1331
+		return EEH_Template::display_template(
1332
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1333
+			$template_args,
1334
+			true
1335
+		);
1336
+	}
1337 1337
 
1338 1338
 
1339
-    /**
1340
-     * @param int         $datetime_row
1341
-     * @param int         $ticket_row
1342
-     * @param EE_Datetime $datetime
1343
-     * @param EE_Ticket   $ticket
1344
-     * @param array       $datetime_tickets
1345
-     * @param bool        $default
1346
-     * @return mixed
1347
-     * @throws DomainException
1348
-     * @throws EE_Error
1349
-     */
1350
-    protected function _get_datetime_tickets_list_item(
1351
-        $datetime_row,
1352
-        $ticket_row,
1353
-        $datetime,
1354
-        $ticket,
1355
-        $datetime_tickets = array(),
1356
-        $default
1357
-    ) {
1358
-        $dtt_tkts      = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1359
-            ? $datetime_tickets[ $datetime->ID() ]
1360
-            : array();
1361
-        $display_row   = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1362
-        $no_ticket     = $default && empty($ticket);
1363
-        $template_args = array(
1364
-            'dtt_row'                 => $default
1365
-                ? 'DTTNUM'
1366
-                : $datetime_row,
1367
-            'tkt_row'                 => $no_ticket
1368
-                ? 'TICKETNUM'
1369
-                : $ticket_row,
1370
-            'datetime_ticket_checked' => in_array($display_row, $dtt_tkts, true)
1371
-                ? ' checked="checked"'
1372
-                : '',
1373
-            'ticket_selected'         => in_array($display_row, $dtt_tkts, true)
1374
-                ? ' ticket-selected'
1375
-                : '',
1376
-            'TKT_name'                => $no_ticket
1377
-                ? 'TKTNAME'
1378
-                : $ticket->get('TKT_name'),
1379
-            'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1380
-                ? ' tkt-status-' . EE_Ticket::onsale
1381
-                : ' tkt-status-' . $ticket->ticket_status(),
1382
-        );
1383
-        //filter template args
1384
-        $template_args = apply_filters(
1385
-            'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1386
-            $template_args,
1387
-            $datetime_row,
1388
-            $ticket_row,
1389
-            $datetime,
1390
-            $ticket,
1391
-            $datetime_tickets,
1392
-            $default,
1393
-            $this->_is_creating_event
1394
-        );
1395
-        return EEH_Template::display_template(
1396
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1397
-            $template_args,
1398
-            true
1399
-        );
1400
-    }
1339
+	/**
1340
+	 * @param int         $datetime_row
1341
+	 * @param int         $ticket_row
1342
+	 * @param EE_Datetime $datetime
1343
+	 * @param EE_Ticket   $ticket
1344
+	 * @param array       $datetime_tickets
1345
+	 * @param bool        $default
1346
+	 * @return mixed
1347
+	 * @throws DomainException
1348
+	 * @throws EE_Error
1349
+	 */
1350
+	protected function _get_datetime_tickets_list_item(
1351
+		$datetime_row,
1352
+		$ticket_row,
1353
+		$datetime,
1354
+		$ticket,
1355
+		$datetime_tickets = array(),
1356
+		$default
1357
+	) {
1358
+		$dtt_tkts      = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1359
+			? $datetime_tickets[ $datetime->ID() ]
1360
+			: array();
1361
+		$display_row   = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1362
+		$no_ticket     = $default && empty($ticket);
1363
+		$template_args = array(
1364
+			'dtt_row'                 => $default
1365
+				? 'DTTNUM'
1366
+				: $datetime_row,
1367
+			'tkt_row'                 => $no_ticket
1368
+				? 'TICKETNUM'
1369
+				: $ticket_row,
1370
+			'datetime_ticket_checked' => in_array($display_row, $dtt_tkts, true)
1371
+				? ' checked="checked"'
1372
+				: '',
1373
+			'ticket_selected'         => in_array($display_row, $dtt_tkts, true)
1374
+				? ' ticket-selected'
1375
+				: '',
1376
+			'TKT_name'                => $no_ticket
1377
+				? 'TKTNAME'
1378
+				: $ticket->get('TKT_name'),
1379
+			'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1380
+				? ' tkt-status-' . EE_Ticket::onsale
1381
+				: ' tkt-status-' . $ticket->ticket_status(),
1382
+		);
1383
+		//filter template args
1384
+		$template_args = apply_filters(
1385
+			'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1386
+			$template_args,
1387
+			$datetime_row,
1388
+			$ticket_row,
1389
+			$datetime,
1390
+			$ticket,
1391
+			$datetime_tickets,
1392
+			$default,
1393
+			$this->_is_creating_event
1394
+		);
1395
+		return EEH_Template::display_template(
1396
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1397
+			$template_args,
1398
+			true
1399
+		);
1400
+	}
1401 1401
 
1402 1402
 
1403
-    /**
1404
-     * This generates the ticket row for tickets.
1405
-     * This same method is used to generate both the actual rows and the js skeleton row
1406
-     * (when default === true)
1407
-     *
1408
-     * @param int           $ticket_row       Represents the row number being generated.
1409
-     * @param               $ticket
1410
-     * @param EE_Datetime[] $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1411
-     *                                        or empty for default
1412
-     * @param EE_Datetime[] $all_datetimes    All Datetimes on the event or empty for default.
1413
-     * @param bool          $default          Whether default row being generated or not.
1414
-     * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1415
-     *                                        (or empty in the case of defaults)
1416
-     * @return mixed
1417
-     * @throws InvalidArgumentException
1418
-     * @throws InvalidInterfaceException
1419
-     * @throws InvalidDataTypeException
1420
-     * @throws DomainException
1421
-     * @throws EE_Error
1422
-     * @throws ReflectionException
1423
-     */
1424
-    protected function _get_ticket_row(
1425
-        $ticket_row,
1426
-        $ticket,
1427
-        $ticket_datetimes,
1428
-        $all_datetimes,
1429
-        $default = false,
1430
-        $all_tickets = array()
1431
-    ) {
1432
-        // if $ticket is not an instance of EE_Ticket then force default to true.
1433
-        $default = ! $ticket instanceof EE_Ticket ? true : $default;
1434
-        $prices  = ! empty($ticket) && ! $default ? $ticket->get_many_related('Price',
1435
-            array('default_where_conditions' => 'none', 'order_by' => array('PRC_order' => 'ASC'))) : array();
1436
-        // if there is only one price (which would be the base price)
1437
-        // or NO prices and this ticket is a default ticket,
1438
-        // let's just make sure there are no cached default prices on the object.
1439
-        // This is done by not including any query_params.
1440
-        if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1441
-            $prices = $ticket->prices();
1442
-        }
1443
-        // check if we're dealing with a default ticket in which case
1444
-        // we don't want any starting_ticket_datetime_row values set
1445
-        // (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1446
-        // This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1447
-        $default_dtt      = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1448
-        $tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1449
-            ? $ticket_datetimes[ $ticket->ID() ]
1450
-            : array();
1451
-        $ticket_subtotal  = $default ? 0 : $ticket->get_ticket_subtotal();
1452
-        $base_price       = $default ? null : $ticket->base_price();
1453
-        $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1454
-        //breaking out complicated condition for ticket_status
1455
-        if ($default) {
1456
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1457
-        } else {
1458
-            $ticket_status_class = $ticket->is_default()
1459
-                ? ' tkt-status-' . EE_Ticket::onsale
1460
-                : ' tkt-status-' . $ticket->ticket_status();
1461
-        }
1462
-        //breaking out complicated condition for TKT_taxable
1463
-        if ($default) {
1464
-            $TKT_taxable = '';
1465
-        } else {
1466
-            $TKT_taxable = $ticket->taxable()
1467
-                ? ' checked="checked"'
1468
-                : '';
1469
-        }
1470
-        if ($default) {
1471
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1472
-        } elseif ($ticket->is_default()) {
1473
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1474
-        } else {
1475
-            $TKT_status = $ticket->ticket_status(true);
1476
-        }
1477
-        if ($default) {
1478
-            $TKT_min = '';
1479
-        } else {
1480
-            $TKT_min = $ticket->min();
1481
-            if ($TKT_min === -1 || $TKT_min === 0) {
1482
-                $TKT_min = '';
1483
-            }
1484
-        }
1485
-        $template_args                 = array(
1486
-            'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1487
-            'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1488
-            //on initial page load this will always be the correct order.
1489
-            'tkt_status_class'              => $ticket_status_class,
1490
-            'display_edit_tkt_row'          => ' style="display:none;"',
1491
-            'edit_tkt_expanded'             => '',
1492
-            'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1493
-            'TKT_name'                      => $default ? '' : $ticket->get_f('TKT_name'),
1494
-            'TKT_start_date'                => $default
1495
-                ? ''
1496
-                : $ticket->get_date('TKT_start_date', $this->_date_time_format),
1497
-            'TKT_end_date'                  => $default
1498
-                ? ''
1499
-                : $ticket->get_date('TKT_end_date', $this->_date_time_format),
1500
-            'TKT_status'                    => $TKT_status,
1501
-            'TKT_price'                     => $default
1502
-                ? ''
1503
-                : EEH_Template::format_currency(
1504
-                    $ticket->get_ticket_total_with_taxes(),
1505
-                    false,
1506
-                    false
1507
-                ),
1508
-            'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1509
-            'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1510
-            'TKT_qty'                       => $default
1511
-                ? ''
1512
-                : $ticket->get_pretty('TKT_qty', 'symbol'),
1513
-            'TKT_qty_for_input'             => $default
1514
-                ? ''
1515
-                : $ticket->get_pretty('TKT_qty', 'input'),
1516
-            'TKT_uses'                      => $default
1517
-                ? ''
1518
-                : $ticket->get_pretty('TKT_uses', 'input'),
1519
-            'TKT_min'                       => $TKT_min,
1520
-            'TKT_max'                       => $default
1521
-                ? ''
1522
-                : $ticket->get_pretty('TKT_max', 'input'),
1523
-            'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold('ticket'),
1524
-            'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1525
-            'TKT_registrations'             => $default
1526
-                ? 0
1527
-                : $ticket->count_registrations(
1528
-                    array(
1529
-                        array(
1530
-                            'STS_ID' => array(
1531
-                                '!=',
1532
-                                EEM_Registration::status_id_incomplete,
1533
-                            ),
1534
-                        ),
1535
-                    )
1536
-                ),
1537
-            'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1538
-            'TKT_description'               => $default ? '' : $ticket->get_f('TKT_description'),
1539
-            'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1540
-            'TKT_required'                  => $default ? 0 : $ticket->required(),
1541
-            'TKT_is_default_selector'       => '',
1542
-            'ticket_price_rows'             => '',
1543
-            'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1544
-                ? ''
1545
-                : $base_price->get_pretty('PRC_amount', 'localized_float'),
1546
-            'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1547
-            'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1548
-                ? ''
1549
-                : ' style="display:none;"',
1550
-            'show_price_mod_button'         => count($prices) > 1
1551
-                                               || ($default && $count_price_mods > 0)
1552
-                                               || (! $default && $ticket->deleted())
1553
-                ? ' style="display:none;"'
1554
-                : '',
1555
-            'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1556
-            'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1557
-            'starting_ticket_datetime_rows' => $default || $default_dtt ? '' : implode(',', $tkt_datetimes),
1558
-            'ticket_datetime_rows'          => $default ? '' : implode(',', $tkt_datetimes),
1559
-            'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1560
-            'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1561
-            'TKT_taxable'                   => $TKT_taxable,
1562
-            'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1563
-                ? ''
1564
-                : ' style="display:none"',
1565
-            'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1566
-            'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1567
-                $ticket_subtotal,
1568
-                false,
1569
-                false
1570
-            ),
1571
-            'TKT_subtotal_amount'           => $ticket_subtotal,
1572
-            'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1573
-            'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1574
-            'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1575
-                ? ' ticket-archived'
1576
-                : '',
1577
-            'trash_icon'                    => $ticket instanceof EE_Ticket
1578
-                                               && $ticket->deleted()
1579
-                                               && ! $ticket->is_permanently_deleteable()
1580
-                ? 'ee-lock-icon '
1581
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1582
-            'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1583
-                ? ''
1584
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1585
-        );
1586
-        $template_args['trash_hidden'] = count($all_tickets) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1587
-            ? ' style="display:none"'
1588
-            : '';
1589
-        //handle rows that should NOT be empty
1590
-        if (empty($template_args['TKT_start_date'])) {
1591
-            //if empty then the start date will be now.
1592
-            $template_args['TKT_start_date']   = date($this->_date_time_format,
1593
-                current_time('timestamp'));
1594
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1595
-        }
1596
-        if (empty($template_args['TKT_end_date'])) {
1597
-            //get the earliest datetime (if present);
1598
-            $earliest_dtt = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1599
-                ? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1600
-                    'Datetime',
1601
-                    array('order_by' => array('DTT_EVT_start' => 'ASC'))
1602
-                )
1603
-                : null;
1604
-            if (! empty($earliest_dtt)) {
1605
-                $template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1606
-                    'DTT_EVT_start',
1607
-                    $this->_date_time_format
1608
-                );
1609
-            } else {
1610
-                //default so let's just use what's been set for the default date-time which is 30 days from now.
1611
-                $template_args['TKT_end_date'] = date(
1612
-                    $this->_date_time_format,
1613
-                    mktime(
1614
-                        24, 0, 0, date('m'), date('d') + 29, date('Y')
1615
-                    )
1616
-                );
1617
-            }
1618
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1619
-        }
1620
-        //generate ticket_datetime items
1621
-        if (! $default) {
1622
-            $datetime_row = 1;
1623
-            foreach ($all_datetimes as $datetime) {
1624
-                $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1625
-                    $datetime_row,
1626
-                    $ticket_row,
1627
-                    $datetime,
1628
-                    $ticket,
1629
-                    $ticket_datetimes,
1630
-                    $default
1631
-                );
1632
-                $datetime_row++;
1633
-            }
1634
-        }
1635
-        $price_row = 1;
1636
-        foreach ($prices as $price) {
1637
-            if (! $price instanceof EE_Price) {
1638
-                continue;
1639
-            }
1640
-            if ($price->is_base_price()) {
1641
-                $price_row++;
1642
-                continue;
1643
-            }
1644
-            $show_trash                         = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1645
-            $show_create                        = ! (count($prices) > 1 && count($prices) !== $price_row);
1646
-            $template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1647
-                $ticket_row,
1648
-                $price_row,
1649
-                $price,
1650
-                $default,
1651
-                $ticket,
1652
-                $show_trash,
1653
-                $show_create
1654
-            );
1655
-            $price_row++;
1656
-        }
1657
-        //filter $template_args
1658
-        $template_args = apply_filters(
1659
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1660
-            $template_args,
1661
-            $ticket_row,
1662
-            $ticket,
1663
-            $ticket_datetimes,
1664
-            $all_datetimes,
1665
-            $default,
1666
-            $all_tickets,
1667
-            $this->_is_creating_event
1668
-        );
1669
-        return EEH_Template::display_template(
1670
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1671
-            $template_args,
1672
-            true
1673
-        );
1674
-    }
1403
+	/**
1404
+	 * This generates the ticket row for tickets.
1405
+	 * This same method is used to generate both the actual rows and the js skeleton row
1406
+	 * (when default === true)
1407
+	 *
1408
+	 * @param int           $ticket_row       Represents the row number being generated.
1409
+	 * @param               $ticket
1410
+	 * @param EE_Datetime[] $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1411
+	 *                                        or empty for default
1412
+	 * @param EE_Datetime[] $all_datetimes    All Datetimes on the event or empty for default.
1413
+	 * @param bool          $default          Whether default row being generated or not.
1414
+	 * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1415
+	 *                                        (or empty in the case of defaults)
1416
+	 * @return mixed
1417
+	 * @throws InvalidArgumentException
1418
+	 * @throws InvalidInterfaceException
1419
+	 * @throws InvalidDataTypeException
1420
+	 * @throws DomainException
1421
+	 * @throws EE_Error
1422
+	 * @throws ReflectionException
1423
+	 */
1424
+	protected function _get_ticket_row(
1425
+		$ticket_row,
1426
+		$ticket,
1427
+		$ticket_datetimes,
1428
+		$all_datetimes,
1429
+		$default = false,
1430
+		$all_tickets = array()
1431
+	) {
1432
+		// if $ticket is not an instance of EE_Ticket then force default to true.
1433
+		$default = ! $ticket instanceof EE_Ticket ? true : $default;
1434
+		$prices  = ! empty($ticket) && ! $default ? $ticket->get_many_related('Price',
1435
+			array('default_where_conditions' => 'none', 'order_by' => array('PRC_order' => 'ASC'))) : array();
1436
+		// if there is only one price (which would be the base price)
1437
+		// or NO prices and this ticket is a default ticket,
1438
+		// let's just make sure there are no cached default prices on the object.
1439
+		// This is done by not including any query_params.
1440
+		if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1441
+			$prices = $ticket->prices();
1442
+		}
1443
+		// check if we're dealing with a default ticket in which case
1444
+		// we don't want any starting_ticket_datetime_row values set
1445
+		// (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1446
+		// This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1447
+		$default_dtt      = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1448
+		$tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1449
+			? $ticket_datetimes[ $ticket->ID() ]
1450
+			: array();
1451
+		$ticket_subtotal  = $default ? 0 : $ticket->get_ticket_subtotal();
1452
+		$base_price       = $default ? null : $ticket->base_price();
1453
+		$count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1454
+		//breaking out complicated condition for ticket_status
1455
+		if ($default) {
1456
+			$ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1457
+		} else {
1458
+			$ticket_status_class = $ticket->is_default()
1459
+				? ' tkt-status-' . EE_Ticket::onsale
1460
+				: ' tkt-status-' . $ticket->ticket_status();
1461
+		}
1462
+		//breaking out complicated condition for TKT_taxable
1463
+		if ($default) {
1464
+			$TKT_taxable = '';
1465
+		} else {
1466
+			$TKT_taxable = $ticket->taxable()
1467
+				? ' checked="checked"'
1468
+				: '';
1469
+		}
1470
+		if ($default) {
1471
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1472
+		} elseif ($ticket->is_default()) {
1473
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1474
+		} else {
1475
+			$TKT_status = $ticket->ticket_status(true);
1476
+		}
1477
+		if ($default) {
1478
+			$TKT_min = '';
1479
+		} else {
1480
+			$TKT_min = $ticket->min();
1481
+			if ($TKT_min === -1 || $TKT_min === 0) {
1482
+				$TKT_min = '';
1483
+			}
1484
+		}
1485
+		$template_args                 = array(
1486
+			'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1487
+			'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1488
+			//on initial page load this will always be the correct order.
1489
+			'tkt_status_class'              => $ticket_status_class,
1490
+			'display_edit_tkt_row'          => ' style="display:none;"',
1491
+			'edit_tkt_expanded'             => '',
1492
+			'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1493
+			'TKT_name'                      => $default ? '' : $ticket->get_f('TKT_name'),
1494
+			'TKT_start_date'                => $default
1495
+				? ''
1496
+				: $ticket->get_date('TKT_start_date', $this->_date_time_format),
1497
+			'TKT_end_date'                  => $default
1498
+				? ''
1499
+				: $ticket->get_date('TKT_end_date', $this->_date_time_format),
1500
+			'TKT_status'                    => $TKT_status,
1501
+			'TKT_price'                     => $default
1502
+				? ''
1503
+				: EEH_Template::format_currency(
1504
+					$ticket->get_ticket_total_with_taxes(),
1505
+					false,
1506
+					false
1507
+				),
1508
+			'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1509
+			'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1510
+			'TKT_qty'                       => $default
1511
+				? ''
1512
+				: $ticket->get_pretty('TKT_qty', 'symbol'),
1513
+			'TKT_qty_for_input'             => $default
1514
+				? ''
1515
+				: $ticket->get_pretty('TKT_qty', 'input'),
1516
+			'TKT_uses'                      => $default
1517
+				? ''
1518
+				: $ticket->get_pretty('TKT_uses', 'input'),
1519
+			'TKT_min'                       => $TKT_min,
1520
+			'TKT_max'                       => $default
1521
+				? ''
1522
+				: $ticket->get_pretty('TKT_max', 'input'),
1523
+			'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold('ticket'),
1524
+			'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1525
+			'TKT_registrations'             => $default
1526
+				? 0
1527
+				: $ticket->count_registrations(
1528
+					array(
1529
+						array(
1530
+							'STS_ID' => array(
1531
+								'!=',
1532
+								EEM_Registration::status_id_incomplete,
1533
+							),
1534
+						),
1535
+					)
1536
+				),
1537
+			'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1538
+			'TKT_description'               => $default ? '' : $ticket->get_f('TKT_description'),
1539
+			'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1540
+			'TKT_required'                  => $default ? 0 : $ticket->required(),
1541
+			'TKT_is_default_selector'       => '',
1542
+			'ticket_price_rows'             => '',
1543
+			'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1544
+				? ''
1545
+				: $base_price->get_pretty('PRC_amount', 'localized_float'),
1546
+			'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1547
+			'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1548
+				? ''
1549
+				: ' style="display:none;"',
1550
+			'show_price_mod_button'         => count($prices) > 1
1551
+											   || ($default && $count_price_mods > 0)
1552
+											   || (! $default && $ticket->deleted())
1553
+				? ' style="display:none;"'
1554
+				: '',
1555
+			'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1556
+			'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1557
+			'starting_ticket_datetime_rows' => $default || $default_dtt ? '' : implode(',', $tkt_datetimes),
1558
+			'ticket_datetime_rows'          => $default ? '' : implode(',', $tkt_datetimes),
1559
+			'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1560
+			'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1561
+			'TKT_taxable'                   => $TKT_taxable,
1562
+			'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1563
+				? ''
1564
+				: ' style="display:none"',
1565
+			'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1566
+			'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1567
+				$ticket_subtotal,
1568
+				false,
1569
+				false
1570
+			),
1571
+			'TKT_subtotal_amount'           => $ticket_subtotal,
1572
+			'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1573
+			'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1574
+			'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1575
+				? ' ticket-archived'
1576
+				: '',
1577
+			'trash_icon'                    => $ticket instanceof EE_Ticket
1578
+											   && $ticket->deleted()
1579
+											   && ! $ticket->is_permanently_deleteable()
1580
+				? 'ee-lock-icon '
1581
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1582
+			'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1583
+				? ''
1584
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1585
+		);
1586
+		$template_args['trash_hidden'] = count($all_tickets) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1587
+			? ' style="display:none"'
1588
+			: '';
1589
+		//handle rows that should NOT be empty
1590
+		if (empty($template_args['TKT_start_date'])) {
1591
+			//if empty then the start date will be now.
1592
+			$template_args['TKT_start_date']   = date($this->_date_time_format,
1593
+				current_time('timestamp'));
1594
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1595
+		}
1596
+		if (empty($template_args['TKT_end_date'])) {
1597
+			//get the earliest datetime (if present);
1598
+			$earliest_dtt = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1599
+				? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1600
+					'Datetime',
1601
+					array('order_by' => array('DTT_EVT_start' => 'ASC'))
1602
+				)
1603
+				: null;
1604
+			if (! empty($earliest_dtt)) {
1605
+				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1606
+					'DTT_EVT_start',
1607
+					$this->_date_time_format
1608
+				);
1609
+			} else {
1610
+				//default so let's just use what's been set for the default date-time which is 30 days from now.
1611
+				$template_args['TKT_end_date'] = date(
1612
+					$this->_date_time_format,
1613
+					mktime(
1614
+						24, 0, 0, date('m'), date('d') + 29, date('Y')
1615
+					)
1616
+				);
1617
+			}
1618
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1619
+		}
1620
+		//generate ticket_datetime items
1621
+		if (! $default) {
1622
+			$datetime_row = 1;
1623
+			foreach ($all_datetimes as $datetime) {
1624
+				$template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1625
+					$datetime_row,
1626
+					$ticket_row,
1627
+					$datetime,
1628
+					$ticket,
1629
+					$ticket_datetimes,
1630
+					$default
1631
+				);
1632
+				$datetime_row++;
1633
+			}
1634
+		}
1635
+		$price_row = 1;
1636
+		foreach ($prices as $price) {
1637
+			if (! $price instanceof EE_Price) {
1638
+				continue;
1639
+			}
1640
+			if ($price->is_base_price()) {
1641
+				$price_row++;
1642
+				continue;
1643
+			}
1644
+			$show_trash                         = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1645
+			$show_create                        = ! (count($prices) > 1 && count($prices) !== $price_row);
1646
+			$template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1647
+				$ticket_row,
1648
+				$price_row,
1649
+				$price,
1650
+				$default,
1651
+				$ticket,
1652
+				$show_trash,
1653
+				$show_create
1654
+			);
1655
+			$price_row++;
1656
+		}
1657
+		//filter $template_args
1658
+		$template_args = apply_filters(
1659
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1660
+			$template_args,
1661
+			$ticket_row,
1662
+			$ticket,
1663
+			$ticket_datetimes,
1664
+			$all_datetimes,
1665
+			$default,
1666
+			$all_tickets,
1667
+			$this->_is_creating_event
1668
+		);
1669
+		return EEH_Template::display_template(
1670
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1671
+			$template_args,
1672
+			true
1673
+		);
1674
+	}
1675 1675
 
1676 1676
 
1677
-    /**
1678
-     * @param int            $ticket_row
1679
-     * @param EE_Ticket|null $ticket
1680
-     * @return string
1681
-     * @throws DomainException
1682
-     * @throws EE_Error
1683
-     */
1684
-    protected function _get_tax_rows($ticket_row, $ticket)
1685
-    {
1686
-        $tax_rows = '';
1687
-        /** @var EE_Price[] $taxes */
1688
-        $taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1689
-        foreach ($taxes as $tax) {
1690
-            $tax_added     = $this->_get_tax_added($tax, $ticket);
1691
-            $template_args = array(
1692
-                'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1693
-                    ? ''
1694
-                    : ' style="display:none;"',
1695
-                'tax_id'            => $tax->ID(),
1696
-                'tkt_row'           => $ticket_row,
1697
-                'tax_label'         => $tax->get('PRC_name'),
1698
-                'tax_added'         => $tax_added,
1699
-                'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1700
-                'tax_amount'        => $tax->get('PRC_amount'),
1701
-            );
1702
-            $template_args = apply_filters(
1703
-                'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1704
-                $template_args,
1705
-                $ticket_row,
1706
-                $ticket,
1707
-                $this->_is_creating_event
1708
-            );
1709
-            $tax_rows      .= EEH_Template::display_template(
1710
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1711
-                $template_args,
1712
-                true
1713
-            );
1714
-        }
1715
-        return $tax_rows;
1716
-    }
1677
+	/**
1678
+	 * @param int            $ticket_row
1679
+	 * @param EE_Ticket|null $ticket
1680
+	 * @return string
1681
+	 * @throws DomainException
1682
+	 * @throws EE_Error
1683
+	 */
1684
+	protected function _get_tax_rows($ticket_row, $ticket)
1685
+	{
1686
+		$tax_rows = '';
1687
+		/** @var EE_Price[] $taxes */
1688
+		$taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1689
+		foreach ($taxes as $tax) {
1690
+			$tax_added     = $this->_get_tax_added($tax, $ticket);
1691
+			$template_args = array(
1692
+				'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1693
+					? ''
1694
+					: ' style="display:none;"',
1695
+				'tax_id'            => $tax->ID(),
1696
+				'tkt_row'           => $ticket_row,
1697
+				'tax_label'         => $tax->get('PRC_name'),
1698
+				'tax_added'         => $tax_added,
1699
+				'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1700
+				'tax_amount'        => $tax->get('PRC_amount'),
1701
+			);
1702
+			$template_args = apply_filters(
1703
+				'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1704
+				$template_args,
1705
+				$ticket_row,
1706
+				$ticket,
1707
+				$this->_is_creating_event
1708
+			);
1709
+			$tax_rows      .= EEH_Template::display_template(
1710
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1711
+				$template_args,
1712
+				true
1713
+			);
1714
+		}
1715
+		return $tax_rows;
1716
+	}
1717 1717
 
1718 1718
 
1719
-    /**
1720
-     * @param EE_Price       $tax
1721
-     * @param EE_Ticket|null $ticket
1722
-     * @return float|int
1723
-     * @throws EE_Error
1724
-     */
1725
-    protected function _get_tax_added(EE_Price $tax, $ticket)
1726
-    {
1727
-        $subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1728
-        return $subtotal * $tax->get('PRC_amount') / 100;
1729
-    }
1719
+	/**
1720
+	 * @param EE_Price       $tax
1721
+	 * @param EE_Ticket|null $ticket
1722
+	 * @return float|int
1723
+	 * @throws EE_Error
1724
+	 */
1725
+	protected function _get_tax_added(EE_Price $tax, $ticket)
1726
+	{
1727
+		$subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1728
+		return $subtotal * $tax->get('PRC_amount') / 100;
1729
+	}
1730 1730
 
1731 1731
 
1732
-    /**
1733
-     * @param int            $ticket_row
1734
-     * @param int            $price_row
1735
-     * @param EE_Price|null  $price
1736
-     * @param bool           $default
1737
-     * @param EE_Ticket|null $ticket
1738
-     * @param bool           $show_trash
1739
-     * @param bool           $show_create
1740
-     * @return mixed
1741
-     * @throws InvalidArgumentException
1742
-     * @throws InvalidInterfaceException
1743
-     * @throws InvalidDataTypeException
1744
-     * @throws DomainException
1745
-     * @throws EE_Error
1746
-     * @throws ReflectionException
1747
-     */
1748
-    protected function _get_ticket_price_row(
1749
-        $ticket_row,
1750
-        $price_row,
1751
-        $price,
1752
-        $default,
1753
-        $ticket,
1754
-        $show_trash = true,
1755
-        $show_create = true
1756
-    ) {
1757
-        $send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1758
-        $template_args = array(
1759
-            'tkt_row'               => $default && empty($ticket)
1760
-                ? 'TICKETNUM'
1761
-                : $ticket_row,
1762
-            'PRC_order'             => $default && empty($price)
1763
-                ? 'PRICENUM'
1764
-                : $price_row,
1765
-            'edit_prices_name'      => $default && empty($price)
1766
-                ? 'PRICENAMEATTR'
1767
-                : 'edit_prices',
1768
-            'price_type_selector'   => $default && empty($price)
1769
-                ? $this->_get_base_price_template($ticket_row, $price_row, $price, $default)
1770
-                : $this->_get_price_type_selector(
1771
-                    $ticket_row,
1772
-                    $price_row,
1773
-                    $price,
1774
-                    $default,
1775
-                    $send_disabled
1776
-                ),
1777
-            'PRC_ID'                => $default && empty($price)
1778
-                ? 0
1779
-                : $price->ID(),
1780
-            'PRC_is_default'        => $default && empty($price)
1781
-                ? 0
1782
-                : $price->get('PRC_is_default'),
1783
-            'PRC_name'              => $default && empty($price)
1784
-                ? ''
1785
-                : $price->get('PRC_name'),
1786
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1787
-            'show_plus_or_minus'    => $default && empty($price)
1788
-                ? ''
1789
-                : ' style="display:none;"',
1790
-            'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1791
-                ? ' style="display:none;"'
1792
-                : '',
1793
-            'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1794
-                ? ' style="display:none;"'
1795
-                : '',
1796
-            'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1797
-                ? ' style="display:none"'
1798
-                : '',
1799
-            'PRC_amount'            => $default && empty($price)
1800
-                ? 0
1801
-                : $price->get_pretty('PRC_amount',
1802
-                    'localized_float'),
1803
-            'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1804
-                ? ' style="display:none;"'
1805
-                : '',
1806
-            'show_trash_icon'       => $show_trash
1807
-                ? ''
1808
-                : ' style="display:none;"',
1809
-            'show_create_button'    => $show_create
1810
-                ? ''
1811
-                : ' style="display:none;"',
1812
-            'PRC_desc'              => $default && empty($price)
1813
-                ? ''
1814
-                : $price->get('PRC_desc'),
1815
-            'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1816
-        );
1817
-        $template_args = apply_filters(
1818
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1819
-            $template_args,
1820
-            $ticket_row,
1821
-            $price_row,
1822
-            $price,
1823
-            $default,
1824
-            $ticket,
1825
-            $show_trash,
1826
-            $show_create,
1827
-            $this->_is_creating_event
1828
-        );
1829
-        return EEH_Template::display_template(
1830
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1831
-            $template_args,
1832
-            true
1833
-        );
1834
-    }
1732
+	/**
1733
+	 * @param int            $ticket_row
1734
+	 * @param int            $price_row
1735
+	 * @param EE_Price|null  $price
1736
+	 * @param bool           $default
1737
+	 * @param EE_Ticket|null $ticket
1738
+	 * @param bool           $show_trash
1739
+	 * @param bool           $show_create
1740
+	 * @return mixed
1741
+	 * @throws InvalidArgumentException
1742
+	 * @throws InvalidInterfaceException
1743
+	 * @throws InvalidDataTypeException
1744
+	 * @throws DomainException
1745
+	 * @throws EE_Error
1746
+	 * @throws ReflectionException
1747
+	 */
1748
+	protected function _get_ticket_price_row(
1749
+		$ticket_row,
1750
+		$price_row,
1751
+		$price,
1752
+		$default,
1753
+		$ticket,
1754
+		$show_trash = true,
1755
+		$show_create = true
1756
+	) {
1757
+		$send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1758
+		$template_args = array(
1759
+			'tkt_row'               => $default && empty($ticket)
1760
+				? 'TICKETNUM'
1761
+				: $ticket_row,
1762
+			'PRC_order'             => $default && empty($price)
1763
+				? 'PRICENUM'
1764
+				: $price_row,
1765
+			'edit_prices_name'      => $default && empty($price)
1766
+				? 'PRICENAMEATTR'
1767
+				: 'edit_prices',
1768
+			'price_type_selector'   => $default && empty($price)
1769
+				? $this->_get_base_price_template($ticket_row, $price_row, $price, $default)
1770
+				: $this->_get_price_type_selector(
1771
+					$ticket_row,
1772
+					$price_row,
1773
+					$price,
1774
+					$default,
1775
+					$send_disabled
1776
+				),
1777
+			'PRC_ID'                => $default && empty($price)
1778
+				? 0
1779
+				: $price->ID(),
1780
+			'PRC_is_default'        => $default && empty($price)
1781
+				? 0
1782
+				: $price->get('PRC_is_default'),
1783
+			'PRC_name'              => $default && empty($price)
1784
+				? ''
1785
+				: $price->get('PRC_name'),
1786
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1787
+			'show_plus_or_minus'    => $default && empty($price)
1788
+				? ''
1789
+				: ' style="display:none;"',
1790
+			'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1791
+				? ' style="display:none;"'
1792
+				: '',
1793
+			'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1794
+				? ' style="display:none;"'
1795
+				: '',
1796
+			'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1797
+				? ' style="display:none"'
1798
+				: '',
1799
+			'PRC_amount'            => $default && empty($price)
1800
+				? 0
1801
+				: $price->get_pretty('PRC_amount',
1802
+					'localized_float'),
1803
+			'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1804
+				? ' style="display:none;"'
1805
+				: '',
1806
+			'show_trash_icon'       => $show_trash
1807
+				? ''
1808
+				: ' style="display:none;"',
1809
+			'show_create_button'    => $show_create
1810
+				? ''
1811
+				: ' style="display:none;"',
1812
+			'PRC_desc'              => $default && empty($price)
1813
+				? ''
1814
+				: $price->get('PRC_desc'),
1815
+			'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1816
+		);
1817
+		$template_args = apply_filters(
1818
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1819
+			$template_args,
1820
+			$ticket_row,
1821
+			$price_row,
1822
+			$price,
1823
+			$default,
1824
+			$ticket,
1825
+			$show_trash,
1826
+			$show_create,
1827
+			$this->_is_creating_event
1828
+		);
1829
+		return EEH_Template::display_template(
1830
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1831
+			$template_args,
1832
+			true
1833
+		);
1834
+	}
1835 1835
 
1836 1836
 
1837
-    /**
1838
-     * @param int      $ticket_row
1839
-     * @param int      $price_row
1840
-     * @param EE_Price $price
1841
-     * @param bool     $default
1842
-     * @param bool     $disabled
1843
-     * @return mixed
1844
-     * @throws ReflectionException
1845
-     * @throws InvalidArgumentException
1846
-     * @throws InvalidInterfaceException
1847
-     * @throws InvalidDataTypeException
1848
-     * @throws DomainException
1849
-     * @throws EE_Error
1850
-     */
1851
-    protected function _get_price_type_selector($ticket_row, $price_row, $price, $default, $disabled = false)
1852
-    {
1853
-        if ($price->is_base_price()) {
1854
-            return $this->_get_base_price_template(
1855
-                $ticket_row,
1856
-                $price_row,
1857
-                $price,
1858
-                $default
1859
-            );
1860
-        }
1861
-        return $this->_get_price_modifier_template(
1862
-            $ticket_row,
1863
-            $price_row,
1864
-            $price,
1865
-            $default,
1866
-            $disabled
1867
-        );
1868
-    }
1837
+	/**
1838
+	 * @param int      $ticket_row
1839
+	 * @param int      $price_row
1840
+	 * @param EE_Price $price
1841
+	 * @param bool     $default
1842
+	 * @param bool     $disabled
1843
+	 * @return mixed
1844
+	 * @throws ReflectionException
1845
+	 * @throws InvalidArgumentException
1846
+	 * @throws InvalidInterfaceException
1847
+	 * @throws InvalidDataTypeException
1848
+	 * @throws DomainException
1849
+	 * @throws EE_Error
1850
+	 */
1851
+	protected function _get_price_type_selector($ticket_row, $price_row, $price, $default, $disabled = false)
1852
+	{
1853
+		if ($price->is_base_price()) {
1854
+			return $this->_get_base_price_template(
1855
+				$ticket_row,
1856
+				$price_row,
1857
+				$price,
1858
+				$default
1859
+			);
1860
+		}
1861
+		return $this->_get_price_modifier_template(
1862
+			$ticket_row,
1863
+			$price_row,
1864
+			$price,
1865
+			$default,
1866
+			$disabled
1867
+		);
1868
+	}
1869 1869
 
1870 1870
 
1871
-    /**
1872
-     * @param int      $ticket_row
1873
-     * @param int      $price_row
1874
-     * @param EE_Price $price
1875
-     * @param bool     $default
1876
-     * @return mixed
1877
-     * @throws DomainException
1878
-     * @throws EE_Error
1879
-     */
1880
-    protected function _get_base_price_template($ticket_row, $price_row, $price, $default)
1881
-    {
1882
-        $template_args = array(
1883
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1884
-            'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1885
-            'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1886
-            'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1887
-            'price_selected_operator'   => '+',
1888
-            'price_selected_is_percent' => 0,
1889
-        );
1890
-        $template_args = apply_filters(
1891
-            'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1892
-            $template_args,
1893
-            $ticket_row,
1894
-            $price_row,
1895
-            $price,
1896
-            $default,
1897
-            $this->_is_creating_event
1898
-        );
1899
-        return EEH_Template::display_template(
1900
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1901
-            $template_args,
1902
-            true
1903
-        );
1904
-    }
1871
+	/**
1872
+	 * @param int      $ticket_row
1873
+	 * @param int      $price_row
1874
+	 * @param EE_Price $price
1875
+	 * @param bool     $default
1876
+	 * @return mixed
1877
+	 * @throws DomainException
1878
+	 * @throws EE_Error
1879
+	 */
1880
+	protected function _get_base_price_template($ticket_row, $price_row, $price, $default)
1881
+	{
1882
+		$template_args = array(
1883
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1884
+			'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1885
+			'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1886
+			'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1887
+			'price_selected_operator'   => '+',
1888
+			'price_selected_is_percent' => 0,
1889
+		);
1890
+		$template_args = apply_filters(
1891
+			'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1892
+			$template_args,
1893
+			$ticket_row,
1894
+			$price_row,
1895
+			$price,
1896
+			$default,
1897
+			$this->_is_creating_event
1898
+		);
1899
+		return EEH_Template::display_template(
1900
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1901
+			$template_args,
1902
+			true
1903
+		);
1904
+	}
1905 1905
 
1906 1906
 
1907
-    /**
1908
-     * @param int      $ticket_row
1909
-     * @param int      $price_row
1910
-     * @param EE_Price $price
1911
-     * @param bool     $default
1912
-     * @param bool     $disabled
1913
-     * @return mixed
1914
-     * @throws ReflectionException
1915
-     * @throws InvalidArgumentException
1916
-     * @throws InvalidInterfaceException
1917
-     * @throws InvalidDataTypeException
1918
-     * @throws DomainException
1919
-     * @throws EE_Error
1920
-     */
1921
-    protected function _get_price_modifier_template(
1922
-        $ticket_row,
1923
-        $price_row,
1924
-        $price,
1925
-        $default,
1926
-        $disabled = false
1927
-    ) {
1928
-        $select_name = $default && ! $price instanceof EE_Price
1929
-            ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1930
-            : 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1931
-        /** @var EEM_Price_Type $price_type_model */
1932
-        $price_type_model       = EE_Registry::instance()->load_model('Price_Type');
1933
-        $price_types            = $price_type_model->get_all(array(
1934
-            array(
1935
-                'OR' => array(
1936
-                    'PBT_ID'  => '2',
1937
-                    'PBT_ID*' => '3',
1938
-                ),
1939
-            ),
1940
-        ));
1941
-        $all_price_types        = $default && ! $price instanceof EE_Price
1942
-            ? array(esc_html__('Select Modifier', 'event_espresso'))
1943
-            : array();
1944
-        $selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1945
-        $price_option_spans     = '';
1946
-        //setup price types for selector
1947
-        foreach ($price_types as $price_type) {
1948
-            if (! $price_type instanceof EE_Price_Type) {
1949
-                continue;
1950
-            }
1951
-            $all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
1952
-            //while we're in the loop let's setup the option spans used by js
1953
-            $span_args          = array(
1954
-                'PRT_ID'         => $price_type->ID(),
1955
-                'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1956
-                'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1957
-            );
1958
-            $price_option_spans .= EEH_Template::display_template(
1959
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1960
-                $span_args,
1961
-                true
1962
-            );
1963
-        }
1964
-        $select_name               = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
1965
-            : $select_name;
1966
-        $select_input              = new EE_Select_Input(
1967
-            $all_price_types,
1968
-            array(
1969
-                'default'               => $selected_price_type_id,
1970
-                'html_name'             => $select_name,
1971
-                'html_class'            => 'edit-price-PRT_ID',
1972
-                'html_other_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1973
-            )
1974
-        );
1975
-        $price_selected_operator   = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1976
-        $price_selected_operator   = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1977
-        $price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1978
-        $price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1979
-        $template_args             = array(
1980
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1981
-            'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1982
-            'price_modifier_selector'   => $select_input->get_html_for_input(),
1983
-            'main_name'                 => $select_name,
1984
-            'selected_price_type_id'    => $selected_price_type_id,
1985
-            'price_option_spans'        => $price_option_spans,
1986
-            'price_selected_operator'   => $price_selected_operator,
1987
-            'price_selected_is_percent' => $price_selected_is_percent,
1988
-            'disabled'                  => $disabled,
1989
-        );
1990
-        $template_args             = apply_filters(
1991
-            'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1992
-            $template_args,
1993
-            $ticket_row,
1994
-            $price_row,
1995
-            $price,
1996
-            $default,
1997
-            $disabled,
1998
-            $this->_is_creating_event
1999
-        );
2000
-        return EEH_Template::display_template(
2001
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
2002
-            $template_args,
2003
-            true
2004
-        );
2005
-    }
1907
+	/**
1908
+	 * @param int      $ticket_row
1909
+	 * @param int      $price_row
1910
+	 * @param EE_Price $price
1911
+	 * @param bool     $default
1912
+	 * @param bool     $disabled
1913
+	 * @return mixed
1914
+	 * @throws ReflectionException
1915
+	 * @throws InvalidArgumentException
1916
+	 * @throws InvalidInterfaceException
1917
+	 * @throws InvalidDataTypeException
1918
+	 * @throws DomainException
1919
+	 * @throws EE_Error
1920
+	 */
1921
+	protected function _get_price_modifier_template(
1922
+		$ticket_row,
1923
+		$price_row,
1924
+		$price,
1925
+		$default,
1926
+		$disabled = false
1927
+	) {
1928
+		$select_name = $default && ! $price instanceof EE_Price
1929
+			? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1930
+			: 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1931
+		/** @var EEM_Price_Type $price_type_model */
1932
+		$price_type_model       = EE_Registry::instance()->load_model('Price_Type');
1933
+		$price_types            = $price_type_model->get_all(array(
1934
+			array(
1935
+				'OR' => array(
1936
+					'PBT_ID'  => '2',
1937
+					'PBT_ID*' => '3',
1938
+				),
1939
+			),
1940
+		));
1941
+		$all_price_types        = $default && ! $price instanceof EE_Price
1942
+			? array(esc_html__('Select Modifier', 'event_espresso'))
1943
+			: array();
1944
+		$selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1945
+		$price_option_spans     = '';
1946
+		//setup price types for selector
1947
+		foreach ($price_types as $price_type) {
1948
+			if (! $price_type instanceof EE_Price_Type) {
1949
+				continue;
1950
+			}
1951
+			$all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
1952
+			//while we're in the loop let's setup the option spans used by js
1953
+			$span_args          = array(
1954
+				'PRT_ID'         => $price_type->ID(),
1955
+				'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1956
+				'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1957
+			);
1958
+			$price_option_spans .= EEH_Template::display_template(
1959
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1960
+				$span_args,
1961
+				true
1962
+			);
1963
+		}
1964
+		$select_name               = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
1965
+			: $select_name;
1966
+		$select_input              = new EE_Select_Input(
1967
+			$all_price_types,
1968
+			array(
1969
+				'default'               => $selected_price_type_id,
1970
+				'html_name'             => $select_name,
1971
+				'html_class'            => 'edit-price-PRT_ID',
1972
+				'html_other_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1973
+			)
1974
+		);
1975
+		$price_selected_operator   = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1976
+		$price_selected_operator   = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1977
+		$price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1978
+		$price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1979
+		$template_args             = array(
1980
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1981
+			'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1982
+			'price_modifier_selector'   => $select_input->get_html_for_input(),
1983
+			'main_name'                 => $select_name,
1984
+			'selected_price_type_id'    => $selected_price_type_id,
1985
+			'price_option_spans'        => $price_option_spans,
1986
+			'price_selected_operator'   => $price_selected_operator,
1987
+			'price_selected_is_percent' => $price_selected_is_percent,
1988
+			'disabled'                  => $disabled,
1989
+		);
1990
+		$template_args             = apply_filters(
1991
+			'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1992
+			$template_args,
1993
+			$ticket_row,
1994
+			$price_row,
1995
+			$price,
1996
+			$default,
1997
+			$disabled,
1998
+			$this->_is_creating_event
1999
+		);
2000
+		return EEH_Template::display_template(
2001
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
2002
+			$template_args,
2003
+			true
2004
+		);
2005
+	}
2006 2006
 
2007 2007
 
2008
-    /**
2009
-     * @param int              $datetime_row
2010
-     * @param int              $ticket_row
2011
-     * @param EE_Datetime|null $datetime
2012
-     * @param EE_Ticket|null   $ticket
2013
-     * @param array            $ticket_datetimes
2014
-     * @param bool             $default
2015
-     * @return mixed
2016
-     * @throws DomainException
2017
-     * @throws EE_Error
2018
-     */
2019
-    protected function _get_ticket_datetime_list_item(
2020
-        $datetime_row,
2021
-        $ticket_row,
2022
-        $datetime,
2023
-        $ticket,
2024
-        $ticket_datetimes = array(),
2025
-        $default
2026
-    ) {
2027
-        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2028
-            ? $ticket_datetimes[ $ticket->ID() ]
2029
-            : array();
2030
-        $template_args = array(
2031
-            'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
2032
-                ? 'DTTNUM'
2033
-                : $datetime_row,
2034
-            'tkt_row'                  => $default
2035
-                ? 'TICKETNUM'
2036
-                : $ticket_row,
2037
-            'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
2038
-                ? ' ticket-selected'
2039
-                : '',
2040
-            'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
2041
-                ? ' checked="checked"'
2042
-                : '',
2043
-            'DTT_name'                 => $default && empty($datetime)
2044
-                ? 'DTTNAME'
2045
-                : $datetime->get_dtt_display_name(true),
2046
-            'tkt_status_class'         => '',
2047
-        );
2048
-        $template_args = apply_filters(
2049
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
2050
-            $template_args,
2051
-            $datetime_row,
2052
-            $ticket_row,
2053
-            $datetime,
2054
-            $ticket,
2055
-            $ticket_datetimes,
2056
-            $default,
2057
-            $this->_is_creating_event
2058
-        );
2059
-        return EEH_Template::display_template(
2060
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2061
-            $template_args,
2062
-            true
2063
-        );
2064
-    }
2008
+	/**
2009
+	 * @param int              $datetime_row
2010
+	 * @param int              $ticket_row
2011
+	 * @param EE_Datetime|null $datetime
2012
+	 * @param EE_Ticket|null   $ticket
2013
+	 * @param array            $ticket_datetimes
2014
+	 * @param bool             $default
2015
+	 * @return mixed
2016
+	 * @throws DomainException
2017
+	 * @throws EE_Error
2018
+	 */
2019
+	protected function _get_ticket_datetime_list_item(
2020
+		$datetime_row,
2021
+		$ticket_row,
2022
+		$datetime,
2023
+		$ticket,
2024
+		$ticket_datetimes = array(),
2025
+		$default
2026
+	) {
2027
+		$tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2028
+			? $ticket_datetimes[ $ticket->ID() ]
2029
+			: array();
2030
+		$template_args = array(
2031
+			'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
2032
+				? 'DTTNUM'
2033
+				: $datetime_row,
2034
+			'tkt_row'                  => $default
2035
+				? 'TICKETNUM'
2036
+				: $ticket_row,
2037
+			'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
2038
+				? ' ticket-selected'
2039
+				: '',
2040
+			'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
2041
+				? ' checked="checked"'
2042
+				: '',
2043
+			'DTT_name'                 => $default && empty($datetime)
2044
+				? 'DTTNAME'
2045
+				: $datetime->get_dtt_display_name(true),
2046
+			'tkt_status_class'         => '',
2047
+		);
2048
+		$template_args = apply_filters(
2049
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
2050
+			$template_args,
2051
+			$datetime_row,
2052
+			$ticket_row,
2053
+			$datetime,
2054
+			$ticket,
2055
+			$ticket_datetimes,
2056
+			$default,
2057
+			$this->_is_creating_event
2058
+		);
2059
+		return EEH_Template::display_template(
2060
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2061
+			$template_args,
2062
+			true
2063
+		);
2064
+	}
2065 2065
 
2066 2066
 
2067
-    /**
2068
-     * @param array $all_datetimes
2069
-     * @param array $all_tickets
2070
-     * @return mixed
2071
-     * @throws ReflectionException
2072
-     * @throws InvalidArgumentException
2073
-     * @throws InvalidInterfaceException
2074
-     * @throws InvalidDataTypeException
2075
-     * @throws DomainException
2076
-     * @throws EE_Error
2077
-     */
2078
-    protected function _get_ticket_js_structure($all_datetimes = array(), $all_tickets = array())
2079
-    {
2080
-        $template_args = array(
2081
-            'default_datetime_edit_row'                => $this->_get_dtt_edit_row(
2082
-                'DTTNUM',
2083
-                null,
2084
-                true,
2085
-                $all_datetimes
2086
-            ),
2087
-            'default_ticket_row'                       => $this->_get_ticket_row(
2088
-                'TICKETNUM',
2089
-                null,
2090
-                array(),
2091
-                array(),
2092
-                true
2093
-            ),
2094
-            'default_price_row'                        => $this->_get_ticket_price_row(
2095
-                'TICKETNUM',
2096
-                'PRICENUM',
2097
-                null,
2098
-                true,
2099
-                null
2100
-            ),
2101
-            'default_price_rows'                       => '',
2102
-            'default_base_price_amount'                => 0,
2103
-            'default_base_price_name'                  => '',
2104
-            'default_base_price_description'           => '',
2105
-            'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2106
-                'TICKETNUM',
2107
-                'PRICENUM',
2108
-                null,
2109
-                true
2110
-            ),
2111
-            'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2112
-                'DTTNUM',
2113
-                null,
2114
-                array(),
2115
-                array(),
2116
-                true
2117
-            ),
2118
-            'existing_available_datetime_tickets_list' => '',
2119
-            'existing_available_ticket_datetimes_list' => '',
2120
-            'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2121
-                'DTTNUM',
2122
-                'TICKETNUM',
2123
-                null,
2124
-                null,
2125
-                array(),
2126
-                true
2127
-            ),
2128
-            'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2129
-                'DTTNUM',
2130
-                'TICKETNUM',
2131
-                null,
2132
-                null,
2133
-                array(),
2134
-                true
2135
-            ),
2136
-        );
2137
-        $ticket_row    = 1;
2138
-        foreach ($all_tickets as $ticket) {
2139
-            $template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2140
-                'DTTNUM',
2141
-                $ticket_row,
2142
-                null,
2143
-                $ticket,
2144
-                array(),
2145
-                true
2146
-            );
2147
-            $ticket_row++;
2148
-        }
2149
-        $datetime_row = 1;
2150
-        foreach ($all_datetimes as $datetime) {
2151
-            $template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2152
-                $datetime_row,
2153
-                'TICKETNUM',
2154
-                $datetime,
2155
-                null,
2156
-                array(),
2157
-                true
2158
-            );
2159
-            $datetime_row++;
2160
-        }
2161
-        /** @var EEM_Price $price_model */
2162
-        $price_model    = EE_Registry::instance()->load_model('Price');
2163
-        $default_prices = $price_model->get_all_default_prices();
2164
-        $price_row      = 1;
2165
-        foreach ($default_prices as $price) {
2166
-            if (! $price instanceof EE_Price) {
2167
-                continue;
2168
-            }
2169
-            if ($price->is_base_price()) {
2170
-                $template_args['default_base_price_amount']      = $price->get_pretty(
2171
-                    'PRC_amount',
2172
-                    'localized_float'
2173
-                );
2174
-                $template_args['default_base_price_name']        = $price->get('PRC_name');
2175
-                $template_args['default_base_price_description'] = $price->get('PRC_desc');
2176
-                $price_row++;
2177
-                continue;
2178
-            }
2179
-            $show_trash                          = ! ((count($default_prices) > 1 && $price_row === 1)
2180
-                                                      || count($default_prices) === 1);
2181
-            $show_create                         = ! (count($default_prices) > 1
2182
-                                                      && count($default_prices)
2183
-                                                         !== $price_row);
2184
-            $template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2185
-                'TICKETNUM',
2186
-                $price_row,
2187
-                $price,
2188
-                true,
2189
-                null,
2190
-                $show_trash,
2191
-                $show_create
2192
-            );
2193
-            $price_row++;
2194
-        }
2195
-        $template_args = apply_filters(
2196
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2197
-            $template_args,
2198
-            $all_datetimes,
2199
-            $all_tickets,
2200
-            $this->_is_creating_event
2201
-        );
2202
-        return EEH_Template::display_template(
2203
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2204
-            $template_args,
2205
-            true
2206
-        );
2207
-    }
2067
+	/**
2068
+	 * @param array $all_datetimes
2069
+	 * @param array $all_tickets
2070
+	 * @return mixed
2071
+	 * @throws ReflectionException
2072
+	 * @throws InvalidArgumentException
2073
+	 * @throws InvalidInterfaceException
2074
+	 * @throws InvalidDataTypeException
2075
+	 * @throws DomainException
2076
+	 * @throws EE_Error
2077
+	 */
2078
+	protected function _get_ticket_js_structure($all_datetimes = array(), $all_tickets = array())
2079
+	{
2080
+		$template_args = array(
2081
+			'default_datetime_edit_row'                => $this->_get_dtt_edit_row(
2082
+				'DTTNUM',
2083
+				null,
2084
+				true,
2085
+				$all_datetimes
2086
+			),
2087
+			'default_ticket_row'                       => $this->_get_ticket_row(
2088
+				'TICKETNUM',
2089
+				null,
2090
+				array(),
2091
+				array(),
2092
+				true
2093
+			),
2094
+			'default_price_row'                        => $this->_get_ticket_price_row(
2095
+				'TICKETNUM',
2096
+				'PRICENUM',
2097
+				null,
2098
+				true,
2099
+				null
2100
+			),
2101
+			'default_price_rows'                       => '',
2102
+			'default_base_price_amount'                => 0,
2103
+			'default_base_price_name'                  => '',
2104
+			'default_base_price_description'           => '',
2105
+			'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2106
+				'TICKETNUM',
2107
+				'PRICENUM',
2108
+				null,
2109
+				true
2110
+			),
2111
+			'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2112
+				'DTTNUM',
2113
+				null,
2114
+				array(),
2115
+				array(),
2116
+				true
2117
+			),
2118
+			'existing_available_datetime_tickets_list' => '',
2119
+			'existing_available_ticket_datetimes_list' => '',
2120
+			'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2121
+				'DTTNUM',
2122
+				'TICKETNUM',
2123
+				null,
2124
+				null,
2125
+				array(),
2126
+				true
2127
+			),
2128
+			'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2129
+				'DTTNUM',
2130
+				'TICKETNUM',
2131
+				null,
2132
+				null,
2133
+				array(),
2134
+				true
2135
+			),
2136
+		);
2137
+		$ticket_row    = 1;
2138
+		foreach ($all_tickets as $ticket) {
2139
+			$template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2140
+				'DTTNUM',
2141
+				$ticket_row,
2142
+				null,
2143
+				$ticket,
2144
+				array(),
2145
+				true
2146
+			);
2147
+			$ticket_row++;
2148
+		}
2149
+		$datetime_row = 1;
2150
+		foreach ($all_datetimes as $datetime) {
2151
+			$template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2152
+				$datetime_row,
2153
+				'TICKETNUM',
2154
+				$datetime,
2155
+				null,
2156
+				array(),
2157
+				true
2158
+			);
2159
+			$datetime_row++;
2160
+		}
2161
+		/** @var EEM_Price $price_model */
2162
+		$price_model    = EE_Registry::instance()->load_model('Price');
2163
+		$default_prices = $price_model->get_all_default_prices();
2164
+		$price_row      = 1;
2165
+		foreach ($default_prices as $price) {
2166
+			if (! $price instanceof EE_Price) {
2167
+				continue;
2168
+			}
2169
+			if ($price->is_base_price()) {
2170
+				$template_args['default_base_price_amount']      = $price->get_pretty(
2171
+					'PRC_amount',
2172
+					'localized_float'
2173
+				);
2174
+				$template_args['default_base_price_name']        = $price->get('PRC_name');
2175
+				$template_args['default_base_price_description'] = $price->get('PRC_desc');
2176
+				$price_row++;
2177
+				continue;
2178
+			}
2179
+			$show_trash                          = ! ((count($default_prices) > 1 && $price_row === 1)
2180
+													  || count($default_prices) === 1);
2181
+			$show_create                         = ! (count($default_prices) > 1
2182
+													  && count($default_prices)
2183
+														 !== $price_row);
2184
+			$template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2185
+				'TICKETNUM',
2186
+				$price_row,
2187
+				$price,
2188
+				true,
2189
+				null,
2190
+				$show_trash,
2191
+				$show_create
2192
+			);
2193
+			$price_row++;
2194
+		}
2195
+		$template_args = apply_filters(
2196
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2197
+			$template_args,
2198
+			$all_datetimes,
2199
+			$all_tickets,
2200
+			$this->_is_creating_event
2201
+		);
2202
+		return EEH_Template::display_template(
2203
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2204
+			$template_args,
2205
+			true
2206
+		);
2207
+	}
2208 2208
 } //end class espresso_events_Pricing_Hooks
Please login to merge, or discard this patch.
Spacing   +90 added lines, -90 removed lines patch added patch discarded remove patch
@@ -52,7 +52,7 @@  discard block
 block discarded – undo
52 52
     {
53 53
         $this->_name = 'pricing';
54 54
         //capability check
55
-        if (! EE_Registry::instance()->CAP->current_user_can(
55
+        if ( ! EE_Registry::instance()->CAP->current_user_can(
56 56
             'ee_read_default_prices',
57 57
             'advanced_ticket_datetime_metabox'
58 58
         )) {
@@ -80,7 +80,7 @@  discard block
 block discarded – undo
80 80
     protected function _setup_metaboxes()
81 81
     {
82 82
         //if we were going to add our own metaboxes we'd use the below.
83
-        $this->_metaboxes        = array(
83
+        $this->_metaboxes = array(
84 84
             0 => array(
85 85
                 'page_route' => array('edit', 'create_new'),
86 86
                 'func'       => 'pricing_metabox',
@@ -152,7 +152,7 @@  discard block
 block discarded – undo
152 152
             );
153 153
             $msg .= '</p><ul>';
154 154
             foreach ($format_validation as $error) {
155
-                $msg .= '<li>' . $error . '</li>';
155
+                $msg .= '<li>'.$error.'</li>';
156 156
             }
157 157
             $msg .= '</ul><p>';
158 158
             $msg .= sprintf(
@@ -181,11 +181,11 @@  discard block
 block discarded – undo
181 181
         $this->_scripts_styles = array(
182 182
             'registers'   => array(
183 183
                 'ee-tickets-datetimes-css' => array(
184
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
184
+                    'url'  => PRICING_ASSETS_URL.'event-tickets-datetimes.css',
185 185
                     'type' => 'css',
186 186
                 ),
187 187
                 'ee-dtt-ticket-metabox'    => array(
188
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
188
+                    'url'     => PRICING_ASSETS_URL.'ee-datetime-ticket-metabox.js',
189 189
                     'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
190 190
                 ),
191 191
             ),
@@ -209,9 +209,9 @@  discard block
 block discarded – undo
209 209
                             'event_espresso'
210 210
                         ),
211 211
                         'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
212
-                                                     . esc_html__('Cancel', 'event_espresso') . '</button>',
212
+                                                     . esc_html__('Cancel', 'event_espresso').'</button>',
213 213
                         'close_button'            => '<button class="button-secondary ee-modal-cancel">'
214
-                                                     . esc_html__('Close', 'event_espresso') . '</button>',
214
+                                                     . esc_html__('Close', 'event_espresso').'</button>',
215 215
                         'single_warning_from_tkt' => esc_html__(
216 216
                             'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
217 217
                             'event_espresso'
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
                             'event_espresso'
222 222
                         ),
223 223
                         'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
224
-                                                     . esc_html__('Dismiss', 'event_espresso') . '</button>',
224
+                                                     . esc_html__('Dismiss', 'event_espresso').'</button>',
225 225
                     ),
226 226
                     'DTT_ERROR_MSG'         => array(
227 227
                         'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
@@ -259,7 +259,7 @@  discard block
 block discarded – undo
259 259
     {
260 260
         foreach ($update_callbacks as $key => $callback) {
261 261
             if ($callback[1] === '_default_tickets_update') {
262
-                unset($update_callbacks[ $key ]);
262
+                unset($update_callbacks[$key]);
263 263
             }
264 264
         }
265 265
         $update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
@@ -316,8 +316,8 @@  discard block
 block discarded – undo
316 316
         }
317 317
         foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
318 318
             //trim all values to ensure any excess whitespace is removed.
319
-            $datetime_data                = array_map(
320
-                function ($datetime_data)
319
+            $datetime_data = array_map(
320
+                function($datetime_data)
321 321
                 {
322 322
                     return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
323 323
                 },
@@ -327,7 +327,7 @@  discard block
 block discarded – undo
327 327
                                             && ! empty($datetime_data['DTT_EVT_end'])
328 328
                 ? $datetime_data['DTT_EVT_end']
329 329
                 : $datetime_data['DTT_EVT_start'];
330
-            $datetime_values              = array(
330
+            $datetime_values = array(
331 331
                 'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
332 332
                     ? $datetime_data['DTT_ID']
333 333
                     : null,
@@ -348,7 +348,7 @@  discard block
 block discarded – undo
348 348
             );
349 349
             // if we have an id then let's get existing object first and then set the new values.
350 350
             // Otherwise we instantiate a new object for save.
351
-            if (! empty($datetime_data['DTT_ID'])) {
351
+            if ( ! empty($datetime_data['DTT_ID'])) {
352 352
                 $datetime = EE_Registry::instance()
353 353
                                        ->load_model('Datetime', array($timezone))
354 354
                                        ->get_one_by_ID($datetime_data['DTT_ID']);
@@ -362,7 +362,7 @@  discard block
 block discarded – undo
362 362
                 // after the add_relation_to() the autosave replaces it.
363 363
                 // We need to do this so we dont' TRASH the parent DTT.
364 364
                 // (save the ID for both key and value to avoid duplications)
365
-                $saved_dtt_ids[ $datetime->ID() ] = $datetime->ID();
365
+                $saved_dtt_ids[$datetime->ID()] = $datetime->ID();
366 366
             } else {
367 367
                 $datetime = EE_Registry::instance()->load_class(
368 368
                     'Datetime',
@@ -391,8 +391,8 @@  discard block
 block discarded – undo
391 391
             // because it is possible there was a new one created for the autosave.
392 392
             // (save the ID for both key and value to avoid duplications)
393 393
             $DTT_ID                   = $datetime->ID();
394
-            $saved_dtt_ids[ $DTT_ID ] = $DTT_ID;
395
-            $saved_dtt_objs[ $row ]   = $datetime;
394
+            $saved_dtt_ids[$DTT_ID] = $DTT_ID;
395
+            $saved_dtt_objs[$row]   = $datetime;
396 396
             //todo if ANY of these updates fail then we want the appropriate global error message.
397 397
         }
398 398
         $event->save();
@@ -457,13 +457,13 @@  discard block
 block discarded – undo
457 457
             $update_prices = $create_new_TKT = false;
458 458
             // figure out what datetimes were added to the ticket
459 459
             // and what datetimes were removed from the ticket in the session.
460
-            $starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
461
-            $tkt_dtt_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
460
+            $starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][$row]);
461
+            $tkt_dtt_rows          = explode(',', $data['ticket_datetime_rows'][$row]);
462 462
             $datetimes_added       = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
463 463
             $datetimes_removed     = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
464 464
             // trim inputs to ensure any excess whitespace is removed.
465 465
             $tkt = array_map(
466
-                function ($ticket_data)
466
+                function($ticket_data)
467 467
                 {
468 468
                     return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
469 469
                 },
@@ -486,8 +486,8 @@  discard block
 block discarded – undo
486 486
             $base_price_id = isset($tkt['TKT_base_price_ID'])
487 487
                 ? $tkt['TKT_base_price_ID']
488 488
                 : 0;
489
-            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
490
-                ? $data['edit_prices'][ $row ]
489
+            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][$row])
490
+                ? $data['edit_prices'][$row]
491 491
                 : array();
492 492
             $now           = null;
493 493
             if (empty($tkt['TKT_start_date'])) {
@@ -499,7 +499,7 @@  discard block
 block discarded – undo
499 499
                 /**
500 500
                  * set the TKT_end_date to the first datetime attached to the ticket.
501 501
                  */
502
-                $first_dtt           = $saved_datetimes[ reset($tkt_dtt_rows) ];
502
+                $first_dtt           = $saved_datetimes[reset($tkt_dtt_rows)];
503 503
                 $tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
504 504
             }
505 505
             $TKT_values = array(
@@ -600,7 +600,7 @@  discard block
 block discarded – undo
600 600
                 if ($ticket instanceof EE_Ticket) {
601 601
                     // make sure ticket has an ID of setting relations won't work
602 602
                     $ticket->save();
603
-                    $ticket        = $this->_update_ticket_datetimes(
603
+                    $ticket = $this->_update_ticket_datetimes(
604 604
                         $ticket,
605 605
                         $saved_datetimes,
606 606
                         $datetimes_added,
@@ -634,7 +634,7 @@  discard block
 block discarded – undo
634 634
             //need to make sue that the TKT_price is accurate after saving the prices.
635 635
             $ticket->ensure_TKT_Price_correct();
636 636
             //handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
637
-            if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
637
+            if ( ! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
638 638
                 $update_prices = true;
639 639
                 $new_default   = clone $ticket;
640 640
                 $new_default->set('TKT_ID', 0);
@@ -679,7 +679,7 @@  discard block
 block discarded – undo
679 679
                 //save new TKT
680 680
                 $new_tkt->save();
681 681
                 //add new ticket to array
682
-                $saved_tickets[ $new_tkt->ID() ] = $new_tkt;
682
+                $saved_tickets[$new_tkt->ID()] = $new_tkt;
683 683
                 do_action(
684 684
                     'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
685 685
                     $new_tkt,
@@ -689,7 +689,7 @@  discard block
 block discarded – undo
689 689
                 );
690 690
             } else {
691 691
                 //add tkt to saved tkts
692
-                $saved_tickets[ $ticket->ID() ] = $ticket;
692
+                $saved_tickets[$ticket->ID()] = $ticket;
693 693
                 do_action(
694 694
                     'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
695 695
                     $ticket,
@@ -756,33 +756,33 @@  discard block
 block discarded – undo
756 756
         // to start we have to add the ticket to all the datetimes its supposed to be with,
757 757
         // and removing the ticket from datetimes it got removed from.
758 758
         // first let's add datetimes
759
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
759
+        if ( ! empty($added_datetimes) && is_array($added_datetimes)) {
760 760
             foreach ($added_datetimes as $row_id) {
761 761
                 $row_id = (int) $row_id;
762
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
763
-                    $ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
762
+                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
763
+                    $ticket->_add_relation_to($saved_datetimes[$row_id], 'Datetime');
764 764
                     // Is this an existing ticket (has an ID) and does it have any sold?
765 765
                     // If so, then we need to add that to the DTT sold because this DTT is getting added.
766 766
                     if ($ticket->ID() && $ticket->sold() > 0) {
767
-                        $saved_datetimes[ $row_id ]->increase_sold($ticket->sold());
768
-                        $saved_datetimes[ $row_id ]->save();
767
+                        $saved_datetimes[$row_id]->increase_sold($ticket->sold());
768
+                        $saved_datetimes[$row_id]->save();
769 769
                     }
770 770
                 }
771 771
             }
772 772
         }
773 773
         // then remove datetimes
774
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
774
+        if ( ! empty($removed_datetimes) && is_array($removed_datetimes)) {
775 775
             foreach ($removed_datetimes as $row_id) {
776 776
                 $row_id = (int) $row_id;
777 777
                 // its entirely possible that a datetime got deleted (instead of just removed from relationship.
778 778
                 // So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
779
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
780
-                    $ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
779
+                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
780
+                    $ticket->_remove_relation_to($saved_datetimes[$row_id], 'Datetime');
781 781
                     // Is this an existing ticket (has an ID) and does it have any sold?
782 782
                     // If so, then we need to remove it's sold from the DTT_sold.
783 783
                     if ($ticket->ID() && $ticket->sold() > 0) {
784
-                        $saved_datetimes[ $row_id ]->decrease_sold($ticket->sold());
785
-                        $saved_datetimes[ $row_id ]->save();
784
+                        $saved_datetimes[$row_id]->decrease_sold($ticket->sold());
785
+                        $saved_datetimes[$row_id]->save();
786 786
                     }
787 787
                 }
788 788
             }
@@ -895,7 +895,7 @@  discard block
 block discarded – undo
895 895
             );
896 896
         }
897 897
         //possibly need to save tkt
898
-        if (! $ticket->ID()) {
898
+        if ( ! $ticket->ID()) {
899 899
             $ticket->save();
900 900
         }
901 901
         foreach ($prices as $row => $prc) {
@@ -929,17 +929,17 @@  discard block
 block discarded – undo
929 929
                 }
930 930
             }
931 931
             $price->save();
932
-            $updated_prices[ $price->ID() ] = $price;
932
+            $updated_prices[$price->ID()] = $price;
933 933
             $ticket->_add_relation_to($price, 'Price');
934 934
         }
935 935
         //now let's remove any prices that got removed from the ticket
936
-        if (! empty ($current_prices_on_ticket)) {
936
+        if ( ! empty ($current_prices_on_ticket)) {
937 937
             $current          = array_keys($current_prices_on_ticket);
938 938
             $updated          = array_keys($updated_prices);
939 939
             $prices_to_remove = array_diff($current, $updated);
940
-            if (! empty($prices_to_remove)) {
940
+            if ( ! empty($prices_to_remove)) {
941 941
                 foreach ($prices_to_remove as $prc_id) {
942
-                    $p = $current_prices_on_ticket[ $prc_id ];
942
+                    $p = $current_prices_on_ticket[$prc_id];
943 943
                     $ticket->_remove_relation_to($p, 'Price');
944 944
                     //delete permanently the price
945 945
                     $p->delete_permanently();
@@ -1028,7 +1028,7 @@  discard block
 block discarded – undo
1028 1028
             'ee_collapsible_status'    => ' ee-collapsible-open'
1029 1029
             //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
1030 1030
         );
1031
-        $timezone           = $event instanceof EE_Event ? $event->timezone_string() : null;
1031
+        $timezone = $event instanceof EE_Event ? $event->timezone_string() : null;
1032 1032
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1033 1033
         /**
1034 1034
          * 1. Start with retrieving Datetimes
@@ -1090,18 +1090,18 @@  discard block
 block discarded – undo
1090 1090
                 $TKT_ID     = $ticket->get('TKT_ID');
1091 1091
                 $ticket_row = $ticket->get('TKT_row');
1092 1092
                 //we only want unique tickets in our final display!!
1093
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1093
+                if ( ! in_array($TKT_ID, $existing_ticket_ids, true)) {
1094 1094
                     $existing_ticket_ids[] = $TKT_ID;
1095 1095
                     $all_tickets[]         = $ticket;
1096 1096
                 }
1097 1097
                 //temporary cache of this ticket info for this datetime for later processing of datetime rows.
1098
-                $datetime_tickets[ $DTT_ID ][] = $ticket_row;
1098
+                $datetime_tickets[$DTT_ID][] = $ticket_row;
1099 1099
                 //temporary cache of this datetime info for this ticket for later processing of ticket rows.
1100 1100
                 if (
1101
-                    ! isset($ticket_datetimes[ $TKT_ID ])
1102
-                    || ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1101
+                    ! isset($ticket_datetimes[$TKT_ID])
1102
+                    || ! in_array($datetime_row, $ticket_datetimes[$TKT_ID], true)
1103 1103
                 ) {
1104
-                    $ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1104
+                    $ticket_datetimes[$TKT_ID][] = $datetime_row;
1105 1105
                 }
1106 1106
             }
1107 1107
             $datetime_row++;
@@ -1112,7 +1112,7 @@  discard block
 block discarded – undo
1112 1112
         //sort $all_tickets by order
1113 1113
         usort(
1114 1114
             $all_tickets,
1115
-            function (EE_Ticket $a, EE_Ticket $b)
1115
+            function(EE_Ticket $a, EE_Ticket $b)
1116 1116
             {
1117 1117
                 $a_order = (int) $a->get('TKT_order');
1118 1118
                 $b_order = (int) $b->get('TKT_order');
@@ -1151,7 +1151,7 @@  discard block
 block discarded – undo
1151 1151
         }
1152 1152
         $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1153 1153
         EEH_Template::display_template(
1154
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1154
+            PRICING_TEMPLATE_PATH.'event_tickets_metabox_main.template.php',
1155 1155
             $main_template_args
1156 1156
         );
1157 1157
     }
@@ -1193,7 +1193,7 @@  discard block
 block discarded – undo
1193 1193
             'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1194 1194
         );
1195 1195
         return EEH_Template::display_template(
1196
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1196
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_row_wrapper.template.php',
1197 1197
             $dtt_display_template_args,
1198 1198
             true
1199 1199
         );
@@ -1262,7 +1262,7 @@  discard block
 block discarded – undo
1262 1262
             $this->_is_creating_event
1263 1263
         );
1264 1264
         return EEH_Template::display_template(
1265
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1265
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_edit_row.template.php',
1266 1266
             $template_args,
1267 1267
             true
1268 1268
         );
@@ -1303,7 +1303,7 @@  discard block
 block discarded – undo
1303 1303
             'DTT_ID'                            => $default ? '' : $datetime->ID(),
1304 1304
         );
1305 1305
         //need to setup the list items (but only if this isn't a default skeleton setup)
1306
-        if (! $default) {
1306
+        if ( ! $default) {
1307 1307
             $ticket_row = 1;
1308 1308
             foreach ($all_tickets as $ticket) {
1309 1309
                 $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
@@ -1329,7 +1329,7 @@  discard block
 block discarded – undo
1329 1329
             $this->_is_creating_event
1330 1330
         );
1331 1331
         return EEH_Template::display_template(
1332
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1332
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_attached_tickets_row.template.php',
1333 1333
             $template_args,
1334 1334
             true
1335 1335
         );
@@ -1355,8 +1355,8 @@  discard block
 block discarded – undo
1355 1355
         $datetime_tickets = array(),
1356 1356
         $default
1357 1357
     ) {
1358
-        $dtt_tkts      = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1359
-            ? $datetime_tickets[ $datetime->ID() ]
1358
+        $dtt_tkts      = $datetime instanceof EE_Datetime && isset($datetime_tickets[$datetime->ID()])
1359
+            ? $datetime_tickets[$datetime->ID()]
1360 1360
             : array();
1361 1361
         $display_row   = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1362 1362
         $no_ticket     = $default && empty($ticket);
@@ -1377,8 +1377,8 @@  discard block
 block discarded – undo
1377 1377
                 ? 'TKTNAME'
1378 1378
                 : $ticket->get('TKT_name'),
1379 1379
             'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1380
-                ? ' tkt-status-' . EE_Ticket::onsale
1381
-                : ' tkt-status-' . $ticket->ticket_status(),
1380
+                ? ' tkt-status-'.EE_Ticket::onsale
1381
+                : ' tkt-status-'.$ticket->ticket_status(),
1382 1382
         );
1383 1383
         //filter template args
1384 1384
         $template_args = apply_filters(
@@ -1393,7 +1393,7 @@  discard block
 block discarded – undo
1393 1393
             $this->_is_creating_event
1394 1394
         );
1395 1395
         return EEH_Template::display_template(
1396
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1396
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_dtt_tickets_list.template.php',
1397 1397
             $template_args,
1398 1398
             true
1399 1399
         );
@@ -1445,19 +1445,19 @@  discard block
 block discarded – undo
1445 1445
         // (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1446 1446
         // This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1447 1447
         $default_dtt      = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1448
-        $tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1449
-            ? $ticket_datetimes[ $ticket->ID() ]
1448
+        $tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1449
+            ? $ticket_datetimes[$ticket->ID()]
1450 1450
             : array();
1451 1451
         $ticket_subtotal  = $default ? 0 : $ticket->get_ticket_subtotal();
1452 1452
         $base_price       = $default ? null : $ticket->base_price();
1453 1453
         $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1454 1454
         //breaking out complicated condition for ticket_status
1455 1455
         if ($default) {
1456
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1456
+            $ticket_status_class = ' tkt-status-'.EE_Ticket::onsale;
1457 1457
         } else {
1458 1458
             $ticket_status_class = $ticket->is_default()
1459
-                ? ' tkt-status-' . EE_Ticket::onsale
1460
-                : ' tkt-status-' . $ticket->ticket_status();
1459
+                ? ' tkt-status-'.EE_Ticket::onsale
1460
+                : ' tkt-status-'.$ticket->ticket_status();
1461 1461
         }
1462 1462
         //breaking out complicated condition for TKT_taxable
1463 1463
         if ($default) {
@@ -1482,7 +1482,7 @@  discard block
 block discarded – undo
1482 1482
                 $TKT_min = '';
1483 1483
             }
1484 1484
         }
1485
-        $template_args                 = array(
1485
+        $template_args = array(
1486 1486
             'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1487 1487
             'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1488 1488
             //on initial page load this will always be the correct order.
@@ -1549,7 +1549,7 @@  discard block
 block discarded – undo
1549 1549
                 : ' style="display:none;"',
1550 1550
             'show_price_mod_button'         => count($prices) > 1
1551 1551
                                                || ($default && $count_price_mods > 0)
1552
-                                               || (! $default && $ticket->deleted())
1552
+                                               || ( ! $default && $ticket->deleted())
1553 1553
                 ? ' style="display:none;"'
1554 1554
                 : '',
1555 1555
             'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
@@ -1591,7 +1591,7 @@  discard block
 block discarded – undo
1591 1591
             //if empty then the start date will be now.
1592 1592
             $template_args['TKT_start_date']   = date($this->_date_time_format,
1593 1593
                 current_time('timestamp'));
1594
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1594
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1595 1595
         }
1596 1596
         if (empty($template_args['TKT_end_date'])) {
1597 1597
             //get the earliest datetime (if present);
@@ -1601,7 +1601,7 @@  discard block
 block discarded – undo
1601 1601
                     array('order_by' => array('DTT_EVT_start' => 'ASC'))
1602 1602
                 )
1603 1603
                 : null;
1604
-            if (! empty($earliest_dtt)) {
1604
+            if ( ! empty($earliest_dtt)) {
1605 1605
                 $template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1606 1606
                     'DTT_EVT_start',
1607 1607
                     $this->_date_time_format
@@ -1615,10 +1615,10 @@  discard block
 block discarded – undo
1615 1615
                     )
1616 1616
                 );
1617 1617
             }
1618
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1618
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1619 1619
         }
1620 1620
         //generate ticket_datetime items
1621
-        if (! $default) {
1621
+        if ( ! $default) {
1622 1622
             $datetime_row = 1;
1623 1623
             foreach ($all_datetimes as $datetime) {
1624 1624
                 $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
@@ -1634,7 +1634,7 @@  discard block
 block discarded – undo
1634 1634
         }
1635 1635
         $price_row = 1;
1636 1636
         foreach ($prices as $price) {
1637
-            if (! $price instanceof EE_Price) {
1637
+            if ( ! $price instanceof EE_Price) {
1638 1638
                 continue;
1639 1639
             }
1640 1640
             if ($price->is_base_price()) {
@@ -1667,7 +1667,7 @@  discard block
 block discarded – undo
1667 1667
             $this->_is_creating_event
1668 1668
         );
1669 1669
         return EEH_Template::display_template(
1670
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1670
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_row.template.php',
1671 1671
             $template_args,
1672 1672
             true
1673 1673
         );
@@ -1706,8 +1706,8 @@  discard block
 block discarded – undo
1706 1706
                 $ticket,
1707 1707
                 $this->_is_creating_event
1708 1708
             );
1709
-            $tax_rows      .= EEH_Template::display_template(
1710
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1709
+            $tax_rows .= EEH_Template::display_template(
1710
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_tax_row.template.php',
1711 1711
                 $template_args,
1712 1712
                 true
1713 1713
             );
@@ -1827,7 +1827,7 @@  discard block
 block discarded – undo
1827 1827
             $this->_is_creating_event
1828 1828
         );
1829 1829
         return EEH_Template::display_template(
1830
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1830
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_price_row.template.php',
1831 1831
             $template_args,
1832 1832
             true
1833 1833
         );
@@ -1897,7 +1897,7 @@  discard block
 block discarded – undo
1897 1897
             $this->_is_creating_event
1898 1898
         );
1899 1899
         return EEH_Template::display_template(
1900
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1900
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_type_base.template.php',
1901 1901
             $template_args,
1902 1902
             true
1903 1903
         );
@@ -1927,7 +1927,7 @@  discard block
 block discarded – undo
1927 1927
     ) {
1928 1928
         $select_name = $default && ! $price instanceof EE_Price
1929 1929
             ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1930
-            : 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1930
+            : 'edit_prices['.$ticket_row.']['.$price_row.'][PRT_ID]';
1931 1931
         /** @var EEM_Price_Type $price_type_model */
1932 1932
         $price_type_model       = EE_Registry::instance()->load_model('Price_Type');
1933 1933
         $price_types            = $price_type_model->get_all(array(
@@ -1945,23 +1945,23 @@  discard block
 block discarded – undo
1945 1945
         $price_option_spans     = '';
1946 1946
         //setup price types for selector
1947 1947
         foreach ($price_types as $price_type) {
1948
-            if (! $price_type instanceof EE_Price_Type) {
1948
+            if ( ! $price_type instanceof EE_Price_Type) {
1949 1949
                 continue;
1950 1950
             }
1951
-            $all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
1951
+            $all_price_types[$price_type->ID()] = $price_type->get('PRT_name');
1952 1952
             //while we're in the loop let's setup the option spans used by js
1953
-            $span_args          = array(
1953
+            $span_args = array(
1954 1954
                 'PRT_ID'         => $price_type->ID(),
1955 1955
                 'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1956 1956
                 'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1957 1957
             );
1958 1958
             $price_option_spans .= EEH_Template::display_template(
1959
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1959
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_option_span.template.php',
1960 1960
                 $span_args,
1961 1961
                 true
1962 1962
             );
1963 1963
         }
1964
-        $select_name               = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
1964
+        $select_name               = $disabled ? 'archive_price['.$ticket_row.']['.$price_row.'][PRT_ID]'
1965 1965
             : $select_name;
1966 1966
         $select_input              = new EE_Select_Input(
1967 1967
             $all_price_types,
@@ -1987,7 +1987,7 @@  discard block
 block discarded – undo
1987 1987
             'price_selected_is_percent' => $price_selected_is_percent,
1988 1988
             'disabled'                  => $disabled,
1989 1989
         );
1990
-        $template_args             = apply_filters(
1990
+        $template_args = apply_filters(
1991 1991
             'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1992 1992
             $template_args,
1993 1993
             $ticket_row,
@@ -1998,7 +1998,7 @@  discard block
 block discarded – undo
1998 1998
             $this->_is_creating_event
1999 1999
         );
2000 2000
         return EEH_Template::display_template(
2001
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
2001
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_modifier_selector.template.php',
2002 2002
             $template_args,
2003 2003
             true
2004 2004
         );
@@ -2024,8 +2024,8 @@  discard block
 block discarded – undo
2024 2024
         $ticket_datetimes = array(),
2025 2025
         $default
2026 2026
     ) {
2027
-        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2028
-            ? $ticket_datetimes[ $ticket->ID() ]
2027
+        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
2028
+            ? $ticket_datetimes[$ticket->ID()]
2029 2029
             : array();
2030 2030
         $template_args = array(
2031 2031
             'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
@@ -2057,7 +2057,7 @@  discard block
 block discarded – undo
2057 2057
             $this->_is_creating_event
2058 2058
         );
2059 2059
         return EEH_Template::display_template(
2060
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2060
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2061 2061
             $template_args,
2062 2062
             true
2063 2063
         );
@@ -2134,7 +2134,7 @@  discard block
 block discarded – undo
2134 2134
                 true
2135 2135
             ),
2136 2136
         );
2137
-        $ticket_row    = 1;
2137
+        $ticket_row = 1;
2138 2138
         foreach ($all_tickets as $ticket) {
2139 2139
             $template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2140 2140
                 'DTTNUM',
@@ -2163,11 +2163,11 @@  discard block
 block discarded – undo
2163 2163
         $default_prices = $price_model->get_all_default_prices();
2164 2164
         $price_row      = 1;
2165 2165
         foreach ($default_prices as $price) {
2166
-            if (! $price instanceof EE_Price) {
2166
+            if ( ! $price instanceof EE_Price) {
2167 2167
                 continue;
2168 2168
             }
2169 2169
             if ($price->is_base_price()) {
2170
-                $template_args['default_base_price_amount']      = $price->get_pretty(
2170
+                $template_args['default_base_price_amount'] = $price->get_pretty(
2171 2171
                     'PRC_amount',
2172 2172
                     'localized_float'
2173 2173
                 );
@@ -2200,7 +2200,7 @@  discard block
 block discarded – undo
2200 2200
             $this->_is_creating_event
2201 2201
         );
2202 2202
         return EEH_Template::display_template(
2203
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2203
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_js_structure.template.php',
2204 2204
             $template_args,
2205 2205
             true
2206 2206
         );
Please login to merge, or discard this patch.
core/db_classes/EE_Base_Class.class.php 3 patches
Doc Comments   +10 added lines, -9 removed lines patch added patch discarded remove patch
@@ -712,7 +712,7 @@  discard block
 block discarded – undo
712 712
      *
713 713
      * @param \EE_Datetime_Field $datetime_field
714 714
      * @param bool               $pretty
715
-     * @param null               $date_or_time
715
+     * @param string|null               $date_or_time
716 716
      * @return void
717 717
      * @throws InvalidArgumentException
718 718
      * @throws InvalidInterfaceException
@@ -1066,7 +1066,7 @@  discard block
 block discarded – undo
1066 1066
      *
1067 1067
      * @param null  $field_to_order_by  What field is being used as the reference point.
1068 1068
      * @param array $query_params       Any additional conditions on the query.
1069
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1069
+     * @param string  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070 1070
      *                                  you can indicate just the columns you want returned
1071 1071
      * @return array|EE_Base_Class
1072 1072
      * @throws ReflectionException
@@ -1095,7 +1095,7 @@  discard block
 block discarded – undo
1095 1095
      *
1096 1096
      * @param null  $field_to_order_by  What field is being used as the reference point.
1097 1097
      * @param array $query_params       Any additional conditions on the query.
1098
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1098
+     * @param string  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099 1099
      *                                  you can indicate just the column you want returned
1100 1100
      * @return array|EE_Base_Class
1101 1101
      * @throws ReflectionException
@@ -1178,7 +1178,7 @@  discard block
 block discarded – undo
1178 1178
      * This method simply returns the RAW unprocessed value for the given property in this class
1179 1179
      *
1180 1180
      * @param  string $field_name A valid fieldname
1181
-     * @return mixed              Whatever the raw value stored on the property is.
1181
+     * @return integer|null              Whatever the raw value stored on the property is.
1182 1182
      * @throws ReflectionException
1183 1183
      * @throws InvalidArgumentException
1184 1184
      * @throws InvalidInterfaceException
@@ -1526,7 +1526,7 @@  discard block
 block discarded – undo
1526 1526
      * sets the time on a datetime property
1527 1527
      *
1528 1528
      * @access protected
1529
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1529
+     * @param string $time      a valid time string for php datetime functions (or DateTime object)
1530 1530
      * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1531 1531
      * @throws ReflectionException
1532 1532
      * @throws InvalidArgumentException
@@ -1544,7 +1544,7 @@  discard block
 block discarded – undo
1544 1544
      * sets the date on a datetime property
1545 1545
      *
1546 1546
      * @access protected
1547
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1547
+     * @param string $date      a valid date string for php datetime functions ( or DateTime object)
1548 1548
      * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1549 1549
      * @throws ReflectionException
1550 1550
      * @throws InvalidArgumentException
@@ -1613,6 +1613,7 @@  discard block
 block discarded – undo
1613 1613
      * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1614 1614
      * @param string $prepend                  You can include something to prepend on the timestamp
1615 1615
      * @param string $append                   You can include something to append on the timestamp
1616
+     * @param string $args
1616 1617
      * @throws ReflectionException
1617 1618
      * @throws InvalidArgumentException
1618 1619
      * @throws InvalidInterfaceException
@@ -2066,7 +2067,7 @@  discard block
 block discarded – undo
2066 2067
      *
2067 2068
      * @param  array  $props_n_values   incoming array of properties and their values
2068 2069
      * @param  string $classname        the classname of the child class
2069
-     * @param null    $timezone
2070
+     * @param string|null    $timezone
2070 2071
      * @param array   $date_formats     incoming date_formats in an array where the first value is the
2071 2072
      *                                  date_format and the second value is the time format
2072 2073
      * @return mixed (EE_Base_Class|bool)
@@ -2153,7 +2154,7 @@  discard block
 block discarded – undo
2153 2154
      * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2154 2155
      *
2155 2156
      * @param string $model_classname
2156
-     * @param null   $timezone
2157
+     * @param string|null   $timezone
2157 2158
      * @return EEM_Base
2158 2159
      * @throws ReflectionException
2159 2160
      * @throws InvalidArgumentException
@@ -2773,7 +2774,7 @@  discard block
 block discarded – undo
2773 2774
      *
2774 2775
      * @param string $meta_key
2775 2776
      * @param mixed  $meta_value
2776
-     * @param mixed  $previous_value
2777
+     * @param boolean  $previous_value
2777 2778
      * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2778 2779
      *                  NOTE: if the values haven't changed, returns 0
2779 2780
      * @throws InvalidArgumentException
Please login to merge, or discard this patch.
Indentation   +3125 added lines, -3125 removed lines patch added patch discarded remove patch
@@ -15,3131 +15,3131 @@
 block discarded – undo
15 15
 abstract class EE_Base_Class
16 16
 {
17 17
 
18
-    /**
19
-     * This is an array of the original properties and values provided during construction
20
-     * of this model object. (keys are model field names, values are their values).
21
-     * This list is important to remember so that when we are merging data from the db, we know
22
-     * which values to override and which to not override.
23
-     *
24
-     * @var array
25
-     */
26
-    protected $_props_n_values_provided_in_constructor;
27
-
28
-    /**
29
-     * Timezone
30
-     * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
31
-     * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
32
-     * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
33
-     * access to it.
34
-     *
35
-     * @var string
36
-     */
37
-    protected $_timezone;
38
-
39
-    /**
40
-     * date format
41
-     * pattern or format for displaying dates
42
-     *
43
-     * @var string $_dt_frmt
44
-     */
45
-    protected $_dt_frmt;
46
-
47
-    /**
48
-     * time format
49
-     * pattern or format for displaying time
50
-     *
51
-     * @var string $_tm_frmt
52
-     */
53
-    protected $_tm_frmt;
54
-
55
-    /**
56
-     * This property is for holding a cached array of object properties indexed by property name as the key.
57
-     * The purpose of this is for setting a cache on properties that may have calculated values after a
58
-     * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
59
-     * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
60
-     *
61
-     * @var array
62
-     */
63
-    protected $_cached_properties = array();
64
-
65
-    /**
66
-     * An array containing keys of the related model, and values are either an array of related mode objects or a
67
-     * single
68
-     * related model object. see the model's _model_relations. The keys should match those specified. And if the
69
-     * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
70
-     * all others have an array)
71
-     *
72
-     * @var array
73
-     */
74
-    protected $_model_relations = array();
75
-
76
-    /**
77
-     * Array where keys are field names (see the model's _fields property) and values are their values. To see what
78
-     * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
79
-     *
80
-     * @var array
81
-     */
82
-    protected $_fields = array();
83
-
84
-    /**
85
-     * @var boolean indicating whether or not this model object is intended to ever be saved
86
-     * For example, we might create model objects intended to only be used for the duration
87
-     * of this request and to be thrown away, and if they were accidentally saved
88
-     * it would be a bug.
89
-     */
90
-    protected $_allow_persist = true;
91
-
92
-    /**
93
-     * @var boolean indicating whether or not this model object's properties have changed since construction
94
-     */
95
-    protected $_has_changes = false;
96
-
97
-    /**
98
-     * @var EEM_Base
99
-     */
100
-    protected $_model;
101
-
102
-    /**
103
-     * This is a cache of results from custom selections done on a query that constructs this entity. The only purpose
104
-     * for these values is for retrieval of the results, they are not further queryable and they are not persisted to
105
-     * the db.  They also do not automatically update if there are any changes to the data that produced their results.
106
-     * The format is a simple array of field_alias => field_value.  So for instance if a custom select was something
107
-     * like,  "Select COUNT(Registration.REG_ID) as Registration_Count ...", then the resulting value will be in this
108
-     * array as:
109
-     * array(
110
-     *  'Registration_Count' => 24
111
-     * );
112
-     * Note: if the custom select configuration for the query included a data type, the value will be in the data type
113
-     * provided for the query (@see EventEspresso\core\domain\values\model\CustomSelects::__construct phpdocs for more
114
-     * info)
115
-     *
116
-     * @var array
117
-     */
118
-    protected $custom_selection_results = array();
119
-
120
-
121
-    /**
122
-     * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
123
-     * play nice
124
-     *
125
-     * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
126
-     *                                                         layer of the model's _fields array, (eg, EVT_ID,
127
-     *                                                         TXN_amount, QST_name, etc) and values are their values
128
-     * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
129
-     *                                                         corresponding db model or not.
130
-     * @param string  $timezone                                indicate what timezone you want any datetime fields to
131
-     *                                                         be in when instantiating a EE_Base_Class object.
132
-     * @param array   $date_formats                            An array of date formats to set on construct where first
133
-     *                                                         value is the date_format and second value is the time
134
-     *                                                         format.
135
-     * @throws InvalidArgumentException
136
-     * @throws InvalidInterfaceException
137
-     * @throws InvalidDataTypeException
138
-     * @throws EE_Error
139
-     * @throws ReflectionException
140
-     */
141
-    protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
142
-    {
143
-        $className = get_class($this);
144
-        do_action("AHEE__{$className}__construct", $this, $fieldValues);
145
-        $model        = $this->get_model();
146
-        $model_fields = $model->field_settings(false);
147
-        // ensure $fieldValues is an array
148
-        $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149
-        // verify client code has not passed any invalid field names
150
-        foreach ($fieldValues as $field_name => $field_value) {
151
-            if (! isset($model_fields[ $field_name ])) {
152
-                throw new EE_Error(
153
-                    sprintf(
154
-                        esc_html__(
155
-                            'Invalid field (%s) passed to constructor of %s. Allowed fields are :%s',
156
-                            'event_espresso'
157
-                        ),
158
-                        $field_name,
159
-                        get_class($this),
160
-                        implode(', ', array_keys($model_fields))
161
-                    )
162
-                );
163
-            }
164
-        }
165
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
-        if (! empty($date_formats) && is_array($date_formats)) {
167
-            list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168
-        } else {
169
-            //set default formats for date and time
170
-            $this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
171
-            $this->_tm_frmt = (string) get_option('time_format', 'g:i a');
172
-        }
173
-        //if db model is instantiating
174
-        if ($bydb) {
175
-            //client code has indicated these field values are from the database
176
-            foreach ($model_fields as $fieldName => $field) {
177
-                $this->set_from_db(
178
-                    $fieldName,
179
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
180
-                );
181
-            }
182
-        } else {
183
-            //we're constructing a brand
184
-            //new instance of the model object. Generally, this means we'll need to do more field validation
185
-            foreach ($model_fields as $fieldName => $field) {
186
-                $this->set(
187
-                    $fieldName,
188
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
189
-                );
190
-            }
191
-        }
192
-        //remember what values were passed to this constructor
193
-        $this->_props_n_values_provided_in_constructor = $fieldValues;
194
-        //remember in entity mapper
195
-        if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
196
-            $model->add_to_entity_map($this);
197
-        }
198
-        //setup all the relations
199
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
-                $this->_model_relations[ $relation_name ] = null;
202
-            } else {
203
-                $this->_model_relations[ $relation_name ] = array();
204
-            }
205
-        }
206
-        /**
207
-         * Action done at the end of each model object construction
208
-         *
209
-         * @param EE_Base_Class $this the model object just created
210
-         */
211
-        do_action('AHEE__EE_Base_Class__construct__finished', $this);
212
-    }
213
-
214
-
215
-    /**
216
-     * Gets whether or not this model object is allowed to persist/be saved to the database.
217
-     *
218
-     * @return boolean
219
-     */
220
-    public function allow_persist()
221
-    {
222
-        return $this->_allow_persist;
223
-    }
224
-
225
-
226
-    /**
227
-     * Sets whether or not this model object should be allowed to be saved to the DB.
228
-     * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
229
-     * you got new information that somehow made you change your mind.
230
-     *
231
-     * @param boolean $allow_persist
232
-     * @return boolean
233
-     */
234
-    public function set_allow_persist($allow_persist)
235
-    {
236
-        return $this->_allow_persist = $allow_persist;
237
-    }
238
-
239
-
240
-    /**
241
-     * Gets the field's original value when this object was constructed during this request.
242
-     * This can be helpful when determining if a model object has changed or not
243
-     *
244
-     * @param string $field_name
245
-     * @return mixed|null
246
-     * @throws ReflectionException
247
-     * @throws InvalidArgumentException
248
-     * @throws InvalidInterfaceException
249
-     * @throws InvalidDataTypeException
250
-     * @throws EE_Error
251
-     */
252
-    public function get_original($field_name)
253
-    {
254
-        if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
255
-            && $field_settings = $this->get_model()->field_settings_for($field_name)
256
-        ) {
257
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
258
-        }
259
-        return null;
260
-    }
261
-
262
-
263
-    /**
264
-     * @param EE_Base_Class $obj
265
-     * @return string
266
-     */
267
-    public function get_class($obj)
268
-    {
269
-        return get_class($obj);
270
-    }
271
-
272
-
273
-    /**
274
-     * Overrides parent because parent expects old models.
275
-     * This also doesn't do any validation, and won't work for serialized arrays
276
-     *
277
-     * @param    string $field_name
278
-     * @param    mixed  $field_value
279
-     * @param bool      $use_default
280
-     * @throws InvalidArgumentException
281
-     * @throws InvalidInterfaceException
282
-     * @throws InvalidDataTypeException
283
-     * @throws EE_Error
284
-     * @throws ReflectionException
285
-     * @throws ReflectionException
286
-     * @throws ReflectionException
287
-     */
288
-    public function set($field_name, $field_value, $use_default = false)
289
-    {
290
-        // if not using default and nothing has changed, and object has already been setup (has ID),
291
-        // then don't do anything
292
-        if (
293
-            ! $use_default
294
-            && $this->_fields[ $field_name ] === $field_value
295
-            && $this->ID()
296
-        ) {
297
-            return;
298
-        }
299
-        $model              = $this->get_model();
300
-        $this->_has_changes = true;
301
-        $field_obj          = $model->field_settings_for($field_name);
302
-        if ($field_obj instanceof EE_Model_Field_Base) {
303
-            //			if ( method_exists( $field_obj, 'set_timezone' )) {
304
-            if ($field_obj instanceof EE_Datetime_Field) {
305
-                $field_obj->set_timezone($this->_timezone);
306
-                $field_obj->set_date_format($this->_dt_frmt);
307
-                $field_obj->set_time_format($this->_tm_frmt);
308
-            }
309
-            $holder_of_value = $field_obj->prepare_for_set($field_value);
310
-            //should the value be null?
311
-            if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
-                $this->_fields[ $field_name ] = $field_obj->get_default_value();
313
-                /**
314
-                 * To save having to refactor all the models, if a default value is used for a
315
-                 * EE_Datetime_Field, and that value is not null nor is it a DateTime
316
-                 * object.  Then let's do a set again to ensure that it becomes a DateTime
317
-                 * object.
318
-                 *
319
-                 * @since 4.6.10+
320
-                 */
321
-                if (
322
-                    $field_obj instanceof EE_Datetime_Field
323
-                    && $this->_fields[ $field_name ] !== null
324
-                    && ! $this->_fields[ $field_name ] instanceof DateTime
325
-                ) {
326
-                    empty($this->_fields[ $field_name ])
327
-                        ? $this->set($field_name, time())
328
-                        : $this->set($field_name, $this->_fields[ $field_name ]);
329
-                }
330
-            } else {
331
-                $this->_fields[ $field_name ] = $holder_of_value;
332
-            }
333
-            //if we're not in the constructor...
334
-            //now check if what we set was a primary key
335
-            if (
336
-                //note: props_n_values_provided_in_constructor is only set at the END of the constructor
337
-                $this->_props_n_values_provided_in_constructor
338
-                && $field_value
339
-                && $field_name === $model->primary_key_name()
340
-            ) {
341
-                //if so, we want all this object's fields to be filled either with
342
-                //what we've explicitly set on this model
343
-                //or what we have in the db
344
-                // echo "setting primary key!";
345
-                $fields_on_model = self::_get_model(get_class($this))->field_settings();
346
-                $obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347
-                foreach ($fields_on_model as $field_obj) {
348
-                    if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349
-                        && $field_obj->get_name() !== $field_name
350
-                    ) {
351
-                        $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
352
-                    }
353
-                }
354
-                //oh this model object has an ID? well make sure its in the entity mapper
355
-                $model->add_to_entity_map($this);
356
-            }
357
-            //let's unset any cache for this field_name from the $_cached_properties property.
358
-            $this->_clear_cached_property($field_name);
359
-        } else {
360
-            throw new EE_Error(
361
-                sprintf(
362
-                    esc_html__(
363
-                        'A valid EE_Model_Field_Base could not be found for the given field name: %s',
364
-                        'event_espresso'
365
-                    ),
366
-                    $field_name
367
-                )
368
-            );
369
-        }
370
-    }
371
-
372
-
373
-    /**
374
-     * Set custom select values for model.
375
-     *
376
-     * @param array $custom_select_values
377
-     */
378
-    public function setCustomSelectsValues(array $custom_select_values)
379
-    {
380
-        $this->custom_selection_results = $custom_select_values;
381
-    }
382
-
383
-
384
-    /**
385
-     * Returns the custom select value for the provided alias if its set.
386
-     * If not set, returns null.
387
-     *
388
-     * @param string $alias
389
-     * @return string|int|float|null
390
-     */
391
-    public function getCustomSelect($alias)
392
-    {
393
-        return isset($this->custom_selection_results[ $alias ])
394
-            ? $this->custom_selection_results[ $alias ]
395
-            : null;
396
-    }
397
-
398
-
399
-    /**
400
-     * This sets the field value on the db column if it exists for the given $column_name or
401
-     * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
402
-     *
403
-     * @see EE_message::get_column_value for related documentation on the necessity of this method.
404
-     * @param string $field_name  Must be the exact column name.
405
-     * @param mixed  $field_value The value to set.
406
-     * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
407
-     * @throws InvalidArgumentException
408
-     * @throws InvalidInterfaceException
409
-     * @throws InvalidDataTypeException
410
-     * @throws EE_Error
411
-     * @throws ReflectionException
412
-     */
413
-    public function set_field_or_extra_meta($field_name, $field_value)
414
-    {
415
-        if ($this->get_model()->has_field($field_name)) {
416
-            $this->set($field_name, $field_value);
417
-            return true;
418
-        }
419
-        //ensure this object is saved first so that extra meta can be properly related.
420
-        $this->save();
421
-        return $this->update_extra_meta($field_name, $field_value);
422
-    }
423
-
424
-
425
-    /**
426
-     * This retrieves the value of the db column set on this class or if that's not present
427
-     * it will attempt to retrieve from extra_meta if found.
428
-     * Example Usage:
429
-     * Via EE_Message child class:
430
-     * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
431
-     * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
432
-     * also have additional main fields specific to the messenger.  The system accommodates those extra
433
-     * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
434
-     * value for those extra fields dynamically via the EE_message object.
435
-     *
436
-     * @param  string $field_name expecting the fully qualified field name.
437
-     * @return mixed|null  value for the field if found.  null if not found.
438
-     * @throws ReflectionException
439
-     * @throws InvalidArgumentException
440
-     * @throws InvalidInterfaceException
441
-     * @throws InvalidDataTypeException
442
-     * @throws EE_Error
443
-     */
444
-    public function get_field_or_extra_meta($field_name)
445
-    {
446
-        if ($this->get_model()->has_field($field_name)) {
447
-            $column_value = $this->get($field_name);
448
-        } else {
449
-            //This isn't a column in the main table, let's see if it is in the extra meta.
450
-            $column_value = $this->get_extra_meta($field_name, true, null);
451
-        }
452
-        return $column_value;
453
-    }
454
-
455
-
456
-    /**
457
-     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
458
-     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
459
-     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
460
-     * available to all child classes that may be using the EE_Datetime_Field for a field data type.
461
-     *
462
-     * @access public
463
-     * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
464
-     * @return void
465
-     * @throws InvalidArgumentException
466
-     * @throws InvalidInterfaceException
467
-     * @throws InvalidDataTypeException
468
-     * @throws EE_Error
469
-     * @throws ReflectionException
470
-     */
471
-    public function set_timezone($timezone = '')
472
-    {
473
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
474
-        //make sure we clear all cached properties because they won't be relevant now
475
-        $this->_clear_cached_properties();
476
-        //make sure we update field settings and the date for all EE_Datetime_Fields
477
-        $model_fields = $this->get_model()->field_settings(false);
478
-        foreach ($model_fields as $field_name => $field_obj) {
479
-            if ($field_obj instanceof EE_Datetime_Field) {
480
-                $field_obj->set_timezone($this->_timezone);
481
-                if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
-                    $this->_fields[ $field_name ]->setTimezone(new DateTimeZone($this->_timezone));
483
-                }
484
-            }
485
-        }
486
-    }
487
-
488
-
489
-    /**
490
-     * This just returns whatever is set for the current timezone.
491
-     *
492
-     * @access public
493
-     * @return string timezone string
494
-     */
495
-    public function get_timezone()
496
-    {
497
-        return $this->_timezone;
498
-    }
499
-
500
-
501
-    /**
502
-     * This sets the internal date format to what is sent in to be used as the new default for the class
503
-     * internally instead of wp set date format options
504
-     *
505
-     * @since 4.6
506
-     * @param string $format should be a format recognizable by PHP date() functions.
507
-     */
508
-    public function set_date_format($format)
509
-    {
510
-        $this->_dt_frmt = $format;
511
-        //clear cached_properties because they won't be relevant now.
512
-        $this->_clear_cached_properties();
513
-    }
514
-
515
-
516
-    /**
517
-     * This sets the internal time format string to what is sent in to be used as the new default for the
518
-     * class internally instead of wp set time format options.
519
-     *
520
-     * @since 4.6
521
-     * @param string $format should be a format recognizable by PHP date() functions.
522
-     */
523
-    public function set_time_format($format)
524
-    {
525
-        $this->_tm_frmt = $format;
526
-        //clear cached_properties because they won't be relevant now.
527
-        $this->_clear_cached_properties();
528
-    }
529
-
530
-
531
-    /**
532
-     * This returns the current internal set format for the date and time formats.
533
-     *
534
-     * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
535
-     *                             where the first value is the date format and the second value is the time format.
536
-     * @return mixed string|array
537
-     */
538
-    public function get_format($full = true)
539
-    {
540
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541
-    }
542
-
543
-
544
-    /**
545
-     * cache
546
-     * stores the passed model object on the current model object.
547
-     * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
548
-     *
549
-     * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
550
-     *                                       'Registration' associated with this model object
551
-     * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
552
-     *                                       that could be a payment or a registration)
553
-     * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
554
-     *                                       items which will be stored in an array on this object
555
-     * @throws ReflectionException
556
-     * @throws InvalidArgumentException
557
-     * @throws InvalidInterfaceException
558
-     * @throws InvalidDataTypeException
559
-     * @throws EE_Error
560
-     * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
561
-     *                                       related thing, no array)
562
-     */
563
-    public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564
-    {
565
-        // its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
-        if (! $object_to_cache instanceof EE_Base_Class) {
567
-            return false;
568
-        }
569
-        // also get "how" the object is related, or throw an error
570
-        if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571
-            throw new EE_Error(
572
-                sprintf(
573
-                    esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
574
-                    $relationName,
575
-                    get_class($this)
576
-                )
577
-            );
578
-        }
579
-        // how many things are related ?
580
-        if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
581
-            // if it's a "belongs to" relationship, then there's only one related model object
582
-            // eg, if this is a registration, there's only 1 attendee for it
583
-            // so for these model objects just set it to be cached
584
-            $this->_model_relations[ $relationName ] = $object_to_cache;
585
-            $return                                  = true;
586
-        } else {
587
-            // otherwise, this is the "many" side of a one to many relationship,
588
-            // so we'll add the object to the array of related objects for that type.
589
-            // eg: if this is an event, there are many registrations for that event,
590
-            // so we cache the registrations in an array
591
-            if (! is_array($this->_model_relations[ $relationName ])) {
592
-                // if for some reason, the cached item is a model object,
593
-                // then stick that in the array, otherwise start with an empty array
594
-                $this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
595
-                                                           instanceof
596
-                                                           EE_Base_Class
597
-                    ? array($this->_model_relations[ $relationName ]) : array();
598
-            }
599
-            // first check for a cache_id which is normally empty
600
-            if (! empty($cache_id)) {
601
-                // if the cache_id exists, then it means we are purposely trying to cache this
602
-                // with a known key that can then be used to retrieve the object later on
603
-                $this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
604
-                $return                                               = $cache_id;
605
-            } elseif ($object_to_cache->ID()) {
606
-                // OR the cached object originally came from the db, so let's just use it's PK for an ID
607
-                $this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
608
-                $return                                                            = $object_to_cache->ID();
609
-            } else {
610
-                // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
-                $this->_model_relations[ $relationName ][] = $object_to_cache;
612
-                // move the internal pointer to the end of the array
613
-                end($this->_model_relations[ $relationName ]);
614
-                // and grab the key so that we can return it
615
-                $return = key($this->_model_relations[ $relationName ]);
616
-            }
617
-        }
618
-        return $return;
619
-    }
620
-
621
-
622
-    /**
623
-     * For adding an item to the cached_properties property.
624
-     *
625
-     * @access protected
626
-     * @param string      $fieldname the property item the corresponding value is for.
627
-     * @param mixed       $value     The value we are caching.
628
-     * @param string|null $cache_type
629
-     * @return void
630
-     * @throws ReflectionException
631
-     * @throws InvalidArgumentException
632
-     * @throws InvalidInterfaceException
633
-     * @throws InvalidDataTypeException
634
-     * @throws EE_Error
635
-     */
636
-    protected function _set_cached_property($fieldname, $value, $cache_type = null)
637
-    {
638
-        //first make sure this property exists
639
-        $this->get_model()->field_settings_for($fieldname);
640
-        $cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
-        $this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
642
-    }
643
-
644
-
645
-    /**
646
-     * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
647
-     * This also SETS the cache if we return the actual property!
648
-     *
649
-     * @param string $fieldname        the name of the property we're trying to retrieve
650
-     * @param bool   $pretty
651
-     * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
652
-     *                                 (in cases where the same property may be used for different outputs
653
-     *                                 - i.e. datetime, money etc.)
654
-     *                                 It can also accept certain pre-defined "schema" strings
655
-     *                                 to define how to output the property.
656
-     *                                 see the field's prepare_for_pretty_echoing for what strings can be used
657
-     * @return mixed                   whatever the value for the property is we're retrieving
658
-     * @throws ReflectionException
659
-     * @throws InvalidArgumentException
660
-     * @throws InvalidInterfaceException
661
-     * @throws InvalidDataTypeException
662
-     * @throws EE_Error
663
-     */
664
-    protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
665
-    {
666
-        //verify the field exists
667
-        $model = $this->get_model();
668
-        $model->field_settings_for($fieldname);
669
-        $cache_type = $pretty ? 'pretty' : 'standard';
670
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
-        if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
-            return $this->_cached_properties[ $fieldname ][ $cache_type ];
673
-        }
674
-        $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675
-        $this->_set_cached_property($fieldname, $value, $cache_type);
676
-        return $value;
677
-    }
678
-
679
-
680
-    /**
681
-     * If the cache didn't fetch the needed item, this fetches it.
682
-     *
683
-     * @param string $fieldname
684
-     * @param bool   $pretty
685
-     * @param string $extra_cache_ref
686
-     * @return mixed
687
-     * @throws InvalidArgumentException
688
-     * @throws InvalidInterfaceException
689
-     * @throws InvalidDataTypeException
690
-     * @throws EE_Error
691
-     * @throws ReflectionException
692
-     */
693
-    protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
694
-    {
695
-        $field_obj = $this->get_model()->field_settings_for($fieldname);
696
-        // If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
697
-        if ($field_obj instanceof EE_Datetime_Field) {
698
-            $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699
-        }
700
-        if (! isset($this->_fields[ $fieldname ])) {
701
-            $this->_fields[ $fieldname ] = null;
702
-        }
703
-        $value = $pretty
704
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
-            : $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
706
-        return $value;
707
-    }
708
-
709
-
710
-    /**
711
-     * set timezone, formats, and output for EE_Datetime_Field objects
712
-     *
713
-     * @param \EE_Datetime_Field $datetime_field
714
-     * @param bool               $pretty
715
-     * @param null               $date_or_time
716
-     * @return void
717
-     * @throws InvalidArgumentException
718
-     * @throws InvalidInterfaceException
719
-     * @throws InvalidDataTypeException
720
-     * @throws EE_Error
721
-     */
722
-    protected function _prepare_datetime_field(
723
-        EE_Datetime_Field $datetime_field,
724
-        $pretty = false,
725
-        $date_or_time = null
726
-    ) {
727
-        $datetime_field->set_timezone($this->_timezone);
728
-        $datetime_field->set_date_format($this->_dt_frmt, $pretty);
729
-        $datetime_field->set_time_format($this->_tm_frmt, $pretty);
730
-        //set the output returned
731
-        switch ($date_or_time) {
732
-            case 'D' :
733
-                $datetime_field->set_date_time_output('date');
734
-                break;
735
-            case 'T' :
736
-                $datetime_field->set_date_time_output('time');
737
-                break;
738
-            default :
739
-                $datetime_field->set_date_time_output();
740
-        }
741
-    }
742
-
743
-
744
-    /**
745
-     * This just takes care of clearing out the cached_properties
746
-     *
747
-     * @return void
748
-     */
749
-    protected function _clear_cached_properties()
750
-    {
751
-        $this->_cached_properties = array();
752
-    }
753
-
754
-
755
-    /**
756
-     * This just clears out ONE property if it exists in the cache
757
-     *
758
-     * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
759
-     * @return void
760
-     */
761
-    protected function _clear_cached_property($property_name)
762
-    {
763
-        if (isset($this->_cached_properties[ $property_name ])) {
764
-            unset($this->_cached_properties[ $property_name ]);
765
-        }
766
-    }
767
-
768
-
769
-    /**
770
-     * Ensures that this related thing is a model object.
771
-     *
772
-     * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
773
-     * @param string $model_name   name of the related thing, eg 'Attendee',
774
-     * @return EE_Base_Class
775
-     * @throws ReflectionException
776
-     * @throws InvalidArgumentException
777
-     * @throws InvalidInterfaceException
778
-     * @throws InvalidDataTypeException
779
-     * @throws EE_Error
780
-     */
781
-    protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
782
-    {
783
-        $other_model_instance = self::_get_model_instance_with_name(
784
-            self::_get_model_classname($model_name),
785
-            $this->_timezone
786
-        );
787
-        return $other_model_instance->ensure_is_obj($object_or_id);
788
-    }
789
-
790
-
791
-    /**
792
-     * Forgets the cached model of the given relation Name. So the next time we request it,
793
-     * we will fetch it again from the database. (Handy if you know it's changed somehow).
794
-     * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
795
-     * then only remove that one object from our cached array. Otherwise, clear the entire list
796
-     *
797
-     * @param string $relationName                         one of the keys in the _model_relations array on the model.
798
-     *                                                     Eg 'Registration'
799
-     * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
800
-     *                                                     if you intend to use $clear_all = TRUE, or the relation only
801
-     *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
802
-     * @param bool   $clear_all                            This flags clearing the entire cache relation property if
803
-     *                                                     this is HasMany or HABTM.
804
-     * @throws ReflectionException
805
-     * @throws InvalidArgumentException
806
-     * @throws InvalidInterfaceException
807
-     * @throws InvalidDataTypeException
808
-     * @throws EE_Error
809
-     * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
810
-     *                                                     relation from all
811
-     */
812
-    public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
813
-    {
814
-        $relationship_to_model = $this->get_model()->related_settings_for($relationName);
815
-        $index_in_cache        = '';
816
-        if (! $relationship_to_model) {
817
-            throw new EE_Error(
818
-                sprintf(
819
-                    esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
820
-                    $relationName,
821
-                    get_class($this)
822
-                )
823
-            );
824
-        }
825
-        if ($clear_all) {
826
-            $obj_removed                             = true;
827
-            $this->_model_relations[ $relationName ] = null;
828
-        } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
-            $obj_removed                             = $this->_model_relations[ $relationName ];
830
-            $this->_model_relations[ $relationName ] = null;
831
-        } else {
832
-            if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833
-                && $object_to_remove_or_index_into_array->ID()
834
-            ) {
835
-                $index_in_cache = $object_to_remove_or_index_into_array->ID();
836
-                if (is_array($this->_model_relations[ $relationName ])
837
-                    && ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
838
-                ) {
839
-                    $index_found_at = null;
840
-                    //find this object in the array even though it has a different key
841
-                    foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
842
-                        /** @noinspection TypeUnsafeComparisonInspection */
843
-                        if (
844
-                            $obj instanceof EE_Base_Class
845
-                            && (
846
-                                $obj == $object_to_remove_or_index_into_array
847
-                                || $obj->ID() === $object_to_remove_or_index_into_array->ID()
848
-                            )
849
-                        ) {
850
-                            $index_found_at = $index;
851
-                            break;
852
-                        }
853
-                    }
854
-                    if ($index_found_at) {
855
-                        $index_in_cache = $index_found_at;
856
-                    } else {
857
-                        //it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
858
-                        //if it wasn't in it to begin with. So we're done
859
-                        return $object_to_remove_or_index_into_array;
860
-                    }
861
-                }
862
-            } elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
863
-                //so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
864
-                foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
865
-                    /** @noinspection TypeUnsafeComparisonInspection */
866
-                    if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
867
-                        $index_in_cache = $index;
868
-                    }
869
-                }
870
-            } else {
871
-                $index_in_cache = $object_to_remove_or_index_into_array;
872
-            }
873
-            //supposedly we've found it. But it could just be that the client code
874
-            //provided a bad index/object
875
-            if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
-                $obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
-                unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
878
-            } else {
879
-                //that thing was never cached anyways.
880
-                $obj_removed = null;
881
-            }
882
-        }
883
-        return $obj_removed;
884
-    }
885
-
886
-
887
-    /**
888
-     * update_cache_after_object_save
889
-     * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
890
-     * obtained after being saved to the db
891
-     *
892
-     * @param string        $relationName       - the type of object that is cached
893
-     * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
894
-     * @param string        $current_cache_id   - the ID that was used when originally caching the object
895
-     * @return boolean TRUE on success, FALSE on fail
896
-     * @throws ReflectionException
897
-     * @throws InvalidArgumentException
898
-     * @throws InvalidInterfaceException
899
-     * @throws InvalidDataTypeException
900
-     * @throws EE_Error
901
-     */
902
-    public function update_cache_after_object_save(
903
-        $relationName,
904
-        EE_Base_Class $newly_saved_object,
905
-        $current_cache_id = ''
906
-    ) {
907
-        // verify that incoming object is of the correct type
908
-        $obj_class = 'EE_' . $relationName;
909
-        if ($newly_saved_object instanceof $obj_class) {
910
-            /* @type EE_Base_Class $newly_saved_object */
911
-            // now get the type of relation
912
-            $relationship_to_model = $this->get_model()->related_settings_for($relationName);
913
-            // if this is a 1:1 relationship
914
-            if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915
-                // then just replace the cached object with the newly saved object
916
-                $this->_model_relations[ $relationName ] = $newly_saved_object;
917
-                return true;
918
-                // or if it's some kind of sordid feral polyamorous relationship...
919
-            }
920
-            if (is_array($this->_model_relations[ $relationName ])
921
-                      && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
922
-            ) {
923
-                // then remove the current cached item
924
-                unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
925
-                // and cache the newly saved object using it's new ID
926
-                $this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
927
-                return true;
928
-            }
929
-        }
930
-        return false;
931
-    }
932
-
933
-
934
-    /**
935
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
936
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
937
-     *
938
-     * @param string $relationName
939
-     * @return EE_Base_Class
940
-     */
941
-    public function get_one_from_cache($relationName)
942
-    {
943
-        $cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
-            ? $this->_model_relations[ $relationName ]
945
-            : null;
946
-        if (is_array($cached_array_or_object)) {
947
-            return array_shift($cached_array_or_object);
948
-        }
949
-        return $cached_array_or_object;
950
-    }
951
-
952
-
953
-    /**
954
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
955
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
956
-     *
957
-     * @param string $relationName
958
-     * @throws ReflectionException
959
-     * @throws InvalidArgumentException
960
-     * @throws InvalidInterfaceException
961
-     * @throws InvalidDataTypeException
962
-     * @throws EE_Error
963
-     * @return EE_Base_Class[] NOT necessarily indexed by primary keys
964
-     */
965
-    public function get_all_from_cache($relationName)
966
-    {
967
-        $objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
968
-        // if the result is not an array, but exists, make it an array
969
-        $objects = is_array($objects) ? $objects : array($objects);
970
-        //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
971
-        //basically, if this model object was stored in the session, and these cached model objects
972
-        //already have IDs, let's make sure they're in their model's entity mapper
973
-        //otherwise we will have duplicates next time we call
974
-        // EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
975
-        $model = EE_Registry::instance()->load_model($relationName);
976
-        foreach ($objects as $model_object) {
977
-            if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
978
-                //ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
979
-                if ($model_object->ID()) {
980
-                    $model->add_to_entity_map($model_object);
981
-                }
982
-            } else {
983
-                throw new EE_Error(
984
-                    sprintf(
985
-                        esc_html__(
986
-                            'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
987
-                            'event_espresso'
988
-                        ),
989
-                        $relationName,
990
-                        gettype($model_object)
991
-                    )
992
-                );
993
-            }
994
-        }
995
-        return $objects;
996
-    }
997
-
998
-
999
-    /**
1000
-     * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
1001
-     * matching the given query conditions.
1002
-     *
1003
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1004
-     * @param int   $limit              How many objects to return.
1005
-     * @param array $query_params       Any additional conditions on the query.
1006
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1007
-     *                                  you can indicate just the columns you want returned
1008
-     * @return array|EE_Base_Class[]
1009
-     * @throws ReflectionException
1010
-     * @throws InvalidArgumentException
1011
-     * @throws InvalidInterfaceException
1012
-     * @throws InvalidDataTypeException
1013
-     * @throws EE_Error
1014
-     */
1015
-    public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
1016
-    {
1017
-        $model         = $this->get_model();
1018
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1019
-            ? $model->get_primary_key_field()->get_name()
1020
-            : $field_to_order_by;
1021
-        $current_value = ! empty($field) ? $this->get($field) : null;
1022
-        if (empty($field) || empty($current_value)) {
1023
-            return array();
1024
-        }
1025
-        return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
1026
-    }
1027
-
1028
-
1029
-    /**
1030
-     * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
1031
-     * matching the given query conditions.
1032
-     *
1033
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1034
-     * @param int   $limit              How many objects to return.
1035
-     * @param array $query_params       Any additional conditions on the query.
1036
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1037
-     *                                  you can indicate just the columns you want returned
1038
-     * @return array|EE_Base_Class[]
1039
-     * @throws ReflectionException
1040
-     * @throws InvalidArgumentException
1041
-     * @throws InvalidInterfaceException
1042
-     * @throws InvalidDataTypeException
1043
-     * @throws EE_Error
1044
-     */
1045
-    public function previous_x(
1046
-        $field_to_order_by = null,
1047
-        $limit = 1,
1048
-        $query_params = array(),
1049
-        $columns_to_select = null
1050
-    ) {
1051
-        $model         = $this->get_model();
1052
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1053
-            ? $model->get_primary_key_field()->get_name()
1054
-            : $field_to_order_by;
1055
-        $current_value = ! empty($field) ? $this->get($field) : null;
1056
-        if (empty($field) || empty($current_value)) {
1057
-            return array();
1058
-        }
1059
-        return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
1060
-    }
1061
-
1062
-
1063
-    /**
1064
-     * Returns the next EE_Base_Class object in sequence from this object as found in the database
1065
-     * matching the given query conditions.
1066
-     *
1067
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1068
-     * @param array $query_params       Any additional conditions on the query.
1069
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070
-     *                                  you can indicate just the columns you want returned
1071
-     * @return array|EE_Base_Class
1072
-     * @throws ReflectionException
1073
-     * @throws InvalidArgumentException
1074
-     * @throws InvalidInterfaceException
1075
-     * @throws InvalidDataTypeException
1076
-     * @throws EE_Error
1077
-     */
1078
-    public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1079
-    {
1080
-        $model         = $this->get_model();
1081
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1082
-            ? $model->get_primary_key_field()->get_name()
1083
-            : $field_to_order_by;
1084
-        $current_value = ! empty($field) ? $this->get($field) : null;
1085
-        if (empty($field) || empty($current_value)) {
1086
-            return array();
1087
-        }
1088
-        return $model->next($current_value, $field, $query_params, $columns_to_select);
1089
-    }
1090
-
1091
-
1092
-    /**
1093
-     * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1094
-     * matching the given query conditions.
1095
-     *
1096
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1097
-     * @param array $query_params       Any additional conditions on the query.
1098
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099
-     *                                  you can indicate just the column you want returned
1100
-     * @return array|EE_Base_Class
1101
-     * @throws ReflectionException
1102
-     * @throws InvalidArgumentException
1103
-     * @throws InvalidInterfaceException
1104
-     * @throws InvalidDataTypeException
1105
-     * @throws EE_Error
1106
-     */
1107
-    public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1108
-    {
1109
-        $model         = $this->get_model();
1110
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1111
-            ? $model->get_primary_key_field()->get_name()
1112
-            : $field_to_order_by;
1113
-        $current_value = ! empty($field) ? $this->get($field) : null;
1114
-        if (empty($field) || empty($current_value)) {
1115
-            return array();
1116
-        }
1117
-        return $model->previous($current_value, $field, $query_params, $columns_to_select);
1118
-    }
1119
-
1120
-
1121
-    /**
1122
-     * Overrides parent because parent expects old models.
1123
-     * This also doesn't do any validation, and won't work for serialized arrays
1124
-     *
1125
-     * @param string $field_name
1126
-     * @param mixed  $field_value_from_db
1127
-     * @throws ReflectionException
1128
-     * @throws InvalidArgumentException
1129
-     * @throws InvalidInterfaceException
1130
-     * @throws InvalidDataTypeException
1131
-     * @throws EE_Error
1132
-     */
1133
-    public function set_from_db($field_name, $field_value_from_db)
1134
-    {
1135
-        $field_obj = $this->get_model()->field_settings_for($field_name);
1136
-        if ($field_obj instanceof EE_Model_Field_Base) {
1137
-            //you would think the DB has no NULLs for non-null label fields right? wrong!
1138
-            //eg, a CPT model object could have an entry in the posts table, but no
1139
-            //entry in the meta table. Meaning that all its columns in the meta table
1140
-            //are null! yikes! so when we find one like that, use defaults for its meta columns
1141
-            if ($field_value_from_db === null) {
1142
-                if ($field_obj->is_nullable()) {
1143
-                    //if the field allows nulls, then let it be null
1144
-                    $field_value = null;
1145
-                } else {
1146
-                    $field_value = $field_obj->get_default_value();
1147
-                }
1148
-            } else {
1149
-                $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150
-            }
1151
-            $this->_fields[ $field_name ] = $field_value;
1152
-            $this->_clear_cached_property($field_name);
1153
-        }
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * verifies that the specified field is of the correct type
1159
-     *
1160
-     * @param string $field_name
1161
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1162
-     *                                (in cases where the same property may be used for different outputs
1163
-     *                                - i.e. datetime, money etc.)
1164
-     * @return mixed
1165
-     * @throws ReflectionException
1166
-     * @throws InvalidArgumentException
1167
-     * @throws InvalidInterfaceException
1168
-     * @throws InvalidDataTypeException
1169
-     * @throws EE_Error
1170
-     */
1171
-    public function get($field_name, $extra_cache_ref = null)
1172
-    {
1173
-        return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1174
-    }
1175
-
1176
-
1177
-    /**
1178
-     * This method simply returns the RAW unprocessed value for the given property in this class
1179
-     *
1180
-     * @param  string $field_name A valid fieldname
1181
-     * @return mixed              Whatever the raw value stored on the property is.
1182
-     * @throws ReflectionException
1183
-     * @throws InvalidArgumentException
1184
-     * @throws InvalidInterfaceException
1185
-     * @throws InvalidDataTypeException
1186
-     * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1187
-     */
1188
-    public function get_raw($field_name)
1189
-    {
1190
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1191
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
-            ? $this->_fields[ $field_name ]->format('U')
1193
-            : $this->_fields[ $field_name ];
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * This is used to return the internal DateTime object used for a field that is a
1199
-     * EE_Datetime_Field.
1200
-     *
1201
-     * @param string $field_name               The field name retrieving the DateTime object.
1202
-     * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1203
-     * @throws ReflectionException
1204
-     * @throws InvalidArgumentException
1205
-     * @throws InvalidInterfaceException
1206
-     * @throws InvalidDataTypeException
1207
-     * @throws EE_Error
1208
-     *                                         an error is set and false returned.  If the field IS an
1209
-     *                                         EE_Datetime_Field and but the field value is null, then
1210
-     *                                         just null is returned (because that indicates that likely
1211
-     *                                         this field is nullable).
1212
-     */
1213
-    public function get_DateTime_object($field_name)
1214
-    {
1215
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1216
-        if (! $field_settings instanceof EE_Datetime_Field) {
1217
-            EE_Error::add_error(
1218
-                sprintf(
1219
-                    esc_html__(
1220
-                        'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1221
-                        'event_espresso'
1222
-                    ),
1223
-                    $field_name
1224
-                ),
1225
-                __FILE__,
1226
-                __FUNCTION__,
1227
-                __LINE__
1228
-            );
1229
-            return false;
1230
-        }
1231
-        return $this->_fields[ $field_name ];
1232
-    }
1233
-
1234
-
1235
-    /**
1236
-     * To be used in template to immediately echo out the value, and format it for output.
1237
-     * Eg, should call stripslashes and whatnot before echoing
1238
-     *
1239
-     * @param string $field_name      the name of the field as it appears in the DB
1240
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1241
-     *                                (in cases where the same property may be used for different outputs
1242
-     *                                - i.e. datetime, money etc.)
1243
-     * @return void
1244
-     * @throws ReflectionException
1245
-     * @throws InvalidArgumentException
1246
-     * @throws InvalidInterfaceException
1247
-     * @throws InvalidDataTypeException
1248
-     * @throws EE_Error
1249
-     */
1250
-    public function e($field_name, $extra_cache_ref = null)
1251
-    {
1252
-        echo $this->get_pretty($field_name, $extra_cache_ref);
1253
-    }
1254
-
1255
-
1256
-    /**
1257
-     * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1258
-     * can be easily used as the value of form input.
1259
-     *
1260
-     * @param string $field_name
1261
-     * @return void
1262
-     * @throws ReflectionException
1263
-     * @throws InvalidArgumentException
1264
-     * @throws InvalidInterfaceException
1265
-     * @throws InvalidDataTypeException
1266
-     * @throws EE_Error
1267
-     */
1268
-    public function f($field_name)
1269
-    {
1270
-        $this->e($field_name, 'form_input');
1271
-    }
1272
-
1273
-
1274
-    /**
1275
-     * Same as `f()` but just returns the value instead of echoing it
1276
-     *
1277
-     * @param string $field_name
1278
-     * @return string
1279
-     * @throws ReflectionException
1280
-     * @throws InvalidArgumentException
1281
-     * @throws InvalidInterfaceException
1282
-     * @throws InvalidDataTypeException
1283
-     * @throws EE_Error
1284
-     */
1285
-    public function get_f($field_name)
1286
-    {
1287
-        return (string) $this->get_pretty($field_name, 'form_input');
1288
-    }
1289
-
1290
-
1291
-    /**
1292
-     * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1293
-     * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1294
-     * to see what options are available.
1295
-     *
1296
-     * @param string $field_name
1297
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1298
-     *                                (in cases where the same property may be used for different outputs
1299
-     *                                - i.e. datetime, money etc.)
1300
-     * @return mixed
1301
-     * @throws ReflectionException
1302
-     * @throws InvalidArgumentException
1303
-     * @throws InvalidInterfaceException
1304
-     * @throws InvalidDataTypeException
1305
-     * @throws EE_Error
1306
-     */
1307
-    public function get_pretty($field_name, $extra_cache_ref = null)
1308
-    {
1309
-        return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1310
-    }
1311
-
1312
-
1313
-    /**
1314
-     * This simply returns the datetime for the given field name
1315
-     * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1316
-     * (and the equivalent e_date, e_time, e_datetime).
1317
-     *
1318
-     * @access   protected
1319
-     * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1320
-     * @param string   $dt_frmt      valid datetime format used for date
1321
-     *                               (if '' then we just use the default on the field,
1322
-     *                               if NULL we use the last-used format)
1323
-     * @param string   $tm_frmt      Same as above except this is for time format
1324
-     * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1325
-     * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1326
-     * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1327
-     *                               if field is not a valid dtt field, or void if echoing
1328
-     * @throws ReflectionException
1329
-     * @throws InvalidArgumentException
1330
-     * @throws InvalidInterfaceException
1331
-     * @throws InvalidDataTypeException
1332
-     * @throws EE_Error
1333
-     */
1334
-    protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1335
-    {
1336
-        // clear cached property
1337
-        $this->_clear_cached_property($field_name);
1338
-        //reset format properties because they are used in get()
1339
-        $this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1340
-        $this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1341
-        if ($echo) {
1342
-            $this->e($field_name, $date_or_time);
1343
-            return '';
1344
-        }
1345
-        return $this->get($field_name, $date_or_time);
1346
-    }
1347
-
1348
-
1349
-    /**
1350
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1351
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1352
-     * other echoes the pretty value for dtt)
1353
-     *
1354
-     * @param  string $field_name name of model object datetime field holding the value
1355
-     * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1356
-     * @return string            datetime value formatted
1357
-     * @throws ReflectionException
1358
-     * @throws InvalidArgumentException
1359
-     * @throws InvalidInterfaceException
1360
-     * @throws InvalidDataTypeException
1361
-     * @throws EE_Error
1362
-     */
1363
-    public function get_date($field_name, $format = '')
1364
-    {
1365
-        return $this->_get_datetime($field_name, $format, null, 'D');
1366
-    }
1367
-
1368
-
1369
-    /**
1370
-     * @param        $field_name
1371
-     * @param string $format
1372
-     * @throws ReflectionException
1373
-     * @throws InvalidArgumentException
1374
-     * @throws InvalidInterfaceException
1375
-     * @throws InvalidDataTypeException
1376
-     * @throws EE_Error
1377
-     */
1378
-    public function e_date($field_name, $format = '')
1379
-    {
1380
-        $this->_get_datetime($field_name, $format, null, 'D', true);
1381
-    }
1382
-
1383
-
1384
-    /**
1385
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1386
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1387
-     * other echoes the pretty value for dtt)
1388
-     *
1389
-     * @param  string $field_name name of model object datetime field holding the value
1390
-     * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1391
-     * @return string             datetime value formatted
1392
-     * @throws ReflectionException
1393
-     * @throws InvalidArgumentException
1394
-     * @throws InvalidInterfaceException
1395
-     * @throws InvalidDataTypeException
1396
-     * @throws EE_Error
1397
-     */
1398
-    public function get_time($field_name, $format = '')
1399
-    {
1400
-        return $this->_get_datetime($field_name, null, $format, 'T');
1401
-    }
1402
-
1403
-
1404
-    /**
1405
-     * @param        $field_name
1406
-     * @param string $format
1407
-     * @throws ReflectionException
1408
-     * @throws InvalidArgumentException
1409
-     * @throws InvalidInterfaceException
1410
-     * @throws InvalidDataTypeException
1411
-     * @throws EE_Error
1412
-     */
1413
-    public function e_time($field_name, $format = '')
1414
-    {
1415
-        $this->_get_datetime($field_name, null, $format, 'T', true);
1416
-    }
1417
-
1418
-
1419
-    /**
1420
-     * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1421
-     * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1422
-     * other echoes the pretty value for dtt)
1423
-     *
1424
-     * @param  string $field_name name of model object datetime field holding the value
1425
-     * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1426
-     * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1427
-     * @return string             datetime value formatted
1428
-     * @throws ReflectionException
1429
-     * @throws InvalidArgumentException
1430
-     * @throws InvalidInterfaceException
1431
-     * @throws InvalidDataTypeException
1432
-     * @throws EE_Error
1433
-     */
1434
-    public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1435
-    {
1436
-        return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1437
-    }
1438
-
1439
-
1440
-    /**
1441
-     * @param string $field_name
1442
-     * @param string $dt_frmt
1443
-     * @param string $tm_frmt
1444
-     * @throws ReflectionException
1445
-     * @throws InvalidArgumentException
1446
-     * @throws InvalidInterfaceException
1447
-     * @throws InvalidDataTypeException
1448
-     * @throws EE_Error
1449
-     */
1450
-    public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1451
-    {
1452
-        $this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1453
-    }
1454
-
1455
-
1456
-    /**
1457
-     * Get the i8ln value for a date using the WordPress @see date_i18n function.
1458
-     *
1459
-     * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1460
-     * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1461
-     *                           on the object will be used.
1462
-     * @return string Date and time string in set locale or false if no field exists for the given
1463
-     * @throws ReflectionException
1464
-     * @throws InvalidArgumentException
1465
-     * @throws InvalidInterfaceException
1466
-     * @throws InvalidDataTypeException
1467
-     * @throws EE_Error
1468
-     *                           field name.
1469
-     */
1470
-    public function get_i18n_datetime($field_name, $format = '')
1471
-    {
1472
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1473
-        return date_i18n(
1474
-            $format,
1475
-            EEH_DTT_Helper::get_timestamp_with_offset(
1476
-                $this->get_raw($field_name),
1477
-                $this->_timezone
1478
-            )
1479
-        );
1480
-    }
1481
-
1482
-
1483
-    /**
1484
-     * This method validates whether the given field name is a valid field on the model object as well as it is of a
1485
-     * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1486
-     * thrown.
1487
-     *
1488
-     * @param  string $field_name The field name being checked
1489
-     * @throws ReflectionException
1490
-     * @throws InvalidArgumentException
1491
-     * @throws InvalidInterfaceException
1492
-     * @throws InvalidDataTypeException
1493
-     * @throws EE_Error
1494
-     * @return EE_Datetime_Field
1495
-     */
1496
-    protected function _get_dtt_field_settings($field_name)
1497
-    {
1498
-        $field = $this->get_model()->field_settings_for($field_name);
1499
-        //check if field is dtt
1500
-        if ($field instanceof EE_Datetime_Field) {
1501
-            return $field;
1502
-        }
1503
-        throw new EE_Error(
1504
-            sprintf(
1505
-                esc_html__(
1506
-                    'The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1507
-                    'event_espresso'
1508
-                ),
1509
-                $field_name,
1510
-                self::_get_model_classname(get_class($this))
1511
-            )
1512
-        );
1513
-    }
1514
-
1515
-
1516
-
1517
-
1518
-    /**
1519
-     * NOTE ABOUT BELOW:
1520
-     * These convenience date and time setters are for setting date and time independently.  In other words you might
1521
-     * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1522
-     * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1523
-     * method and make sure you send the entire datetime value for setting.
1524
-     */
1525
-    /**
1526
-     * sets the time on a datetime property
1527
-     *
1528
-     * @access protected
1529
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1530
-     * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1531
-     * @throws ReflectionException
1532
-     * @throws InvalidArgumentException
1533
-     * @throws InvalidInterfaceException
1534
-     * @throws InvalidDataTypeException
1535
-     * @throws EE_Error
1536
-     */
1537
-    protected function _set_time_for($time, $fieldname)
1538
-    {
1539
-        $this->_set_date_time('T', $time, $fieldname);
1540
-    }
1541
-
1542
-
1543
-    /**
1544
-     * sets the date on a datetime property
1545
-     *
1546
-     * @access protected
1547
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1548
-     * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1549
-     * @throws ReflectionException
1550
-     * @throws InvalidArgumentException
1551
-     * @throws InvalidInterfaceException
1552
-     * @throws InvalidDataTypeException
1553
-     * @throws EE_Error
1554
-     */
1555
-    protected function _set_date_for($date, $fieldname)
1556
-    {
1557
-        $this->_set_date_time('D', $date, $fieldname);
1558
-    }
1559
-
1560
-
1561
-    /**
1562
-     * This takes care of setting a date or time independently on a given model object property. This method also
1563
-     * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1564
-     *
1565
-     * @access protected
1566
-     * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1567
-     * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1568
-     * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1569
-     *                                        EE_Datetime_Field property)
1570
-     * @throws ReflectionException
1571
-     * @throws InvalidArgumentException
1572
-     * @throws InvalidInterfaceException
1573
-     * @throws InvalidDataTypeException
1574
-     * @throws EE_Error
1575
-     */
1576
-    protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1577
-    {
1578
-        $field = $this->_get_dtt_field_settings($fieldname);
1579
-        $field->set_timezone($this->_timezone);
1580
-        $field->set_date_format($this->_dt_frmt);
1581
-        $field->set_time_format($this->_tm_frmt);
1582
-        switch ($what) {
1583
-            case 'T' :
1584
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1585
-                    $datetime_value,
1586
-                    $this->_fields[ $fieldname ]
1587
-                );
1588
-                break;
1589
-            case 'D' :
1590
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1591
-                    $datetime_value,
1592
-                    $this->_fields[ $fieldname ]
1593
-                );
1594
-                break;
1595
-            case 'B' :
1596
-                $this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1597
-                break;
1598
-        }
1599
-        $this->_clear_cached_property($fieldname);
1600
-    }
1601
-
1602
-
1603
-    /**
1604
-     * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1605
-     * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1606
-     * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1607
-     * that could lead to some unexpected results!
1608
-     *
1609
-     * @access public
1610
-     * @param string $field_name               This is the name of the field on the object that contains the date/time
1611
-     *                                         value being returned.
1612
-     * @param string $callback                 must match a valid method in this class (defaults to get_datetime)
1613
-     * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1614
-     * @param string $prepend                  You can include something to prepend on the timestamp
1615
-     * @param string $append                   You can include something to append on the timestamp
1616
-     * @throws ReflectionException
1617
-     * @throws InvalidArgumentException
1618
-     * @throws InvalidInterfaceException
1619
-     * @throws InvalidDataTypeException
1620
-     * @throws EE_Error
1621
-     * @return string timestamp
1622
-     */
1623
-    public function display_in_my_timezone(
1624
-        $field_name,
1625
-        $callback = 'get_datetime',
1626
-        $args = null,
1627
-        $prepend = '',
1628
-        $append = ''
1629
-    ) {
1630
-        $timezone = EEH_DTT_Helper::get_timezone();
1631
-        if ($timezone === $this->_timezone) {
1632
-            return '';
1633
-        }
1634
-        $original_timezone = $this->_timezone;
1635
-        $this->set_timezone($timezone);
1636
-        $fn   = (array) $field_name;
1637
-        $args = array_merge($fn, (array) $args);
1638
-        if (! method_exists($this, $callback)) {
1639
-            throw new EE_Error(
1640
-                sprintf(
1641
-                    esc_html__(
1642
-                        'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1643
-                        'event_espresso'
1644
-                    ),
1645
-                    $callback
1646
-                )
1647
-            );
1648
-        }
1649
-        $args   = (array) $args;
1650
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1651
-        $this->set_timezone($original_timezone);
1652
-        return $return;
1653
-    }
1654
-
1655
-
1656
-    /**
1657
-     * Deletes this model object.
1658
-     * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1659
-     * override
1660
-     * `EE_Base_Class::_delete` NOT this class.
1661
-     *
1662
-     * @return boolean | int
1663
-     * @throws ReflectionException
1664
-     * @throws InvalidArgumentException
1665
-     * @throws InvalidInterfaceException
1666
-     * @throws InvalidDataTypeException
1667
-     * @throws EE_Error
1668
-     */
1669
-    public function delete()
1670
-    {
1671
-        /**
1672
-         * Called just before the `EE_Base_Class::_delete` method call.
1673
-         * Note:
1674
-         * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1675
-         * should be aware that `_delete` may not always result in a permanent delete.
1676
-         * For example, `EE_Soft_Delete_Base_Class::_delete`
1677
-         * soft deletes (trash) the object and does not permanently delete it.
1678
-         *
1679
-         * @param EE_Base_Class $model_object about to be 'deleted'
1680
-         */
1681
-        do_action('AHEE__EE_Base_Class__delete__before', $this);
1682
-        $result = $this->_delete();
1683
-        /**
1684
-         * Called just after the `EE_Base_Class::_delete` method call.
1685
-         * Note:
1686
-         * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1687
-         * should be aware that `_delete` may not always result in a permanent delete.
1688
-         * For example `EE_Soft_Base_Class::_delete`
1689
-         * soft deletes (trash) the object and does not permanently delete it.
1690
-         *
1691
-         * @param EE_Base_Class $model_object that was just 'deleted'
1692
-         * @param boolean       $result
1693
-         */
1694
-        do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1695
-        return $result;
1696
-    }
1697
-
1698
-
1699
-    /**
1700
-     * Calls the specific delete method for the instantiated class.
1701
-     * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1702
-     * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1703
-     * `EE_Base_Class::delete`
1704
-     *
1705
-     * @return bool|int
1706
-     * @throws ReflectionException
1707
-     * @throws InvalidArgumentException
1708
-     * @throws InvalidInterfaceException
1709
-     * @throws InvalidDataTypeException
1710
-     * @throws EE_Error
1711
-     */
1712
-    protected function _delete()
1713
-    {
1714
-        return $this->delete_permanently();
1715
-    }
1716
-
1717
-
1718
-    /**
1719
-     * Deletes this model object permanently from db
1720
-     * (but keep in mind related models may block the delete and return an error)
1721
-     *
1722
-     * @return bool | int
1723
-     * @throws ReflectionException
1724
-     * @throws InvalidArgumentException
1725
-     * @throws InvalidInterfaceException
1726
-     * @throws InvalidDataTypeException
1727
-     * @throws EE_Error
1728
-     */
1729
-    public function delete_permanently()
1730
-    {
1731
-        /**
1732
-         * Called just before HARD deleting a model object
1733
-         *
1734
-         * @param EE_Base_Class $model_object about to be 'deleted'
1735
-         */
1736
-        do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1737
-        $model  = $this->get_model();
1738
-        $result = $model->delete_permanently_by_ID($this->ID());
1739
-        $this->refresh_cache_of_related_objects();
1740
-        /**
1741
-         * Called just after HARD deleting a model object
1742
-         *
1743
-         * @param EE_Base_Class $model_object that was just 'deleted'
1744
-         * @param boolean       $result
1745
-         */
1746
-        do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1747
-        return $result;
1748
-    }
1749
-
1750
-
1751
-    /**
1752
-     * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1753
-     * related model objects
1754
-     *
1755
-     * @throws ReflectionException
1756
-     * @throws InvalidArgumentException
1757
-     * @throws InvalidInterfaceException
1758
-     * @throws InvalidDataTypeException
1759
-     * @throws EE_Error
1760
-     */
1761
-    public function refresh_cache_of_related_objects()
1762
-    {
1763
-        $model = $this->get_model();
1764
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1765
-            if (! empty($this->_model_relations[ $relation_name ])) {
1766
-                $related_objects = $this->_model_relations[ $relation_name ];
1767
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
1768
-                    //this relation only stores a single model object, not an array
1769
-                    //but let's make it consistent
1770
-                    $related_objects = array($related_objects);
1771
-                }
1772
-                foreach ($related_objects as $related_object) {
1773
-                    //only refresh their cache if they're in memory
1774
-                    if ($related_object instanceof EE_Base_Class) {
1775
-                        $related_object->clear_cache(
1776
-                            $model->get_this_model_name(),
1777
-                            $this
1778
-                        );
1779
-                    }
1780
-                }
1781
-            }
1782
-        }
1783
-    }
1784
-
1785
-
1786
-    /**
1787
-     *        Saves this object to the database. An array may be supplied to set some values on this
1788
-     * object just before saving.
1789
-     *
1790
-     * @access public
1791
-     * @param array $set_cols_n_values keys are field names, values are their new values,
1792
-     *                                 if provided during the save() method (often client code will change the fields'
1793
-     *                                 values before calling save)
1794
-     * @throws InvalidArgumentException
1795
-     * @throws InvalidInterfaceException
1796
-     * @throws InvalidDataTypeException
1797
-     * @throws EE_Error
1798
-     * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1799
-     *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1800
-     * @throws ReflectionException
1801
-     * @throws ReflectionException
1802
-     * @throws ReflectionException
1803
-     */
1804
-    public function save($set_cols_n_values = array())
1805
-    {
1806
-        $model = $this->get_model();
1807
-        /**
1808
-         * Filters the fields we're about to save on the model object
1809
-         *
1810
-         * @param array         $set_cols_n_values
1811
-         * @param EE_Base_Class $model_object
1812
-         */
1813
-        $set_cols_n_values = (array) apply_filters(
1814
-            'FHEE__EE_Base_Class__save__set_cols_n_values',
1815
-            $set_cols_n_values,
1816
-            $this
1817
-        );
1818
-        //set attributes as provided in $set_cols_n_values
1819
-        foreach ($set_cols_n_values as $column => $value) {
1820
-            $this->set($column, $value);
1821
-        }
1822
-        // no changes ? then don't do anything
1823
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1824
-            return 0;
1825
-        }
1826
-        /**
1827
-         * Saving a model object.
1828
-         * Before we perform a save, this action is fired.
1829
-         *
1830
-         * @param EE_Base_Class $model_object the model object about to be saved.
1831
-         */
1832
-        do_action('AHEE__EE_Base_Class__save__begin', $this);
1833
-        if (! $this->allow_persist()) {
1834
-            return 0;
1835
-        }
1836
-        // now get current attribute values
1837
-        $save_cols_n_values = $this->_fields;
1838
-        // if the object already has an ID, update it. Otherwise, insert it
1839
-        // also: change the assumption about values passed to the model NOT being prepare dby the model object.
1840
-        // They have been
1841
-        $old_assumption_concerning_value_preparation = $model
1842
-            ->get_assumption_concerning_values_already_prepared_by_model_object();
1843
-        $model->assume_values_already_prepared_by_model_object(true);
1844
-        //does this model have an autoincrement PK?
1845
-        if ($model->has_primary_key_field()) {
1846
-            if ($model->get_primary_key_field()->is_auto_increment()) {
1847
-                //ok check if it's set, if so: update; if not, insert
1848
-                if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1849
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1850
-                } else {
1851
-                    unset($save_cols_n_values[ $model->primary_key_name() ]);
1852
-                    $results = $model->insert($save_cols_n_values);
1853
-                    if ($results) {
1854
-                        //if successful, set the primary key
1855
-                        //but don't use the normal SET method, because it will check if
1856
-                        //an item with the same ID exists in the mapper & db, then
1857
-                        //will find it in the db (because we just added it) and THAT object
1858
-                        //will get added to the mapper before we can add this one!
1859
-                        //but if we just avoid using the SET method, all that headache can be avoided
1860
-                        $pk_field_name                   = $model->primary_key_name();
1861
-                        $this->_fields[ $pk_field_name ] = $results;
1862
-                        $this->_clear_cached_property($pk_field_name);
1863
-                        $model->add_to_entity_map($this);
1864
-                        $this->_update_cached_related_model_objs_fks();
1865
-                    }
1866
-                }
1867
-            } else {//PK is NOT auto-increment
1868
-                //so check if one like it already exists in the db
1869
-                if ($model->exists_by_ID($this->ID())) {
1870
-                    if (WP_DEBUG && ! $this->in_entity_map()) {
1871
-                        throw new EE_Error(
1872
-                            sprintf(
1873
-                                esc_html__(
1874
-                                    'Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1875
-                                    'event_espresso'
1876
-                                ),
1877
-                                get_class($this),
1878
-                                get_class($model) . '::instance()->add_to_entity_map()',
1879
-                                get_class($model) . '::instance()->get_one_by_ID()',
1880
-                                '<br />'
1881
-                            )
1882
-                        );
1883
-                    }
1884
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1885
-                } else {
1886
-                    $results = $model->insert($save_cols_n_values);
1887
-                    $this->_update_cached_related_model_objs_fks();
1888
-                }
1889
-            }
1890
-        } else {//there is NO primary key
1891
-            $already_in_db = false;
1892
-            foreach ($model->unique_indexes() as $index) {
1893
-                $uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1894
-                if ($model->exists(array($uniqueness_where_params))) {
1895
-                    $already_in_db = true;
1896
-                }
1897
-            }
1898
-            if ($already_in_db) {
1899
-                $combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1900
-                    $model->get_combined_primary_key_fields());
1901
-                $results                     = $model->update(
1902
-                    $save_cols_n_values,
1903
-                    $combined_pk_fields_n_values
1904
-                );
1905
-            } else {
1906
-                $results = $model->insert($save_cols_n_values);
1907
-            }
1908
-        }
1909
-        //restore the old assumption about values being prepared by the model object
1910
-        $model->assume_values_already_prepared_by_model_object(
1911
-                $old_assumption_concerning_value_preparation
1912
-            );
1913
-        /**
1914
-         * After saving the model object this action is called
1915
-         *
1916
-         * @param EE_Base_Class $model_object which was just saved
1917
-         * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1918
-         *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1919
-         */
1920
-        do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1921
-        $this->_has_changes = false;
1922
-        return $results;
1923
-    }
1924
-
1925
-
1926
-    /**
1927
-     * Updates the foreign key on related models objects pointing to this to have this model object's ID
1928
-     * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1929
-     * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1930
-     * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1931
-     * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1932
-     * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1933
-     * or not they exist in the DB (if they do, their DB records will be automatically updated)
1934
-     *
1935
-     * @return void
1936
-     * @throws ReflectionException
1937
-     * @throws InvalidArgumentException
1938
-     * @throws InvalidInterfaceException
1939
-     * @throws InvalidDataTypeException
1940
-     * @throws EE_Error
1941
-     */
1942
-    protected function _update_cached_related_model_objs_fks()
1943
-    {
1944
-        $model = $this->get_model();
1945
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1946
-            if ($relation_obj instanceof EE_Has_Many_Relation) {
1947
-                foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1948
-                    $fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1949
-                        $model->get_this_model_name()
1950
-                    );
1951
-                    $related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1952
-                    if ($related_model_obj_in_cache->ID()) {
1953
-                        $related_model_obj_in_cache->save();
1954
-                    }
1955
-                }
1956
-            }
1957
-        }
1958
-    }
1959
-
1960
-
1961
-    /**
1962
-     * Saves this model object and its NEW cached relations to the database.
1963
-     * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1964
-     * In order for that to work, we would need to mark model objects as dirty/clean...
1965
-     * because otherwise, there's a potential for infinite looping of saving
1966
-     * Saves the cached related model objects, and ensures the relation between them
1967
-     * and this object and properly setup
1968
-     *
1969
-     * @return int ID of new model object on save; 0 on failure+
1970
-     * @throws ReflectionException
1971
-     * @throws InvalidArgumentException
1972
-     * @throws InvalidInterfaceException
1973
-     * @throws InvalidDataTypeException
1974
-     * @throws EE_Error
1975
-     */
1976
-    public function save_new_cached_related_model_objs()
1977
-    {
1978
-        //make sure this has been saved
1979
-        if (! $this->ID()) {
1980
-            $id = $this->save();
1981
-        } else {
1982
-            $id = $this->ID();
1983
-        }
1984
-        //now save all the NEW cached model objects  (ie they don't exist in the DB)
1985
-        foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1986
-            if ($this->_model_relations[ $relationName ]) {
1987
-                //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1988
-                //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1989
-                /* @var $related_model_obj EE_Base_Class */
1990
-                if ($relationObj instanceof EE_Belongs_To_Relation) {
1991
-                    //add a relation to that relation type (which saves the appropriate thing in the process)
1992
-                    //but ONLY if it DOES NOT exist in the DB
1993
-                    $related_model_obj = $this->_model_relations[ $relationName ];
1994
-                    //					if( ! $related_model_obj->ID()){
1995
-                    $this->_add_relation_to($related_model_obj, $relationName);
1996
-                    $related_model_obj->save_new_cached_related_model_objs();
1997
-                    //					}
1998
-                } else {
1999
-                    foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2000
-                        //add a relation to that relation type (which saves the appropriate thing in the process)
2001
-                        //but ONLY if it DOES NOT exist in the DB
2002
-                        //						if( ! $related_model_obj->ID()){
2003
-                        $this->_add_relation_to($related_model_obj, $relationName);
2004
-                        $related_model_obj->save_new_cached_related_model_objs();
2005
-                        //						}
2006
-                    }
2007
-                }
2008
-            }
2009
-        }
2010
-        return $id;
2011
-    }
2012
-
2013
-
2014
-    /**
2015
-     * for getting a model while instantiated.
2016
-     *
2017
-     * @return EEM_Base | EEM_CPT_Base
2018
-     * @throws ReflectionException
2019
-     * @throws InvalidArgumentException
2020
-     * @throws InvalidInterfaceException
2021
-     * @throws InvalidDataTypeException
2022
-     * @throws EE_Error
2023
-     */
2024
-    public function get_model()
2025
-    {
2026
-        if (! $this->_model) {
2027
-            $modelName    = self::_get_model_classname(get_class($this));
2028
-            $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2029
-        } else {
2030
-            $this->_model->set_timezone($this->_timezone);
2031
-        }
2032
-        return $this->_model;
2033
-    }
2034
-
2035
-
2036
-    /**
2037
-     * @param $props_n_values
2038
-     * @param $classname
2039
-     * @return mixed bool|EE_Base_Class|EEM_CPT_Base
2040
-     * @throws ReflectionException
2041
-     * @throws InvalidArgumentException
2042
-     * @throws InvalidInterfaceException
2043
-     * @throws InvalidDataTypeException
2044
-     * @throws EE_Error
2045
-     */
2046
-    protected static function _get_object_from_entity_mapper($props_n_values, $classname)
2047
-    {
2048
-        //TODO: will not work for Term_Relationships because they have no PK!
2049
-        $primary_id_ref = self::_get_primary_key_name($classname);
2050
-        if (
2051
-            array_key_exists($primary_id_ref, $props_n_values)
2052
-            && ! empty($props_n_values[ $primary_id_ref ])
2053
-        ) {
2054
-            $id = $props_n_values[ $primary_id_ref ];
2055
-            return self::_get_model($classname)->get_from_entity_map($id);
2056
-        }
2057
-        return false;
2058
-    }
2059
-
2060
-
2061
-    /**
2062
-     * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
2063
-     * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
2064
-     * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
2065
-     * we return false.
2066
-     *
2067
-     * @param  array  $props_n_values   incoming array of properties and their values
2068
-     * @param  string $classname        the classname of the child class
2069
-     * @param null    $timezone
2070
-     * @param array   $date_formats     incoming date_formats in an array where the first value is the
2071
-     *                                  date_format and the second value is the time format
2072
-     * @return mixed (EE_Base_Class|bool)
2073
-     * @throws InvalidArgumentException
2074
-     * @throws InvalidInterfaceException
2075
-     * @throws InvalidDataTypeException
2076
-     * @throws EE_Error
2077
-     * @throws ReflectionException
2078
-     * @throws ReflectionException
2079
-     * @throws ReflectionException
2080
-     */
2081
-    protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
2082
-    {
2083
-        $existing = null;
2084
-        $model    = self::_get_model($classname, $timezone);
2085
-        if ($model->has_primary_key_field()) {
2086
-            $primary_id_ref = self::_get_primary_key_name($classname);
2087
-            if (array_key_exists($primary_id_ref, $props_n_values)
2088
-                && ! empty($props_n_values[ $primary_id_ref ])
2089
-            ) {
2090
-                $existing = $model->get_one_by_ID(
2091
-                    $props_n_values[ $primary_id_ref ]
2092
-                );
2093
-            }
2094
-        } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
2095
-            //no primary key on this model, but there's still a matching item in the DB
2096
-            $existing = self::_get_model($classname, $timezone)->get_one_by_ID(
2097
-                self::_get_model($classname, $timezone)
2098
-                    ->get_index_primary_key_string($props_n_values)
2099
-            );
2100
-        }
2101
-        if ($existing) {
2102
-            //set date formats if present before setting values
2103
-            if (! empty($date_formats) && is_array($date_formats)) {
2104
-                $existing->set_date_format($date_formats[0]);
2105
-                $existing->set_time_format($date_formats[1]);
2106
-            } else {
2107
-                //set default formats for date and time
2108
-                $existing->set_date_format(get_option('date_format'));
2109
-                $existing->set_time_format(get_option('time_format'));
2110
-            }
2111
-            foreach ($props_n_values as $property => $field_value) {
2112
-                $existing->set($property, $field_value);
2113
-            }
2114
-            return $existing;
2115
-        }
2116
-        return false;
2117
-    }
2118
-
2119
-
2120
-    /**
2121
-     * Gets the EEM_*_Model for this class
2122
-     *
2123
-     * @access public now, as this is more convenient
2124
-     * @param      $classname
2125
-     * @param null $timezone
2126
-     * @throws ReflectionException
2127
-     * @throws InvalidArgumentException
2128
-     * @throws InvalidInterfaceException
2129
-     * @throws InvalidDataTypeException
2130
-     * @throws EE_Error
2131
-     * @return EEM_Base
2132
-     */
2133
-    protected static function _get_model($classname, $timezone = null)
2134
-    {
2135
-        //find model for this class
2136
-        if (! $classname) {
2137
-            throw new EE_Error(
2138
-                sprintf(
2139
-                    esc_html__(
2140
-                        'What were you thinking calling _get_model(%s)?? You need to specify the class name',
2141
-                        'event_espresso'
2142
-                    ),
2143
-                    $classname
2144
-                )
2145
-            );
2146
-        }
2147
-        $modelName = self::_get_model_classname($classname);
2148
-        return self::_get_model_instance_with_name($modelName, $timezone);
2149
-    }
2150
-
2151
-
2152
-    /**
2153
-     * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2154
-     *
2155
-     * @param string $model_classname
2156
-     * @param null   $timezone
2157
-     * @return EEM_Base
2158
-     * @throws ReflectionException
2159
-     * @throws InvalidArgumentException
2160
-     * @throws InvalidInterfaceException
2161
-     * @throws InvalidDataTypeException
2162
-     * @throws EE_Error
2163
-     */
2164
-    protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2165
-    {
2166
-        $model_classname = str_replace('EEM_', '', $model_classname);
2167
-        $model           = EE_Registry::instance()->load_model($model_classname);
2168
-        $model->set_timezone($timezone);
2169
-        return $model;
2170
-    }
2171
-
2172
-
2173
-    /**
2174
-     * If a model name is provided (eg Registration), gets the model classname for that model.
2175
-     * Also works if a model class's classname is provided (eg EE_Registration).
2176
-     *
2177
-     * @param null $model_name
2178
-     * @return string like EEM_Attendee
2179
-     */
2180
-    private static function _get_model_classname($model_name = null)
2181
-    {
2182
-        if (strpos($model_name, 'EE_') === 0) {
2183
-            $model_classname = str_replace('EE_', 'EEM_', $model_name);
2184
-        } else {
2185
-            $model_classname = 'EEM_' . $model_name;
2186
-        }
2187
-        return $model_classname;
2188
-    }
2189
-
2190
-
2191
-    /**
2192
-     * returns the name of the primary key attribute
2193
-     *
2194
-     * @param null $classname
2195
-     * @throws ReflectionException
2196
-     * @throws InvalidArgumentException
2197
-     * @throws InvalidInterfaceException
2198
-     * @throws InvalidDataTypeException
2199
-     * @throws EE_Error
2200
-     * @return string
2201
-     */
2202
-    protected static function _get_primary_key_name($classname = null)
2203
-    {
2204
-        if (! $classname) {
2205
-            throw new EE_Error(
2206
-                sprintf(
2207
-                    esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
2208
-                    $classname
2209
-                )
2210
-            );
2211
-        }
2212
-        return self::_get_model($classname)->get_primary_key_field()->get_name();
2213
-    }
2214
-
2215
-
2216
-    /**
2217
-     * Gets the value of the primary key.
2218
-     * If the object hasn't yet been saved, it should be whatever the model field's default was
2219
-     * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2220
-     * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2221
-     *
2222
-     * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2223
-     * @throws ReflectionException
2224
-     * @throws InvalidArgumentException
2225
-     * @throws InvalidInterfaceException
2226
-     * @throws InvalidDataTypeException
2227
-     * @throws EE_Error
2228
-     */
2229
-    public function ID()
2230
-    {
2231
-        $model = $this->get_model();
2232
-        //now that we know the name of the variable, use a variable variable to get its value and return its
2233
-        if ($model->has_primary_key_field()) {
2234
-            return $this->_fields[ $model->primary_key_name() ];
2235
-        }
2236
-        return $model->get_index_primary_key_string($this->_fields);
2237
-    }
2238
-
2239
-
2240
-    /**
2241
-     * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2242
-     * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2243
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2244
-     *
2245
-     * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2246
-     * @param string $relationName                     eg 'Events','Question',etc.
2247
-     *                                                 an attendee to a group, you also want to specify which role they
2248
-     *                                                 will have in that group. So you would use this parameter to
2249
-     *                                                 specify array('role-column-name'=>'role-id')
2250
-     * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2251
-     *                                                 allow you to further constrict the relation to being added.
2252
-     *                                                 However, keep in mind that the columns (keys) given must match a
2253
-     *                                                 column on the JOIN table and currently only the HABTM models
2254
-     *                                                 accept these additional conditions.  Also remember that if an
2255
-     *                                                 exact match isn't found for these extra cols/val pairs, then a
2256
-     *                                                 NEW row is created in the join table.
2257
-     * @param null   $cache_id
2258
-     * @throws ReflectionException
2259
-     * @throws InvalidArgumentException
2260
-     * @throws InvalidInterfaceException
2261
-     * @throws InvalidDataTypeException
2262
-     * @throws EE_Error
2263
-     * @return EE_Base_Class the object the relation was added to
2264
-     */
2265
-    public function _add_relation_to(
2266
-        $otherObjectModelObjectOrID,
2267
-        $relationName,
2268
-        $extra_join_model_fields_n_values = array(),
2269
-        $cache_id = null
2270
-    ) {
2271
-        $model = $this->get_model();
2272
-        //if this thing exists in the DB, save the relation to the DB
2273
-        if ($this->ID()) {
2274
-            $otherObject = $model->add_relationship_to(
2275
-                $this,
2276
-                $otherObjectModelObjectOrID,
2277
-                $relationName,
2278
-                $extra_join_model_fields_n_values
2279
-            );
2280
-            //clear cache so future get_many_related and get_first_related() return new results.
2281
-            $this->clear_cache($relationName, $otherObject, true);
2282
-            if ($otherObject instanceof EE_Base_Class) {
2283
-                $otherObject->clear_cache($model->get_this_model_name(), $this);
2284
-            }
2285
-        } else {
2286
-            //this thing doesn't exist in the DB,  so just cache it
2287
-            if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2288
-                throw new EE_Error(
2289
-                    sprintf(
2290
-                        esc_html__(
2291
-                            'Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2292
-                            'event_espresso'
2293
-                        ),
2294
-                        $otherObjectModelObjectOrID,
2295
-                        get_class($this)
2296
-                    )
2297
-                );
2298
-            }
2299
-            $otherObject = $otherObjectModelObjectOrID;
2300
-            $this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2301
-        }
2302
-        if ($otherObject instanceof EE_Base_Class) {
2303
-            //fix the reciprocal relation too
2304
-            if ($otherObject->ID()) {
2305
-                //its saved so assumed relations exist in the DB, so we can just
2306
-                //clear the cache so future queries use the updated info in the DB
2307
-                $otherObject->clear_cache(
2308
-                    $model->get_this_model_name(),
2309
-                    null,
2310
-                    true
2311
-                );
2312
-            } else {
2313
-                //it's not saved, so it caches relations like this
2314
-                $otherObject->cache($model->get_this_model_name(), $this);
2315
-            }
2316
-        }
2317
-        return $otherObject;
2318
-    }
2319
-
2320
-
2321
-    /**
2322
-     * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2323
-     * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2324
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2325
-     * from the cache
2326
-     *
2327
-     * @param mixed  $otherObjectModelObjectOrID
2328
-     *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2329
-     *                to the DB yet
2330
-     * @param string $relationName
2331
-     * @param array  $where_query
2332
-     *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2333
-     *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2334
-     *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2335
-     *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2336
-     *                created in the join table.
2337
-     * @return EE_Base_Class the relation was removed from
2338
-     * @throws ReflectionException
2339
-     * @throws InvalidArgumentException
2340
-     * @throws InvalidInterfaceException
2341
-     * @throws InvalidDataTypeException
2342
-     * @throws EE_Error
2343
-     */
2344
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2345
-    {
2346
-        if ($this->ID()) {
2347
-            //if this exists in the DB, save the relation change to the DB too
2348
-            $otherObject = $this->get_model()->remove_relationship_to(
2349
-                $this,
2350
-                $otherObjectModelObjectOrID,
2351
-                $relationName,
2352
-                $where_query
2353
-            );
2354
-            $this->clear_cache(
2355
-                $relationName,
2356
-                $otherObject
2357
-            );
2358
-        } else {
2359
-            //this doesn't exist in the DB, just remove it from the cache
2360
-            $otherObject = $this->clear_cache(
2361
-                $relationName,
2362
-                $otherObjectModelObjectOrID
2363
-            );
2364
-        }
2365
-        if ($otherObject instanceof EE_Base_Class) {
2366
-            $otherObject->clear_cache(
2367
-                $this->get_model()->get_this_model_name(),
2368
-                $this
2369
-            );
2370
-        }
2371
-        return $otherObject;
2372
-    }
2373
-
2374
-
2375
-    /**
2376
-     * Removes ALL the related things for the $relationName.
2377
-     *
2378
-     * @param string $relationName
2379
-     * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2380
-     * @return EE_Base_Class
2381
-     * @throws ReflectionException
2382
-     * @throws InvalidArgumentException
2383
-     * @throws InvalidInterfaceException
2384
-     * @throws InvalidDataTypeException
2385
-     * @throws EE_Error
2386
-     */
2387
-    public function _remove_relations($relationName, $where_query_params = array())
2388
-    {
2389
-        if ($this->ID()) {
2390
-            //if this exists in the DB, save the relation change to the DB too
2391
-            $otherObjects = $this->get_model()->remove_relations(
2392
-                $this,
2393
-                $relationName,
2394
-                $where_query_params
2395
-            );
2396
-            $this->clear_cache(
2397
-                $relationName,
2398
-                null,
2399
-                true
2400
-            );
2401
-        } else {
2402
-            //this doesn't exist in the DB, just remove it from the cache
2403
-            $otherObjects = $this->clear_cache(
2404
-                $relationName,
2405
-                null,
2406
-                true
2407
-            );
2408
-        }
2409
-        if (is_array($otherObjects)) {
2410
-            foreach ($otherObjects as $otherObject) {
2411
-                $otherObject->clear_cache(
2412
-                    $this->get_model()->get_this_model_name(),
2413
-                    $this
2414
-                );
2415
-            }
2416
-        }
2417
-        return $otherObjects;
2418
-    }
2419
-
2420
-
2421
-    /**
2422
-     * Gets all the related model objects of the specified type. Eg, if the current class if
2423
-     * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2424
-     * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2425
-     * because we want to get even deleted items etc.
2426
-     *
2427
-     * @param string $relationName key in the model's _model_relations array
2428
-     * @param array  $query_params like EEM_Base::get_all
2429
-     * @return EE_Base_Class[]     Results not necessarily indexed by IDs, because some results might not have primary
2430
-     *                             keys or might not be saved yet. Consider using EEM_Base::get_IDs() on these
2431
-     *                             results if you want IDs
2432
-     * @throws ReflectionException
2433
-     * @throws InvalidArgumentException
2434
-     * @throws InvalidInterfaceException
2435
-     * @throws InvalidDataTypeException
2436
-     * @throws EE_Error
2437
-     */
2438
-    public function get_many_related($relationName, $query_params = array())
2439
-    {
2440
-        if ($this->ID()) {
2441
-            //this exists in the DB, so get the related things from either the cache or the DB
2442
-            //if there are query parameters, forget about caching the related model objects.
2443
-            if ($query_params) {
2444
-                $related_model_objects = $this->get_model()->get_all_related(
2445
-                    $this,
2446
-                    $relationName,
2447
-                    $query_params
2448
-                );
2449
-            } else {
2450
-                //did we already cache the result of this query?
2451
-                $cached_results = $this->get_all_from_cache($relationName);
2452
-                if (! $cached_results) {
2453
-                    $related_model_objects = $this->get_model()->get_all_related(
2454
-                        $this,
2455
-                        $relationName,
2456
-                        $query_params
2457
-                    );
2458
-                    //if no query parameters were passed, then we got all the related model objects
2459
-                    //for that relation. We can cache them then.
2460
-                    foreach ($related_model_objects as $related_model_object) {
2461
-                        $this->cache($relationName, $related_model_object);
2462
-                    }
2463
-                } else {
2464
-                    $related_model_objects = $cached_results;
2465
-                }
2466
-            }
2467
-        } else {
2468
-            //this doesn't exist in the DB, so just get the related things from the cache
2469
-            $related_model_objects = $this->get_all_from_cache($relationName);
2470
-        }
2471
-        return $related_model_objects;
2472
-    }
2473
-
2474
-
2475
-    /**
2476
-     * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2477
-     * unless otherwise specified in the $query_params
2478
-     *
2479
-     * @param string $relation_name  model_name like 'Event', or 'Registration'
2480
-     * @param array  $query_params   like EEM_Base::get_all's
2481
-     * @param string $field_to_count name of field to count by. By default, uses primary key
2482
-     * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2483
-     *                               that by the setting $distinct to TRUE;
2484
-     * @return int
2485
-     * @throws ReflectionException
2486
-     * @throws InvalidArgumentException
2487
-     * @throws InvalidInterfaceException
2488
-     * @throws InvalidDataTypeException
2489
-     * @throws EE_Error
2490
-     */
2491
-    public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2492
-    {
2493
-        return $this->get_model()->count_related(
2494
-            $this,
2495
-            $relation_name,
2496
-            $query_params,
2497
-            $field_to_count,
2498
-            $distinct
2499
-        );
2500
-    }
2501
-
2502
-
2503
-    /**
2504
-     * Instead of getting the related model objects, simply sums up the values of the specified field.
2505
-     * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2506
-     *
2507
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2508
-     * @param array  $query_params  like EEM_Base::get_all's
2509
-     * @param string $field_to_sum  name of field to count by.
2510
-     *                              By default, uses primary key
2511
-     *                              (which doesn't make much sense, so you should probably change it)
2512
-     * @return int
2513
-     * @throws ReflectionException
2514
-     * @throws InvalidArgumentException
2515
-     * @throws InvalidInterfaceException
2516
-     * @throws InvalidDataTypeException
2517
-     * @throws EE_Error
2518
-     */
2519
-    public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2520
-    {
2521
-        return $this->get_model()->sum_related(
2522
-            $this,
2523
-            $relation_name,
2524
-            $query_params,
2525
-            $field_to_sum
2526
-        );
2527
-    }
2528
-
2529
-
2530
-    /**
2531
-     * Gets the first (ie, one) related model object of the specified type.
2532
-     *
2533
-     * @param string $relationName key in the model's _model_relations array
2534
-     * @param array  $query_params like EEM_Base::get_all
2535
-     * @return EE_Base_Class (not an array, a single object)
2536
-     * @throws ReflectionException
2537
-     * @throws InvalidArgumentException
2538
-     * @throws InvalidInterfaceException
2539
-     * @throws InvalidDataTypeException
2540
-     * @throws EE_Error
2541
-     */
2542
-    public function get_first_related($relationName, $query_params = array())
2543
-    {
2544
-        $model = $this->get_model();
2545
-        if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2546
-            //if they've provided some query parameters, don't bother trying to cache the result
2547
-            //also make sure we're not caching the result of get_first_related
2548
-            //on a relation which should have an array of objects (because the cache might have an array of objects)
2549
-            if ($query_params
2550
-                || ! $model->related_settings_for($relationName)
2551
-                     instanceof
2552
-                     EE_Belongs_To_Relation
2553
-            ) {
2554
-                $related_model_object = $model->get_first_related(
2555
-                    $this,
2556
-                    $relationName,
2557
-                    $query_params
2558
-                );
2559
-            } else {
2560
-                //first, check if we've already cached the result of this query
2561
-                $cached_result = $this->get_one_from_cache($relationName);
2562
-                if (! $cached_result) {
2563
-                    $related_model_object = $model->get_first_related(
2564
-                        $this,
2565
-                        $relationName,
2566
-                        $query_params
2567
-                    );
2568
-                    $this->cache($relationName, $related_model_object);
2569
-                } else {
2570
-                    $related_model_object = $cached_result;
2571
-                }
2572
-            }
2573
-        } else {
2574
-            $related_model_object = null;
2575
-            // this doesn't exist in the Db,
2576
-            // but maybe the relation is of type belongs to, and so the related thing might
2577
-            if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2578
-                $related_model_object = $model->get_first_related(
2579
-                    $this,
2580
-                    $relationName,
2581
-                    $query_params
2582
-                );
2583
-            }
2584
-            // this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2585
-            // just get what's cached on this object
2586
-            if (! $related_model_object) {
2587
-                $related_model_object = $this->get_one_from_cache($relationName);
2588
-            }
2589
-        }
2590
-        return $related_model_object;
2591
-    }
2592
-
2593
-
2594
-    /**
2595
-     * Does a delete on all related objects of type $relationName and removes
2596
-     * the current model object's relation to them. If they can't be deleted (because
2597
-     * of blocking related model objects) does nothing. If the related model objects are
2598
-     * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2599
-     * If this model object doesn't exist yet in the DB, just removes its related things
2600
-     *
2601
-     * @param string $relationName
2602
-     * @param array  $query_params like EEM_Base::get_all's
2603
-     * @return int how many deleted
2604
-     * @throws ReflectionException
2605
-     * @throws InvalidArgumentException
2606
-     * @throws InvalidInterfaceException
2607
-     * @throws InvalidDataTypeException
2608
-     * @throws EE_Error
2609
-     */
2610
-    public function delete_related($relationName, $query_params = array())
2611
-    {
2612
-        if ($this->ID()) {
2613
-            $count = $this->get_model()->delete_related(
2614
-                $this,
2615
-                $relationName,
2616
-                $query_params
2617
-            );
2618
-        } else {
2619
-            $count = count($this->get_all_from_cache($relationName));
2620
-            $this->clear_cache($relationName, null, true);
2621
-        }
2622
-        return $count;
2623
-    }
2624
-
2625
-
2626
-    /**
2627
-     * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2628
-     * the current model object's relation to them. If they can't be deleted (because
2629
-     * of blocking related model objects) just does a soft delete on it instead, if possible.
2630
-     * If the related thing isn't a soft-deletable model object, this function is identical
2631
-     * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2632
-     *
2633
-     * @param string $relationName
2634
-     * @param array  $query_params like EEM_Base::get_all's
2635
-     * @return int how many deleted (including those soft deleted)
2636
-     * @throws ReflectionException
2637
-     * @throws InvalidArgumentException
2638
-     * @throws InvalidInterfaceException
2639
-     * @throws InvalidDataTypeException
2640
-     * @throws EE_Error
2641
-     */
2642
-    public function delete_related_permanently($relationName, $query_params = array())
2643
-    {
2644
-        if ($this->ID()) {
2645
-            $count = $this->get_model()->delete_related_permanently(
2646
-                $this,
2647
-                $relationName,
2648
-                $query_params
2649
-            );
2650
-        } else {
2651
-            $count = count($this->get_all_from_cache($relationName));
2652
-        }
2653
-        $this->clear_cache($relationName, null, true);
2654
-        return $count;
2655
-    }
2656
-
2657
-
2658
-    /**
2659
-     * is_set
2660
-     * Just a simple utility function children can use for checking if property exists
2661
-     *
2662
-     * @access  public
2663
-     * @param  string $field_name property to check
2664
-     * @return bool                              TRUE if existing,FALSE if not.
2665
-     */
2666
-    public function is_set($field_name)
2667
-    {
2668
-        return isset($this->_fields[ $field_name ]);
2669
-    }
2670
-
2671
-
2672
-    /**
2673
-     * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2674
-     * EE_Error exception if they don't
2675
-     *
2676
-     * @param  mixed (string|array) $properties properties to check
2677
-     * @throws EE_Error
2678
-     * @return bool                              TRUE if existing, throw EE_Error if not.
2679
-     */
2680
-    protected function _property_exists($properties)
2681
-    {
2682
-        foreach ((array) $properties as $property_name) {
2683
-            //first make sure this property exists
2684
-            if (! $this->_fields[ $property_name ]) {
2685
-                throw new EE_Error(
2686
-                    sprintf(
2687
-                        esc_html__(
2688
-                            'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2689
-                            'event_espresso'
2690
-                        ),
2691
-                        $property_name
2692
-                    )
2693
-                );
2694
-            }
2695
-        }
2696
-        return true;
2697
-    }
2698
-
2699
-
2700
-    /**
2701
-     * This simply returns an array of model fields for this object
2702
-     *
2703
-     * @return array
2704
-     * @throws ReflectionException
2705
-     * @throws InvalidArgumentException
2706
-     * @throws InvalidInterfaceException
2707
-     * @throws InvalidDataTypeException
2708
-     * @throws EE_Error
2709
-     */
2710
-    public function model_field_array()
2711
-    {
2712
-        $fields     = $this->get_model()->field_settings(false);
2713
-        $properties = array();
2714
-        //remove prepended underscore
2715
-        foreach ($fields as $field_name => $settings) {
2716
-            $properties[ $field_name ] = $this->get($field_name);
2717
-        }
2718
-        return $properties;
2719
-    }
2720
-
2721
-
2722
-    /**
2723
-     * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2724
-     * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2725
-     * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments.
2726
-     * Instead of requiring a plugin to extend the EE_Base_Class
2727
-     * (which works fine is there's only 1 plugin, but when will that happen?)
2728
-     * they can add a hook onto 'filters_hook_espresso__{className}__{methodName}'
2729
-     * (eg, filters_hook_espresso__EE_Answer__my_great_function)
2730
-     * and accepts 2 arguments: the object on which the function was called,
2731
-     * and an array of the original arguments passed to the function.
2732
-     * Whatever their callback function returns will be returned by this function.
2733
-     * Example: in functions.php (or in a plugin):
2734
-     *      add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3);
2735
-     *      function my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2736
-     *          $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2737
-     *          return $previousReturnValue.$returnString;
2738
-     *      }
2739
-     * require('EE_Answer.class.php');
2740
-     * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2741
-     * echo $answer->my_callback('monkeys',100);
2742
-     * //will output "you called my_callback! and passed args:monkeys,100"
2743
-     *
2744
-     * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2745
-     * @param array  $args       array of original arguments passed to the function
2746
-     * @throws EE_Error
2747
-     * @return mixed whatever the plugin which calls add_filter decides
2748
-     */
2749
-    public function __call($methodName, $args)
2750
-    {
2751
-        $className = get_class($this);
2752
-        $tagName   = "FHEE__{$className}__{$methodName}";
2753
-        if (! has_filter($tagName)) {
2754
-            throw new EE_Error(
2755
-                sprintf(
2756
-                    esc_html__(
2757
-                        "Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2758
-                        'event_espresso'
2759
-                    ),
2760
-                    $methodName,
2761
-                    $className,
2762
-                    $tagName
2763
-                )
2764
-            );
2765
-        }
2766
-        return apply_filters($tagName, null, $this, $args);
2767
-    }
2768
-
2769
-
2770
-    /**
2771
-     * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2772
-     * A $previous_value can be specified in case there are many meta rows with the same key
2773
-     *
2774
-     * @param string $meta_key
2775
-     * @param mixed  $meta_value
2776
-     * @param mixed  $previous_value
2777
-     * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2778
-     *                  NOTE: if the values haven't changed, returns 0
2779
-     * @throws InvalidArgumentException
2780
-     * @throws InvalidInterfaceException
2781
-     * @throws InvalidDataTypeException
2782
-     * @throws EE_Error
2783
-     * @throws ReflectionException
2784
-     */
2785
-    public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2786
-    {
2787
-        $query_params = array(
2788
-            array(
2789
-                'EXM_key'  => $meta_key,
2790
-                'OBJ_ID'   => $this->ID(),
2791
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2792
-            ),
2793
-        );
2794
-        if ($previous_value !== null) {
2795
-            $query_params[0]['EXM_value'] = $meta_value;
2796
-        }
2797
-        $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2798
-        if (! $existing_rows_like_that) {
2799
-            return $this->add_extra_meta($meta_key, $meta_value);
2800
-        }
2801
-        foreach ($existing_rows_like_that as $existing_row) {
2802
-            $existing_row->save(array('EXM_value' => $meta_value));
2803
-        }
2804
-        return count($existing_rows_like_that);
2805
-    }
2806
-
2807
-
2808
-    /**
2809
-     * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2810
-     * no other extra meta for this model object have the same key. Returns TRUE if the
2811
-     * extra meta row was entered, false if not
2812
-     *
2813
-     * @param string  $meta_key
2814
-     * @param mixed   $meta_value
2815
-     * @param boolean $unique
2816
-     * @return boolean
2817
-     * @throws InvalidArgumentException
2818
-     * @throws InvalidInterfaceException
2819
-     * @throws InvalidDataTypeException
2820
-     * @throws EE_Error
2821
-     * @throws ReflectionException
2822
-     * @throws ReflectionException
2823
-     */
2824
-    public function add_extra_meta($meta_key, $meta_value, $unique = false)
2825
-    {
2826
-        if ($unique) {
2827
-            $existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2828
-                array(
2829
-                    array(
2830
-                        'EXM_key'  => $meta_key,
2831
-                        'OBJ_ID'   => $this->ID(),
2832
-                        'EXM_type' => $this->get_model()->get_this_model_name(),
2833
-                    ),
2834
-                )
2835
-            );
2836
-            if ($existing_extra_meta) {
2837
-                return false;
2838
-            }
2839
-        }
2840
-        $new_extra_meta = EE_Extra_Meta::new_instance(
2841
-            array(
2842
-                'EXM_key'   => $meta_key,
2843
-                'EXM_value' => $meta_value,
2844
-                'OBJ_ID'    => $this->ID(),
2845
-                'EXM_type'  => $this->get_model()->get_this_model_name(),
2846
-            )
2847
-        );
2848
-        $new_extra_meta->save();
2849
-        return true;
2850
-    }
2851
-
2852
-
2853
-    /**
2854
-     * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2855
-     * is specified, only deletes extra meta records with that value.
2856
-     *
2857
-     * @param string $meta_key
2858
-     * @param mixed  $meta_value
2859
-     * @return int number of extra meta rows deleted
2860
-     * @throws InvalidArgumentException
2861
-     * @throws InvalidInterfaceException
2862
-     * @throws InvalidDataTypeException
2863
-     * @throws EE_Error
2864
-     * @throws ReflectionException
2865
-     */
2866
-    public function delete_extra_meta($meta_key, $meta_value = null)
2867
-    {
2868
-        $query_params = array(
2869
-            array(
2870
-                'EXM_key'  => $meta_key,
2871
-                'OBJ_ID'   => $this->ID(),
2872
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2873
-            ),
2874
-        );
2875
-        if ($meta_value !== null) {
2876
-            $query_params[0]['EXM_value'] = $meta_value;
2877
-        }
2878
-        return EEM_Extra_Meta::instance()->delete($query_params);
2879
-    }
2880
-
2881
-
2882
-    /**
2883
-     * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2884
-     * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2885
-     * You can specify $default is case you haven't found the extra meta
2886
-     *
2887
-     * @param string  $meta_key
2888
-     * @param boolean $single
2889
-     * @param mixed   $default if we don't find anything, what should we return?
2890
-     * @return mixed single value if $single; array if ! $single
2891
-     * @throws ReflectionException
2892
-     * @throws InvalidArgumentException
2893
-     * @throws InvalidInterfaceException
2894
-     * @throws InvalidDataTypeException
2895
-     * @throws EE_Error
2896
-     */
2897
-    public function get_extra_meta($meta_key, $single = false, $default = null)
2898
-    {
2899
-        if ($single) {
2900
-            $result = $this->get_first_related(
2901
-                'Extra_Meta',
2902
-                array(array('EXM_key' => $meta_key))
2903
-            );
2904
-            if ($result instanceof EE_Extra_Meta) {
2905
-                return $result->value();
2906
-            }
2907
-        } else {
2908
-            $results = $this->get_many_related(
2909
-                'Extra_Meta',
2910
-                array(array('EXM_key' => $meta_key))
2911
-            );
2912
-            if ($results) {
2913
-                $values = array();
2914
-                foreach ($results as $result) {
2915
-                    if ($result instanceof EE_Extra_Meta) {
2916
-                        $values[ $result->ID() ] = $result->value();
2917
-                    }
2918
-                }
2919
-                return $values;
2920
-            }
2921
-        }
2922
-        //if nothing discovered yet return default.
2923
-        return apply_filters(
2924
-            'FHEE__EE_Base_Class__get_extra_meta__default_value',
2925
-            $default,
2926
-            $meta_key,
2927
-            $single,
2928
-            $this
2929
-        );
2930
-    }
2931
-
2932
-
2933
-    /**
2934
-     * Returns a simple array of all the extra meta associated with this model object.
2935
-     * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2936
-     * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2937
-     * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2938
-     * If $one_of_each_key is false, it will return an array with the top-level keys being
2939
-     * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2940
-     * finally the extra meta's value as each sub-value. (eg
2941
-     * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2942
-     *
2943
-     * @param boolean $one_of_each_key
2944
-     * @return array
2945
-     * @throws ReflectionException
2946
-     * @throws InvalidArgumentException
2947
-     * @throws InvalidInterfaceException
2948
-     * @throws InvalidDataTypeException
2949
-     * @throws EE_Error
2950
-     */
2951
-    public function all_extra_meta_array($one_of_each_key = true)
2952
-    {
2953
-        $return_array = array();
2954
-        if ($one_of_each_key) {
2955
-            $extra_meta_objs = $this->get_many_related(
2956
-                'Extra_Meta',
2957
-                array('group_by' => 'EXM_key')
2958
-            );
2959
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2960
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2961
-                    $return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2962
-                }
2963
-            }
2964
-        } else {
2965
-            $extra_meta_objs = $this->get_many_related('Extra_Meta');
2966
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2967
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2968
-                    if (! isset($return_array[ $extra_meta_obj->key() ])) {
2969
-                        $return_array[ $extra_meta_obj->key() ] = array();
2970
-                    }
2971
-                    $return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2972
-                }
2973
-            }
2974
-        }
2975
-        return $return_array;
2976
-    }
2977
-
2978
-
2979
-    /**
2980
-     * Gets a pretty nice displayable nice for this model object. Often overridden
2981
-     *
2982
-     * @return string
2983
-     * @throws ReflectionException
2984
-     * @throws InvalidArgumentException
2985
-     * @throws InvalidInterfaceException
2986
-     * @throws InvalidDataTypeException
2987
-     * @throws EE_Error
2988
-     */
2989
-    public function name()
2990
-    {
2991
-        //find a field that's not a text field
2992
-        $field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2993
-        if ($field_we_can_use) {
2994
-            return $this->get($field_we_can_use->get_name());
2995
-        }
2996
-        $first_few_properties = $this->model_field_array();
2997
-        $first_few_properties = array_slice($first_few_properties, 0, 3);
2998
-        $name_parts           = array();
2999
-        foreach ($first_few_properties as $name => $value) {
3000
-            $name_parts[] = "$name:$value";
3001
-        }
3002
-        return implode(',', $name_parts);
3003
-    }
3004
-
3005
-
3006
-    /**
3007
-     * in_entity_map
3008
-     * Checks if this model object has been proven to already be in the entity map
3009
-     *
3010
-     * @return boolean
3011
-     * @throws ReflectionException
3012
-     * @throws InvalidArgumentException
3013
-     * @throws InvalidInterfaceException
3014
-     * @throws InvalidDataTypeException
3015
-     * @throws EE_Error
3016
-     */
3017
-    public function in_entity_map()
3018
-    {
3019
-        // well, if we looked, did we find it in the entity map?
3020
-        return $this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this;
3021
-    }
3022
-
3023
-
3024
-    /**
3025
-     * refresh_from_db
3026
-     * Makes sure the fields and values on this model object are in-sync with what's in the database.
3027
-     *
3028
-     * @throws ReflectionException
3029
-     * @throws InvalidArgumentException
3030
-     * @throws InvalidInterfaceException
3031
-     * @throws InvalidDataTypeException
3032
-     * @throws EE_Error if this model object isn't in the entity mapper (because then you should
3033
-     * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
3034
-     */
3035
-    public function refresh_from_db()
3036
-    {
3037
-        if ($this->ID() && $this->in_entity_map()) {
3038
-            $this->get_model()->refresh_entity_map_from_db($this->ID());
3039
-        } else {
3040
-            //if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
3041
-            //if it has an ID but it's not in the map, and you're asking me to refresh it
3042
-            //that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
3043
-            //absolutely nothing in it for this ID
3044
-            if (WP_DEBUG) {
3045
-                throw new EE_Error(
3046
-                    sprintf(
3047
-                        esc_html__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
3048
-                            'event_espresso'),
3049
-                        $this->ID(),
3050
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3051
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3052
-                    )
3053
-                );
3054
-            }
3055
-        }
3056
-    }
3057
-
3058
-
3059
-    /**
3060
-     * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
3061
-     * (probably a bad assumption they have made, oh well)
3062
-     *
3063
-     * @return string
3064
-     */
3065
-    public function __toString()
3066
-    {
3067
-        try {
3068
-            return sprintf('%s (%s)', $this->name(), $this->ID());
3069
-        } catch (Exception $e) {
3070
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
3071
-            return '';
3072
-        }
3073
-    }
3074
-
3075
-
3076
-    /**
3077
-     * Clear related model objects if they're already in the DB, because otherwise when we
3078
-     * UN-serialize this model object we'll need to be careful to add them to the entity map.
3079
-     * This means if we have made changes to those related model objects, and want to unserialize
3080
-     * the this model object on a subsequent request, changes to those related model objects will be lost.
3081
-     * Instead, those related model objects should be directly serialized and stored.
3082
-     * Eg, the following won't work:
3083
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3084
-     * $att = $reg->attendee();
3085
-     * $att->set( 'ATT_fname', 'Dirk' );
3086
-     * update_option( 'my_option', serialize( $reg ) );
3087
-     * //END REQUEST
3088
-     * //START NEXT REQUEST
3089
-     * $reg = get_option( 'my_option' );
3090
-     * $reg->attendee()->save();
3091
-     * And would need to be replace with:
3092
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3093
-     * $att = $reg->attendee();
3094
-     * $att->set( 'ATT_fname', 'Dirk' );
3095
-     * update_option( 'my_option', serialize( $reg ) );
3096
-     * //END REQUEST
3097
-     * //START NEXT REQUEST
3098
-     * $att = get_option( 'my_option' );
3099
-     * $att->save();
3100
-     *
3101
-     * @return array
3102
-     * @throws ReflectionException
3103
-     * @throws InvalidArgumentException
3104
-     * @throws InvalidInterfaceException
3105
-     * @throws InvalidDataTypeException
3106
-     * @throws EE_Error
3107
-     */
3108
-    public function __sleep()
3109
-    {
3110
-        $model = $this->get_model();
3111
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3112
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
3113
-                $classname = 'EE_' . $model->get_this_model_name();
3114
-                if (
3115
-                    $this->get_one_from_cache($relation_name) instanceof $classname
3116
-                    && $this->get_one_from_cache($relation_name)->ID()
3117
-                ) {
3118
-                    $this->clear_cache(
3119
-                        $relation_name,
3120
-                        $this->get_one_from_cache($relation_name)->ID()
3121
-                    );
3122
-                }
3123
-            }
3124
-        }
3125
-        $this->_props_n_values_provided_in_constructor = array();
3126
-        $properties_to_serialize                       = get_object_vars($this);
3127
-        //don't serialize the model. It's big and that risks recursion
3128
-        unset($properties_to_serialize['_model']);
3129
-        return array_keys($properties_to_serialize);
3130
-    }
3131
-
3132
-
3133
-    /**
3134
-     * restore _props_n_values_provided_in_constructor
3135
-     * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
3136
-     * and therefore should NOT be used to determine if state change has occurred since initial construction.
3137
-     * At best, you would only be able to detect if state change has occurred during THIS request.
3138
-     */
3139
-    public function __wakeup()
3140
-    {
3141
-        $this->_props_n_values_provided_in_constructor = $this->_fields;
3142
-    }
18
+	/**
19
+	 * This is an array of the original properties and values provided during construction
20
+	 * of this model object. (keys are model field names, values are their values).
21
+	 * This list is important to remember so that when we are merging data from the db, we know
22
+	 * which values to override and which to not override.
23
+	 *
24
+	 * @var array
25
+	 */
26
+	protected $_props_n_values_provided_in_constructor;
27
+
28
+	/**
29
+	 * Timezone
30
+	 * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
31
+	 * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
32
+	 * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
33
+	 * access to it.
34
+	 *
35
+	 * @var string
36
+	 */
37
+	protected $_timezone;
38
+
39
+	/**
40
+	 * date format
41
+	 * pattern or format for displaying dates
42
+	 *
43
+	 * @var string $_dt_frmt
44
+	 */
45
+	protected $_dt_frmt;
46
+
47
+	/**
48
+	 * time format
49
+	 * pattern or format for displaying time
50
+	 *
51
+	 * @var string $_tm_frmt
52
+	 */
53
+	protected $_tm_frmt;
54
+
55
+	/**
56
+	 * This property is for holding a cached array of object properties indexed by property name as the key.
57
+	 * The purpose of this is for setting a cache on properties that may have calculated values after a
58
+	 * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
59
+	 * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
60
+	 *
61
+	 * @var array
62
+	 */
63
+	protected $_cached_properties = array();
64
+
65
+	/**
66
+	 * An array containing keys of the related model, and values are either an array of related mode objects or a
67
+	 * single
68
+	 * related model object. see the model's _model_relations. The keys should match those specified. And if the
69
+	 * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
70
+	 * all others have an array)
71
+	 *
72
+	 * @var array
73
+	 */
74
+	protected $_model_relations = array();
75
+
76
+	/**
77
+	 * Array where keys are field names (see the model's _fields property) and values are their values. To see what
78
+	 * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
79
+	 *
80
+	 * @var array
81
+	 */
82
+	protected $_fields = array();
83
+
84
+	/**
85
+	 * @var boolean indicating whether or not this model object is intended to ever be saved
86
+	 * For example, we might create model objects intended to only be used for the duration
87
+	 * of this request and to be thrown away, and if they were accidentally saved
88
+	 * it would be a bug.
89
+	 */
90
+	protected $_allow_persist = true;
91
+
92
+	/**
93
+	 * @var boolean indicating whether or not this model object's properties have changed since construction
94
+	 */
95
+	protected $_has_changes = false;
96
+
97
+	/**
98
+	 * @var EEM_Base
99
+	 */
100
+	protected $_model;
101
+
102
+	/**
103
+	 * This is a cache of results from custom selections done on a query that constructs this entity. The only purpose
104
+	 * for these values is for retrieval of the results, they are not further queryable and they are not persisted to
105
+	 * the db.  They also do not automatically update if there are any changes to the data that produced their results.
106
+	 * The format is a simple array of field_alias => field_value.  So for instance if a custom select was something
107
+	 * like,  "Select COUNT(Registration.REG_ID) as Registration_Count ...", then the resulting value will be in this
108
+	 * array as:
109
+	 * array(
110
+	 *  'Registration_Count' => 24
111
+	 * );
112
+	 * Note: if the custom select configuration for the query included a data type, the value will be in the data type
113
+	 * provided for the query (@see EventEspresso\core\domain\values\model\CustomSelects::__construct phpdocs for more
114
+	 * info)
115
+	 *
116
+	 * @var array
117
+	 */
118
+	protected $custom_selection_results = array();
119
+
120
+
121
+	/**
122
+	 * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
123
+	 * play nice
124
+	 *
125
+	 * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
126
+	 *                                                         layer of the model's _fields array, (eg, EVT_ID,
127
+	 *                                                         TXN_amount, QST_name, etc) and values are their values
128
+	 * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
129
+	 *                                                         corresponding db model or not.
130
+	 * @param string  $timezone                                indicate what timezone you want any datetime fields to
131
+	 *                                                         be in when instantiating a EE_Base_Class object.
132
+	 * @param array   $date_formats                            An array of date formats to set on construct where first
133
+	 *                                                         value is the date_format and second value is the time
134
+	 *                                                         format.
135
+	 * @throws InvalidArgumentException
136
+	 * @throws InvalidInterfaceException
137
+	 * @throws InvalidDataTypeException
138
+	 * @throws EE_Error
139
+	 * @throws ReflectionException
140
+	 */
141
+	protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
142
+	{
143
+		$className = get_class($this);
144
+		do_action("AHEE__{$className}__construct", $this, $fieldValues);
145
+		$model        = $this->get_model();
146
+		$model_fields = $model->field_settings(false);
147
+		// ensure $fieldValues is an array
148
+		$fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149
+		// verify client code has not passed any invalid field names
150
+		foreach ($fieldValues as $field_name => $field_value) {
151
+			if (! isset($model_fields[ $field_name ])) {
152
+				throw new EE_Error(
153
+					sprintf(
154
+						esc_html__(
155
+							'Invalid field (%s) passed to constructor of %s. Allowed fields are :%s',
156
+							'event_espresso'
157
+						),
158
+						$field_name,
159
+						get_class($this),
160
+						implode(', ', array_keys($model_fields))
161
+					)
162
+				);
163
+			}
164
+		}
165
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
+		if (! empty($date_formats) && is_array($date_formats)) {
167
+			list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168
+		} else {
169
+			//set default formats for date and time
170
+			$this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
171
+			$this->_tm_frmt = (string) get_option('time_format', 'g:i a');
172
+		}
173
+		//if db model is instantiating
174
+		if ($bydb) {
175
+			//client code has indicated these field values are from the database
176
+			foreach ($model_fields as $fieldName => $field) {
177
+				$this->set_from_db(
178
+					$fieldName,
179
+					isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
180
+				);
181
+			}
182
+		} else {
183
+			//we're constructing a brand
184
+			//new instance of the model object. Generally, this means we'll need to do more field validation
185
+			foreach ($model_fields as $fieldName => $field) {
186
+				$this->set(
187
+					$fieldName,
188
+					isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
189
+				);
190
+			}
191
+		}
192
+		//remember what values were passed to this constructor
193
+		$this->_props_n_values_provided_in_constructor = $fieldValues;
194
+		//remember in entity mapper
195
+		if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
196
+			$model->add_to_entity_map($this);
197
+		}
198
+		//setup all the relations
199
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
+				$this->_model_relations[ $relation_name ] = null;
202
+			} else {
203
+				$this->_model_relations[ $relation_name ] = array();
204
+			}
205
+		}
206
+		/**
207
+		 * Action done at the end of each model object construction
208
+		 *
209
+		 * @param EE_Base_Class $this the model object just created
210
+		 */
211
+		do_action('AHEE__EE_Base_Class__construct__finished', $this);
212
+	}
213
+
214
+
215
+	/**
216
+	 * Gets whether or not this model object is allowed to persist/be saved to the database.
217
+	 *
218
+	 * @return boolean
219
+	 */
220
+	public function allow_persist()
221
+	{
222
+		return $this->_allow_persist;
223
+	}
224
+
225
+
226
+	/**
227
+	 * Sets whether or not this model object should be allowed to be saved to the DB.
228
+	 * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
229
+	 * you got new information that somehow made you change your mind.
230
+	 *
231
+	 * @param boolean $allow_persist
232
+	 * @return boolean
233
+	 */
234
+	public function set_allow_persist($allow_persist)
235
+	{
236
+		return $this->_allow_persist = $allow_persist;
237
+	}
238
+
239
+
240
+	/**
241
+	 * Gets the field's original value when this object was constructed during this request.
242
+	 * This can be helpful when determining if a model object has changed or not
243
+	 *
244
+	 * @param string $field_name
245
+	 * @return mixed|null
246
+	 * @throws ReflectionException
247
+	 * @throws InvalidArgumentException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws InvalidDataTypeException
250
+	 * @throws EE_Error
251
+	 */
252
+	public function get_original($field_name)
253
+	{
254
+		if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
255
+			&& $field_settings = $this->get_model()->field_settings_for($field_name)
256
+		) {
257
+			return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
258
+		}
259
+		return null;
260
+	}
261
+
262
+
263
+	/**
264
+	 * @param EE_Base_Class $obj
265
+	 * @return string
266
+	 */
267
+	public function get_class($obj)
268
+	{
269
+		return get_class($obj);
270
+	}
271
+
272
+
273
+	/**
274
+	 * Overrides parent because parent expects old models.
275
+	 * This also doesn't do any validation, and won't work for serialized arrays
276
+	 *
277
+	 * @param    string $field_name
278
+	 * @param    mixed  $field_value
279
+	 * @param bool      $use_default
280
+	 * @throws InvalidArgumentException
281
+	 * @throws InvalidInterfaceException
282
+	 * @throws InvalidDataTypeException
283
+	 * @throws EE_Error
284
+	 * @throws ReflectionException
285
+	 * @throws ReflectionException
286
+	 * @throws ReflectionException
287
+	 */
288
+	public function set($field_name, $field_value, $use_default = false)
289
+	{
290
+		// if not using default and nothing has changed, and object has already been setup (has ID),
291
+		// then don't do anything
292
+		if (
293
+			! $use_default
294
+			&& $this->_fields[ $field_name ] === $field_value
295
+			&& $this->ID()
296
+		) {
297
+			return;
298
+		}
299
+		$model              = $this->get_model();
300
+		$this->_has_changes = true;
301
+		$field_obj          = $model->field_settings_for($field_name);
302
+		if ($field_obj instanceof EE_Model_Field_Base) {
303
+			//			if ( method_exists( $field_obj, 'set_timezone' )) {
304
+			if ($field_obj instanceof EE_Datetime_Field) {
305
+				$field_obj->set_timezone($this->_timezone);
306
+				$field_obj->set_date_format($this->_dt_frmt);
307
+				$field_obj->set_time_format($this->_tm_frmt);
308
+			}
309
+			$holder_of_value = $field_obj->prepare_for_set($field_value);
310
+			//should the value be null?
311
+			if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
+				$this->_fields[ $field_name ] = $field_obj->get_default_value();
313
+				/**
314
+				 * To save having to refactor all the models, if a default value is used for a
315
+				 * EE_Datetime_Field, and that value is not null nor is it a DateTime
316
+				 * object.  Then let's do a set again to ensure that it becomes a DateTime
317
+				 * object.
318
+				 *
319
+				 * @since 4.6.10+
320
+				 */
321
+				if (
322
+					$field_obj instanceof EE_Datetime_Field
323
+					&& $this->_fields[ $field_name ] !== null
324
+					&& ! $this->_fields[ $field_name ] instanceof DateTime
325
+				) {
326
+					empty($this->_fields[ $field_name ])
327
+						? $this->set($field_name, time())
328
+						: $this->set($field_name, $this->_fields[ $field_name ]);
329
+				}
330
+			} else {
331
+				$this->_fields[ $field_name ] = $holder_of_value;
332
+			}
333
+			//if we're not in the constructor...
334
+			//now check if what we set was a primary key
335
+			if (
336
+				//note: props_n_values_provided_in_constructor is only set at the END of the constructor
337
+				$this->_props_n_values_provided_in_constructor
338
+				&& $field_value
339
+				&& $field_name === $model->primary_key_name()
340
+			) {
341
+				//if so, we want all this object's fields to be filled either with
342
+				//what we've explicitly set on this model
343
+				//or what we have in the db
344
+				// echo "setting primary key!";
345
+				$fields_on_model = self::_get_model(get_class($this))->field_settings();
346
+				$obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347
+				foreach ($fields_on_model as $field_obj) {
348
+					if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349
+						&& $field_obj->get_name() !== $field_name
350
+					) {
351
+						$this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
352
+					}
353
+				}
354
+				//oh this model object has an ID? well make sure its in the entity mapper
355
+				$model->add_to_entity_map($this);
356
+			}
357
+			//let's unset any cache for this field_name from the $_cached_properties property.
358
+			$this->_clear_cached_property($field_name);
359
+		} else {
360
+			throw new EE_Error(
361
+				sprintf(
362
+					esc_html__(
363
+						'A valid EE_Model_Field_Base could not be found for the given field name: %s',
364
+						'event_espresso'
365
+					),
366
+					$field_name
367
+				)
368
+			);
369
+		}
370
+	}
371
+
372
+
373
+	/**
374
+	 * Set custom select values for model.
375
+	 *
376
+	 * @param array $custom_select_values
377
+	 */
378
+	public function setCustomSelectsValues(array $custom_select_values)
379
+	{
380
+		$this->custom_selection_results = $custom_select_values;
381
+	}
382
+
383
+
384
+	/**
385
+	 * Returns the custom select value for the provided alias if its set.
386
+	 * If not set, returns null.
387
+	 *
388
+	 * @param string $alias
389
+	 * @return string|int|float|null
390
+	 */
391
+	public function getCustomSelect($alias)
392
+	{
393
+		return isset($this->custom_selection_results[ $alias ])
394
+			? $this->custom_selection_results[ $alias ]
395
+			: null;
396
+	}
397
+
398
+
399
+	/**
400
+	 * This sets the field value on the db column if it exists for the given $column_name or
401
+	 * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
402
+	 *
403
+	 * @see EE_message::get_column_value for related documentation on the necessity of this method.
404
+	 * @param string $field_name  Must be the exact column name.
405
+	 * @param mixed  $field_value The value to set.
406
+	 * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
407
+	 * @throws InvalidArgumentException
408
+	 * @throws InvalidInterfaceException
409
+	 * @throws InvalidDataTypeException
410
+	 * @throws EE_Error
411
+	 * @throws ReflectionException
412
+	 */
413
+	public function set_field_or_extra_meta($field_name, $field_value)
414
+	{
415
+		if ($this->get_model()->has_field($field_name)) {
416
+			$this->set($field_name, $field_value);
417
+			return true;
418
+		}
419
+		//ensure this object is saved first so that extra meta can be properly related.
420
+		$this->save();
421
+		return $this->update_extra_meta($field_name, $field_value);
422
+	}
423
+
424
+
425
+	/**
426
+	 * This retrieves the value of the db column set on this class or if that's not present
427
+	 * it will attempt to retrieve from extra_meta if found.
428
+	 * Example Usage:
429
+	 * Via EE_Message child class:
430
+	 * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
431
+	 * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
432
+	 * also have additional main fields specific to the messenger.  The system accommodates those extra
433
+	 * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
434
+	 * value for those extra fields dynamically via the EE_message object.
435
+	 *
436
+	 * @param  string $field_name expecting the fully qualified field name.
437
+	 * @return mixed|null  value for the field if found.  null if not found.
438
+	 * @throws ReflectionException
439
+	 * @throws InvalidArgumentException
440
+	 * @throws InvalidInterfaceException
441
+	 * @throws InvalidDataTypeException
442
+	 * @throws EE_Error
443
+	 */
444
+	public function get_field_or_extra_meta($field_name)
445
+	{
446
+		if ($this->get_model()->has_field($field_name)) {
447
+			$column_value = $this->get($field_name);
448
+		} else {
449
+			//This isn't a column in the main table, let's see if it is in the extra meta.
450
+			$column_value = $this->get_extra_meta($field_name, true, null);
451
+		}
452
+		return $column_value;
453
+	}
454
+
455
+
456
+	/**
457
+	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
458
+	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
459
+	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
460
+	 * available to all child classes that may be using the EE_Datetime_Field for a field data type.
461
+	 *
462
+	 * @access public
463
+	 * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
464
+	 * @return void
465
+	 * @throws InvalidArgumentException
466
+	 * @throws InvalidInterfaceException
467
+	 * @throws InvalidDataTypeException
468
+	 * @throws EE_Error
469
+	 * @throws ReflectionException
470
+	 */
471
+	public function set_timezone($timezone = '')
472
+	{
473
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
474
+		//make sure we clear all cached properties because they won't be relevant now
475
+		$this->_clear_cached_properties();
476
+		//make sure we update field settings and the date for all EE_Datetime_Fields
477
+		$model_fields = $this->get_model()->field_settings(false);
478
+		foreach ($model_fields as $field_name => $field_obj) {
479
+			if ($field_obj instanceof EE_Datetime_Field) {
480
+				$field_obj->set_timezone($this->_timezone);
481
+				if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
+					$this->_fields[ $field_name ]->setTimezone(new DateTimeZone($this->_timezone));
483
+				}
484
+			}
485
+		}
486
+	}
487
+
488
+
489
+	/**
490
+	 * This just returns whatever is set for the current timezone.
491
+	 *
492
+	 * @access public
493
+	 * @return string timezone string
494
+	 */
495
+	public function get_timezone()
496
+	{
497
+		return $this->_timezone;
498
+	}
499
+
500
+
501
+	/**
502
+	 * This sets the internal date format to what is sent in to be used as the new default for the class
503
+	 * internally instead of wp set date format options
504
+	 *
505
+	 * @since 4.6
506
+	 * @param string $format should be a format recognizable by PHP date() functions.
507
+	 */
508
+	public function set_date_format($format)
509
+	{
510
+		$this->_dt_frmt = $format;
511
+		//clear cached_properties because they won't be relevant now.
512
+		$this->_clear_cached_properties();
513
+	}
514
+
515
+
516
+	/**
517
+	 * This sets the internal time format string to what is sent in to be used as the new default for the
518
+	 * class internally instead of wp set time format options.
519
+	 *
520
+	 * @since 4.6
521
+	 * @param string $format should be a format recognizable by PHP date() functions.
522
+	 */
523
+	public function set_time_format($format)
524
+	{
525
+		$this->_tm_frmt = $format;
526
+		//clear cached_properties because they won't be relevant now.
527
+		$this->_clear_cached_properties();
528
+	}
529
+
530
+
531
+	/**
532
+	 * This returns the current internal set format for the date and time formats.
533
+	 *
534
+	 * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
535
+	 *                             where the first value is the date format and the second value is the time format.
536
+	 * @return mixed string|array
537
+	 */
538
+	public function get_format($full = true)
539
+	{
540
+		return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541
+	}
542
+
543
+
544
+	/**
545
+	 * cache
546
+	 * stores the passed model object on the current model object.
547
+	 * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
548
+	 *
549
+	 * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
550
+	 *                                       'Registration' associated with this model object
551
+	 * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
552
+	 *                                       that could be a payment or a registration)
553
+	 * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
554
+	 *                                       items which will be stored in an array on this object
555
+	 * @throws ReflectionException
556
+	 * @throws InvalidArgumentException
557
+	 * @throws InvalidInterfaceException
558
+	 * @throws InvalidDataTypeException
559
+	 * @throws EE_Error
560
+	 * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
561
+	 *                                       related thing, no array)
562
+	 */
563
+	public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564
+	{
565
+		// its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
+		if (! $object_to_cache instanceof EE_Base_Class) {
567
+			return false;
568
+		}
569
+		// also get "how" the object is related, or throw an error
570
+		if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571
+			throw new EE_Error(
572
+				sprintf(
573
+					esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
574
+					$relationName,
575
+					get_class($this)
576
+				)
577
+			);
578
+		}
579
+		// how many things are related ?
580
+		if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
581
+			// if it's a "belongs to" relationship, then there's only one related model object
582
+			// eg, if this is a registration, there's only 1 attendee for it
583
+			// so for these model objects just set it to be cached
584
+			$this->_model_relations[ $relationName ] = $object_to_cache;
585
+			$return                                  = true;
586
+		} else {
587
+			// otherwise, this is the "many" side of a one to many relationship,
588
+			// so we'll add the object to the array of related objects for that type.
589
+			// eg: if this is an event, there are many registrations for that event,
590
+			// so we cache the registrations in an array
591
+			if (! is_array($this->_model_relations[ $relationName ])) {
592
+				// if for some reason, the cached item is a model object,
593
+				// then stick that in the array, otherwise start with an empty array
594
+				$this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
595
+														   instanceof
596
+														   EE_Base_Class
597
+					? array($this->_model_relations[ $relationName ]) : array();
598
+			}
599
+			// first check for a cache_id which is normally empty
600
+			if (! empty($cache_id)) {
601
+				// if the cache_id exists, then it means we are purposely trying to cache this
602
+				// with a known key that can then be used to retrieve the object later on
603
+				$this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
604
+				$return                                               = $cache_id;
605
+			} elseif ($object_to_cache->ID()) {
606
+				// OR the cached object originally came from the db, so let's just use it's PK for an ID
607
+				$this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
608
+				$return                                                            = $object_to_cache->ID();
609
+			} else {
610
+				// OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
+				$this->_model_relations[ $relationName ][] = $object_to_cache;
612
+				// move the internal pointer to the end of the array
613
+				end($this->_model_relations[ $relationName ]);
614
+				// and grab the key so that we can return it
615
+				$return = key($this->_model_relations[ $relationName ]);
616
+			}
617
+		}
618
+		return $return;
619
+	}
620
+
621
+
622
+	/**
623
+	 * For adding an item to the cached_properties property.
624
+	 *
625
+	 * @access protected
626
+	 * @param string      $fieldname the property item the corresponding value is for.
627
+	 * @param mixed       $value     The value we are caching.
628
+	 * @param string|null $cache_type
629
+	 * @return void
630
+	 * @throws ReflectionException
631
+	 * @throws InvalidArgumentException
632
+	 * @throws InvalidInterfaceException
633
+	 * @throws InvalidDataTypeException
634
+	 * @throws EE_Error
635
+	 */
636
+	protected function _set_cached_property($fieldname, $value, $cache_type = null)
637
+	{
638
+		//first make sure this property exists
639
+		$this->get_model()->field_settings_for($fieldname);
640
+		$cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
+		$this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
642
+	}
643
+
644
+
645
+	/**
646
+	 * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
647
+	 * This also SETS the cache if we return the actual property!
648
+	 *
649
+	 * @param string $fieldname        the name of the property we're trying to retrieve
650
+	 * @param bool   $pretty
651
+	 * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
652
+	 *                                 (in cases where the same property may be used for different outputs
653
+	 *                                 - i.e. datetime, money etc.)
654
+	 *                                 It can also accept certain pre-defined "schema" strings
655
+	 *                                 to define how to output the property.
656
+	 *                                 see the field's prepare_for_pretty_echoing for what strings can be used
657
+	 * @return mixed                   whatever the value for the property is we're retrieving
658
+	 * @throws ReflectionException
659
+	 * @throws InvalidArgumentException
660
+	 * @throws InvalidInterfaceException
661
+	 * @throws InvalidDataTypeException
662
+	 * @throws EE_Error
663
+	 */
664
+	protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
665
+	{
666
+		//verify the field exists
667
+		$model = $this->get_model();
668
+		$model->field_settings_for($fieldname);
669
+		$cache_type = $pretty ? 'pretty' : 'standard';
670
+		$cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
+		if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
+			return $this->_cached_properties[ $fieldname ][ $cache_type ];
673
+		}
674
+		$value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675
+		$this->_set_cached_property($fieldname, $value, $cache_type);
676
+		return $value;
677
+	}
678
+
679
+
680
+	/**
681
+	 * If the cache didn't fetch the needed item, this fetches it.
682
+	 *
683
+	 * @param string $fieldname
684
+	 * @param bool   $pretty
685
+	 * @param string $extra_cache_ref
686
+	 * @return mixed
687
+	 * @throws InvalidArgumentException
688
+	 * @throws InvalidInterfaceException
689
+	 * @throws InvalidDataTypeException
690
+	 * @throws EE_Error
691
+	 * @throws ReflectionException
692
+	 */
693
+	protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
694
+	{
695
+		$field_obj = $this->get_model()->field_settings_for($fieldname);
696
+		// If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
697
+		if ($field_obj instanceof EE_Datetime_Field) {
698
+			$this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699
+		}
700
+		if (! isset($this->_fields[ $fieldname ])) {
701
+			$this->_fields[ $fieldname ] = null;
702
+		}
703
+		$value = $pretty
704
+			? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
+			: $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
706
+		return $value;
707
+	}
708
+
709
+
710
+	/**
711
+	 * set timezone, formats, and output for EE_Datetime_Field objects
712
+	 *
713
+	 * @param \EE_Datetime_Field $datetime_field
714
+	 * @param bool               $pretty
715
+	 * @param null               $date_or_time
716
+	 * @return void
717
+	 * @throws InvalidArgumentException
718
+	 * @throws InvalidInterfaceException
719
+	 * @throws InvalidDataTypeException
720
+	 * @throws EE_Error
721
+	 */
722
+	protected function _prepare_datetime_field(
723
+		EE_Datetime_Field $datetime_field,
724
+		$pretty = false,
725
+		$date_or_time = null
726
+	) {
727
+		$datetime_field->set_timezone($this->_timezone);
728
+		$datetime_field->set_date_format($this->_dt_frmt, $pretty);
729
+		$datetime_field->set_time_format($this->_tm_frmt, $pretty);
730
+		//set the output returned
731
+		switch ($date_or_time) {
732
+			case 'D' :
733
+				$datetime_field->set_date_time_output('date');
734
+				break;
735
+			case 'T' :
736
+				$datetime_field->set_date_time_output('time');
737
+				break;
738
+			default :
739
+				$datetime_field->set_date_time_output();
740
+		}
741
+	}
742
+
743
+
744
+	/**
745
+	 * This just takes care of clearing out the cached_properties
746
+	 *
747
+	 * @return void
748
+	 */
749
+	protected function _clear_cached_properties()
750
+	{
751
+		$this->_cached_properties = array();
752
+	}
753
+
754
+
755
+	/**
756
+	 * This just clears out ONE property if it exists in the cache
757
+	 *
758
+	 * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
759
+	 * @return void
760
+	 */
761
+	protected function _clear_cached_property($property_name)
762
+	{
763
+		if (isset($this->_cached_properties[ $property_name ])) {
764
+			unset($this->_cached_properties[ $property_name ]);
765
+		}
766
+	}
767
+
768
+
769
+	/**
770
+	 * Ensures that this related thing is a model object.
771
+	 *
772
+	 * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
773
+	 * @param string $model_name   name of the related thing, eg 'Attendee',
774
+	 * @return EE_Base_Class
775
+	 * @throws ReflectionException
776
+	 * @throws InvalidArgumentException
777
+	 * @throws InvalidInterfaceException
778
+	 * @throws InvalidDataTypeException
779
+	 * @throws EE_Error
780
+	 */
781
+	protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
782
+	{
783
+		$other_model_instance = self::_get_model_instance_with_name(
784
+			self::_get_model_classname($model_name),
785
+			$this->_timezone
786
+		);
787
+		return $other_model_instance->ensure_is_obj($object_or_id);
788
+	}
789
+
790
+
791
+	/**
792
+	 * Forgets the cached model of the given relation Name. So the next time we request it,
793
+	 * we will fetch it again from the database. (Handy if you know it's changed somehow).
794
+	 * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
795
+	 * then only remove that one object from our cached array. Otherwise, clear the entire list
796
+	 *
797
+	 * @param string $relationName                         one of the keys in the _model_relations array on the model.
798
+	 *                                                     Eg 'Registration'
799
+	 * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
800
+	 *                                                     if you intend to use $clear_all = TRUE, or the relation only
801
+	 *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
802
+	 * @param bool   $clear_all                            This flags clearing the entire cache relation property if
803
+	 *                                                     this is HasMany or HABTM.
804
+	 * @throws ReflectionException
805
+	 * @throws InvalidArgumentException
806
+	 * @throws InvalidInterfaceException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws EE_Error
809
+	 * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
810
+	 *                                                     relation from all
811
+	 */
812
+	public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
813
+	{
814
+		$relationship_to_model = $this->get_model()->related_settings_for($relationName);
815
+		$index_in_cache        = '';
816
+		if (! $relationship_to_model) {
817
+			throw new EE_Error(
818
+				sprintf(
819
+					esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
820
+					$relationName,
821
+					get_class($this)
822
+				)
823
+			);
824
+		}
825
+		if ($clear_all) {
826
+			$obj_removed                             = true;
827
+			$this->_model_relations[ $relationName ] = null;
828
+		} elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
+			$obj_removed                             = $this->_model_relations[ $relationName ];
830
+			$this->_model_relations[ $relationName ] = null;
831
+		} else {
832
+			if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833
+				&& $object_to_remove_or_index_into_array->ID()
834
+			) {
835
+				$index_in_cache = $object_to_remove_or_index_into_array->ID();
836
+				if (is_array($this->_model_relations[ $relationName ])
837
+					&& ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
838
+				) {
839
+					$index_found_at = null;
840
+					//find this object in the array even though it has a different key
841
+					foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
842
+						/** @noinspection TypeUnsafeComparisonInspection */
843
+						if (
844
+							$obj instanceof EE_Base_Class
845
+							&& (
846
+								$obj == $object_to_remove_or_index_into_array
847
+								|| $obj->ID() === $object_to_remove_or_index_into_array->ID()
848
+							)
849
+						) {
850
+							$index_found_at = $index;
851
+							break;
852
+						}
853
+					}
854
+					if ($index_found_at) {
855
+						$index_in_cache = $index_found_at;
856
+					} else {
857
+						//it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
858
+						//if it wasn't in it to begin with. So we're done
859
+						return $object_to_remove_or_index_into_array;
860
+					}
861
+				}
862
+			} elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
863
+				//so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
864
+				foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
865
+					/** @noinspection TypeUnsafeComparisonInspection */
866
+					if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
867
+						$index_in_cache = $index;
868
+					}
869
+				}
870
+			} else {
871
+				$index_in_cache = $object_to_remove_or_index_into_array;
872
+			}
873
+			//supposedly we've found it. But it could just be that the client code
874
+			//provided a bad index/object
875
+			if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
+				$obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
+				unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
878
+			} else {
879
+				//that thing was never cached anyways.
880
+				$obj_removed = null;
881
+			}
882
+		}
883
+		return $obj_removed;
884
+	}
885
+
886
+
887
+	/**
888
+	 * update_cache_after_object_save
889
+	 * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
890
+	 * obtained after being saved to the db
891
+	 *
892
+	 * @param string        $relationName       - the type of object that is cached
893
+	 * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
894
+	 * @param string        $current_cache_id   - the ID that was used when originally caching the object
895
+	 * @return boolean TRUE on success, FALSE on fail
896
+	 * @throws ReflectionException
897
+	 * @throws InvalidArgumentException
898
+	 * @throws InvalidInterfaceException
899
+	 * @throws InvalidDataTypeException
900
+	 * @throws EE_Error
901
+	 */
902
+	public function update_cache_after_object_save(
903
+		$relationName,
904
+		EE_Base_Class $newly_saved_object,
905
+		$current_cache_id = ''
906
+	) {
907
+		// verify that incoming object is of the correct type
908
+		$obj_class = 'EE_' . $relationName;
909
+		if ($newly_saved_object instanceof $obj_class) {
910
+			/* @type EE_Base_Class $newly_saved_object */
911
+			// now get the type of relation
912
+			$relationship_to_model = $this->get_model()->related_settings_for($relationName);
913
+			// if this is a 1:1 relationship
914
+			if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915
+				// then just replace the cached object with the newly saved object
916
+				$this->_model_relations[ $relationName ] = $newly_saved_object;
917
+				return true;
918
+				// or if it's some kind of sordid feral polyamorous relationship...
919
+			}
920
+			if (is_array($this->_model_relations[ $relationName ])
921
+					  && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
922
+			) {
923
+				// then remove the current cached item
924
+				unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
925
+				// and cache the newly saved object using it's new ID
926
+				$this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
927
+				return true;
928
+			}
929
+		}
930
+		return false;
931
+	}
932
+
933
+
934
+	/**
935
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
936
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
937
+	 *
938
+	 * @param string $relationName
939
+	 * @return EE_Base_Class
940
+	 */
941
+	public function get_one_from_cache($relationName)
942
+	{
943
+		$cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
+			? $this->_model_relations[ $relationName ]
945
+			: null;
946
+		if (is_array($cached_array_or_object)) {
947
+			return array_shift($cached_array_or_object);
948
+		}
949
+		return $cached_array_or_object;
950
+	}
951
+
952
+
953
+	/**
954
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
955
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
956
+	 *
957
+	 * @param string $relationName
958
+	 * @throws ReflectionException
959
+	 * @throws InvalidArgumentException
960
+	 * @throws InvalidInterfaceException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws EE_Error
963
+	 * @return EE_Base_Class[] NOT necessarily indexed by primary keys
964
+	 */
965
+	public function get_all_from_cache($relationName)
966
+	{
967
+		$objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
968
+		// if the result is not an array, but exists, make it an array
969
+		$objects = is_array($objects) ? $objects : array($objects);
970
+		//bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
971
+		//basically, if this model object was stored in the session, and these cached model objects
972
+		//already have IDs, let's make sure they're in their model's entity mapper
973
+		//otherwise we will have duplicates next time we call
974
+		// EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
975
+		$model = EE_Registry::instance()->load_model($relationName);
976
+		foreach ($objects as $model_object) {
977
+			if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
978
+				//ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
979
+				if ($model_object->ID()) {
980
+					$model->add_to_entity_map($model_object);
981
+				}
982
+			} else {
983
+				throw new EE_Error(
984
+					sprintf(
985
+						esc_html__(
986
+							'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
987
+							'event_espresso'
988
+						),
989
+						$relationName,
990
+						gettype($model_object)
991
+					)
992
+				);
993
+			}
994
+		}
995
+		return $objects;
996
+	}
997
+
998
+
999
+	/**
1000
+	 * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
1001
+	 * matching the given query conditions.
1002
+	 *
1003
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1004
+	 * @param int   $limit              How many objects to return.
1005
+	 * @param array $query_params       Any additional conditions on the query.
1006
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1007
+	 *                                  you can indicate just the columns you want returned
1008
+	 * @return array|EE_Base_Class[]
1009
+	 * @throws ReflectionException
1010
+	 * @throws InvalidArgumentException
1011
+	 * @throws InvalidInterfaceException
1012
+	 * @throws InvalidDataTypeException
1013
+	 * @throws EE_Error
1014
+	 */
1015
+	public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
1016
+	{
1017
+		$model         = $this->get_model();
1018
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1019
+			? $model->get_primary_key_field()->get_name()
1020
+			: $field_to_order_by;
1021
+		$current_value = ! empty($field) ? $this->get($field) : null;
1022
+		if (empty($field) || empty($current_value)) {
1023
+			return array();
1024
+		}
1025
+		return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
1026
+	}
1027
+
1028
+
1029
+	/**
1030
+	 * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
1031
+	 * matching the given query conditions.
1032
+	 *
1033
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1034
+	 * @param int   $limit              How many objects to return.
1035
+	 * @param array $query_params       Any additional conditions on the query.
1036
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1037
+	 *                                  you can indicate just the columns you want returned
1038
+	 * @return array|EE_Base_Class[]
1039
+	 * @throws ReflectionException
1040
+	 * @throws InvalidArgumentException
1041
+	 * @throws InvalidInterfaceException
1042
+	 * @throws InvalidDataTypeException
1043
+	 * @throws EE_Error
1044
+	 */
1045
+	public function previous_x(
1046
+		$field_to_order_by = null,
1047
+		$limit = 1,
1048
+		$query_params = array(),
1049
+		$columns_to_select = null
1050
+	) {
1051
+		$model         = $this->get_model();
1052
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1053
+			? $model->get_primary_key_field()->get_name()
1054
+			: $field_to_order_by;
1055
+		$current_value = ! empty($field) ? $this->get($field) : null;
1056
+		if (empty($field) || empty($current_value)) {
1057
+			return array();
1058
+		}
1059
+		return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
1060
+	}
1061
+
1062
+
1063
+	/**
1064
+	 * Returns the next EE_Base_Class object in sequence from this object as found in the database
1065
+	 * matching the given query conditions.
1066
+	 *
1067
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1068
+	 * @param array $query_params       Any additional conditions on the query.
1069
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070
+	 *                                  you can indicate just the columns you want returned
1071
+	 * @return array|EE_Base_Class
1072
+	 * @throws ReflectionException
1073
+	 * @throws InvalidArgumentException
1074
+	 * @throws InvalidInterfaceException
1075
+	 * @throws InvalidDataTypeException
1076
+	 * @throws EE_Error
1077
+	 */
1078
+	public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1079
+	{
1080
+		$model         = $this->get_model();
1081
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1082
+			? $model->get_primary_key_field()->get_name()
1083
+			: $field_to_order_by;
1084
+		$current_value = ! empty($field) ? $this->get($field) : null;
1085
+		if (empty($field) || empty($current_value)) {
1086
+			return array();
1087
+		}
1088
+		return $model->next($current_value, $field, $query_params, $columns_to_select);
1089
+	}
1090
+
1091
+
1092
+	/**
1093
+	 * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1094
+	 * matching the given query conditions.
1095
+	 *
1096
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1097
+	 * @param array $query_params       Any additional conditions on the query.
1098
+	 * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099
+	 *                                  you can indicate just the column you want returned
1100
+	 * @return array|EE_Base_Class
1101
+	 * @throws ReflectionException
1102
+	 * @throws InvalidArgumentException
1103
+	 * @throws InvalidInterfaceException
1104
+	 * @throws InvalidDataTypeException
1105
+	 * @throws EE_Error
1106
+	 */
1107
+	public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1108
+	{
1109
+		$model         = $this->get_model();
1110
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1111
+			? $model->get_primary_key_field()->get_name()
1112
+			: $field_to_order_by;
1113
+		$current_value = ! empty($field) ? $this->get($field) : null;
1114
+		if (empty($field) || empty($current_value)) {
1115
+			return array();
1116
+		}
1117
+		return $model->previous($current_value, $field, $query_params, $columns_to_select);
1118
+	}
1119
+
1120
+
1121
+	/**
1122
+	 * Overrides parent because parent expects old models.
1123
+	 * This also doesn't do any validation, and won't work for serialized arrays
1124
+	 *
1125
+	 * @param string $field_name
1126
+	 * @param mixed  $field_value_from_db
1127
+	 * @throws ReflectionException
1128
+	 * @throws InvalidArgumentException
1129
+	 * @throws InvalidInterfaceException
1130
+	 * @throws InvalidDataTypeException
1131
+	 * @throws EE_Error
1132
+	 */
1133
+	public function set_from_db($field_name, $field_value_from_db)
1134
+	{
1135
+		$field_obj = $this->get_model()->field_settings_for($field_name);
1136
+		if ($field_obj instanceof EE_Model_Field_Base) {
1137
+			//you would think the DB has no NULLs for non-null label fields right? wrong!
1138
+			//eg, a CPT model object could have an entry in the posts table, but no
1139
+			//entry in the meta table. Meaning that all its columns in the meta table
1140
+			//are null! yikes! so when we find one like that, use defaults for its meta columns
1141
+			if ($field_value_from_db === null) {
1142
+				if ($field_obj->is_nullable()) {
1143
+					//if the field allows nulls, then let it be null
1144
+					$field_value = null;
1145
+				} else {
1146
+					$field_value = $field_obj->get_default_value();
1147
+				}
1148
+			} else {
1149
+				$field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150
+			}
1151
+			$this->_fields[ $field_name ] = $field_value;
1152
+			$this->_clear_cached_property($field_name);
1153
+		}
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * verifies that the specified field is of the correct type
1159
+	 *
1160
+	 * @param string $field_name
1161
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1162
+	 *                                (in cases where the same property may be used for different outputs
1163
+	 *                                - i.e. datetime, money etc.)
1164
+	 * @return mixed
1165
+	 * @throws ReflectionException
1166
+	 * @throws InvalidArgumentException
1167
+	 * @throws InvalidInterfaceException
1168
+	 * @throws InvalidDataTypeException
1169
+	 * @throws EE_Error
1170
+	 */
1171
+	public function get($field_name, $extra_cache_ref = null)
1172
+	{
1173
+		return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1174
+	}
1175
+
1176
+
1177
+	/**
1178
+	 * This method simply returns the RAW unprocessed value for the given property in this class
1179
+	 *
1180
+	 * @param  string $field_name A valid fieldname
1181
+	 * @return mixed              Whatever the raw value stored on the property is.
1182
+	 * @throws ReflectionException
1183
+	 * @throws InvalidArgumentException
1184
+	 * @throws InvalidInterfaceException
1185
+	 * @throws InvalidDataTypeException
1186
+	 * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1187
+	 */
1188
+	public function get_raw($field_name)
1189
+	{
1190
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1191
+		return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
+			? $this->_fields[ $field_name ]->format('U')
1193
+			: $this->_fields[ $field_name ];
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * This is used to return the internal DateTime object used for a field that is a
1199
+	 * EE_Datetime_Field.
1200
+	 *
1201
+	 * @param string $field_name               The field name retrieving the DateTime object.
1202
+	 * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1203
+	 * @throws ReflectionException
1204
+	 * @throws InvalidArgumentException
1205
+	 * @throws InvalidInterfaceException
1206
+	 * @throws InvalidDataTypeException
1207
+	 * @throws EE_Error
1208
+	 *                                         an error is set and false returned.  If the field IS an
1209
+	 *                                         EE_Datetime_Field and but the field value is null, then
1210
+	 *                                         just null is returned (because that indicates that likely
1211
+	 *                                         this field is nullable).
1212
+	 */
1213
+	public function get_DateTime_object($field_name)
1214
+	{
1215
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1216
+		if (! $field_settings instanceof EE_Datetime_Field) {
1217
+			EE_Error::add_error(
1218
+				sprintf(
1219
+					esc_html__(
1220
+						'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1221
+						'event_espresso'
1222
+					),
1223
+					$field_name
1224
+				),
1225
+				__FILE__,
1226
+				__FUNCTION__,
1227
+				__LINE__
1228
+			);
1229
+			return false;
1230
+		}
1231
+		return $this->_fields[ $field_name ];
1232
+	}
1233
+
1234
+
1235
+	/**
1236
+	 * To be used in template to immediately echo out the value, and format it for output.
1237
+	 * Eg, should call stripslashes and whatnot before echoing
1238
+	 *
1239
+	 * @param string $field_name      the name of the field as it appears in the DB
1240
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1241
+	 *                                (in cases where the same property may be used for different outputs
1242
+	 *                                - i.e. datetime, money etc.)
1243
+	 * @return void
1244
+	 * @throws ReflectionException
1245
+	 * @throws InvalidArgumentException
1246
+	 * @throws InvalidInterfaceException
1247
+	 * @throws InvalidDataTypeException
1248
+	 * @throws EE_Error
1249
+	 */
1250
+	public function e($field_name, $extra_cache_ref = null)
1251
+	{
1252
+		echo $this->get_pretty($field_name, $extra_cache_ref);
1253
+	}
1254
+
1255
+
1256
+	/**
1257
+	 * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1258
+	 * can be easily used as the value of form input.
1259
+	 *
1260
+	 * @param string $field_name
1261
+	 * @return void
1262
+	 * @throws ReflectionException
1263
+	 * @throws InvalidArgumentException
1264
+	 * @throws InvalidInterfaceException
1265
+	 * @throws InvalidDataTypeException
1266
+	 * @throws EE_Error
1267
+	 */
1268
+	public function f($field_name)
1269
+	{
1270
+		$this->e($field_name, 'form_input');
1271
+	}
1272
+
1273
+
1274
+	/**
1275
+	 * Same as `f()` but just returns the value instead of echoing it
1276
+	 *
1277
+	 * @param string $field_name
1278
+	 * @return string
1279
+	 * @throws ReflectionException
1280
+	 * @throws InvalidArgumentException
1281
+	 * @throws InvalidInterfaceException
1282
+	 * @throws InvalidDataTypeException
1283
+	 * @throws EE_Error
1284
+	 */
1285
+	public function get_f($field_name)
1286
+	{
1287
+		return (string) $this->get_pretty($field_name, 'form_input');
1288
+	}
1289
+
1290
+
1291
+	/**
1292
+	 * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1293
+	 * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1294
+	 * to see what options are available.
1295
+	 *
1296
+	 * @param string $field_name
1297
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1298
+	 *                                (in cases where the same property may be used for different outputs
1299
+	 *                                - i.e. datetime, money etc.)
1300
+	 * @return mixed
1301
+	 * @throws ReflectionException
1302
+	 * @throws InvalidArgumentException
1303
+	 * @throws InvalidInterfaceException
1304
+	 * @throws InvalidDataTypeException
1305
+	 * @throws EE_Error
1306
+	 */
1307
+	public function get_pretty($field_name, $extra_cache_ref = null)
1308
+	{
1309
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1310
+	}
1311
+
1312
+
1313
+	/**
1314
+	 * This simply returns the datetime for the given field name
1315
+	 * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1316
+	 * (and the equivalent e_date, e_time, e_datetime).
1317
+	 *
1318
+	 * @access   protected
1319
+	 * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1320
+	 * @param string   $dt_frmt      valid datetime format used for date
1321
+	 *                               (if '' then we just use the default on the field,
1322
+	 *                               if NULL we use the last-used format)
1323
+	 * @param string   $tm_frmt      Same as above except this is for time format
1324
+	 * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1325
+	 * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1326
+	 * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1327
+	 *                               if field is not a valid dtt field, or void if echoing
1328
+	 * @throws ReflectionException
1329
+	 * @throws InvalidArgumentException
1330
+	 * @throws InvalidInterfaceException
1331
+	 * @throws InvalidDataTypeException
1332
+	 * @throws EE_Error
1333
+	 */
1334
+	protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1335
+	{
1336
+		// clear cached property
1337
+		$this->_clear_cached_property($field_name);
1338
+		//reset format properties because they are used in get()
1339
+		$this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1340
+		$this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1341
+		if ($echo) {
1342
+			$this->e($field_name, $date_or_time);
1343
+			return '';
1344
+		}
1345
+		return $this->get($field_name, $date_or_time);
1346
+	}
1347
+
1348
+
1349
+	/**
1350
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1351
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1352
+	 * other echoes the pretty value for dtt)
1353
+	 *
1354
+	 * @param  string $field_name name of model object datetime field holding the value
1355
+	 * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1356
+	 * @return string            datetime value formatted
1357
+	 * @throws ReflectionException
1358
+	 * @throws InvalidArgumentException
1359
+	 * @throws InvalidInterfaceException
1360
+	 * @throws InvalidDataTypeException
1361
+	 * @throws EE_Error
1362
+	 */
1363
+	public function get_date($field_name, $format = '')
1364
+	{
1365
+		return $this->_get_datetime($field_name, $format, null, 'D');
1366
+	}
1367
+
1368
+
1369
+	/**
1370
+	 * @param        $field_name
1371
+	 * @param string $format
1372
+	 * @throws ReflectionException
1373
+	 * @throws InvalidArgumentException
1374
+	 * @throws InvalidInterfaceException
1375
+	 * @throws InvalidDataTypeException
1376
+	 * @throws EE_Error
1377
+	 */
1378
+	public function e_date($field_name, $format = '')
1379
+	{
1380
+		$this->_get_datetime($field_name, $format, null, 'D', true);
1381
+	}
1382
+
1383
+
1384
+	/**
1385
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1386
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1387
+	 * other echoes the pretty value for dtt)
1388
+	 *
1389
+	 * @param  string $field_name name of model object datetime field holding the value
1390
+	 * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1391
+	 * @return string             datetime value formatted
1392
+	 * @throws ReflectionException
1393
+	 * @throws InvalidArgumentException
1394
+	 * @throws InvalidInterfaceException
1395
+	 * @throws InvalidDataTypeException
1396
+	 * @throws EE_Error
1397
+	 */
1398
+	public function get_time($field_name, $format = '')
1399
+	{
1400
+		return $this->_get_datetime($field_name, null, $format, 'T');
1401
+	}
1402
+
1403
+
1404
+	/**
1405
+	 * @param        $field_name
1406
+	 * @param string $format
1407
+	 * @throws ReflectionException
1408
+	 * @throws InvalidArgumentException
1409
+	 * @throws InvalidInterfaceException
1410
+	 * @throws InvalidDataTypeException
1411
+	 * @throws EE_Error
1412
+	 */
1413
+	public function e_time($field_name, $format = '')
1414
+	{
1415
+		$this->_get_datetime($field_name, null, $format, 'T', true);
1416
+	}
1417
+
1418
+
1419
+	/**
1420
+	 * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1421
+	 * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1422
+	 * other echoes the pretty value for dtt)
1423
+	 *
1424
+	 * @param  string $field_name name of model object datetime field holding the value
1425
+	 * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1426
+	 * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1427
+	 * @return string             datetime value formatted
1428
+	 * @throws ReflectionException
1429
+	 * @throws InvalidArgumentException
1430
+	 * @throws InvalidInterfaceException
1431
+	 * @throws InvalidDataTypeException
1432
+	 * @throws EE_Error
1433
+	 */
1434
+	public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1435
+	{
1436
+		return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1437
+	}
1438
+
1439
+
1440
+	/**
1441
+	 * @param string $field_name
1442
+	 * @param string $dt_frmt
1443
+	 * @param string $tm_frmt
1444
+	 * @throws ReflectionException
1445
+	 * @throws InvalidArgumentException
1446
+	 * @throws InvalidInterfaceException
1447
+	 * @throws InvalidDataTypeException
1448
+	 * @throws EE_Error
1449
+	 */
1450
+	public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1451
+	{
1452
+		$this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1453
+	}
1454
+
1455
+
1456
+	/**
1457
+	 * Get the i8ln value for a date using the WordPress @see date_i18n function.
1458
+	 *
1459
+	 * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1460
+	 * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1461
+	 *                           on the object will be used.
1462
+	 * @return string Date and time string in set locale or false if no field exists for the given
1463
+	 * @throws ReflectionException
1464
+	 * @throws InvalidArgumentException
1465
+	 * @throws InvalidInterfaceException
1466
+	 * @throws InvalidDataTypeException
1467
+	 * @throws EE_Error
1468
+	 *                           field name.
1469
+	 */
1470
+	public function get_i18n_datetime($field_name, $format = '')
1471
+	{
1472
+		$format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1473
+		return date_i18n(
1474
+			$format,
1475
+			EEH_DTT_Helper::get_timestamp_with_offset(
1476
+				$this->get_raw($field_name),
1477
+				$this->_timezone
1478
+			)
1479
+		);
1480
+	}
1481
+
1482
+
1483
+	/**
1484
+	 * This method validates whether the given field name is a valid field on the model object as well as it is of a
1485
+	 * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1486
+	 * thrown.
1487
+	 *
1488
+	 * @param  string $field_name The field name being checked
1489
+	 * @throws ReflectionException
1490
+	 * @throws InvalidArgumentException
1491
+	 * @throws InvalidInterfaceException
1492
+	 * @throws InvalidDataTypeException
1493
+	 * @throws EE_Error
1494
+	 * @return EE_Datetime_Field
1495
+	 */
1496
+	protected function _get_dtt_field_settings($field_name)
1497
+	{
1498
+		$field = $this->get_model()->field_settings_for($field_name);
1499
+		//check if field is dtt
1500
+		if ($field instanceof EE_Datetime_Field) {
1501
+			return $field;
1502
+		}
1503
+		throw new EE_Error(
1504
+			sprintf(
1505
+				esc_html__(
1506
+					'The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1507
+					'event_espresso'
1508
+				),
1509
+				$field_name,
1510
+				self::_get_model_classname(get_class($this))
1511
+			)
1512
+		);
1513
+	}
1514
+
1515
+
1516
+
1517
+
1518
+	/**
1519
+	 * NOTE ABOUT BELOW:
1520
+	 * These convenience date and time setters are for setting date and time independently.  In other words you might
1521
+	 * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1522
+	 * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1523
+	 * method and make sure you send the entire datetime value for setting.
1524
+	 */
1525
+	/**
1526
+	 * sets the time on a datetime property
1527
+	 *
1528
+	 * @access protected
1529
+	 * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1530
+	 * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1531
+	 * @throws ReflectionException
1532
+	 * @throws InvalidArgumentException
1533
+	 * @throws InvalidInterfaceException
1534
+	 * @throws InvalidDataTypeException
1535
+	 * @throws EE_Error
1536
+	 */
1537
+	protected function _set_time_for($time, $fieldname)
1538
+	{
1539
+		$this->_set_date_time('T', $time, $fieldname);
1540
+	}
1541
+
1542
+
1543
+	/**
1544
+	 * sets the date on a datetime property
1545
+	 *
1546
+	 * @access protected
1547
+	 * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1548
+	 * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1549
+	 * @throws ReflectionException
1550
+	 * @throws InvalidArgumentException
1551
+	 * @throws InvalidInterfaceException
1552
+	 * @throws InvalidDataTypeException
1553
+	 * @throws EE_Error
1554
+	 */
1555
+	protected function _set_date_for($date, $fieldname)
1556
+	{
1557
+		$this->_set_date_time('D', $date, $fieldname);
1558
+	}
1559
+
1560
+
1561
+	/**
1562
+	 * This takes care of setting a date or time independently on a given model object property. This method also
1563
+	 * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1564
+	 *
1565
+	 * @access protected
1566
+	 * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1567
+	 * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1568
+	 * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1569
+	 *                                        EE_Datetime_Field property)
1570
+	 * @throws ReflectionException
1571
+	 * @throws InvalidArgumentException
1572
+	 * @throws InvalidInterfaceException
1573
+	 * @throws InvalidDataTypeException
1574
+	 * @throws EE_Error
1575
+	 */
1576
+	protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1577
+	{
1578
+		$field = $this->_get_dtt_field_settings($fieldname);
1579
+		$field->set_timezone($this->_timezone);
1580
+		$field->set_date_format($this->_dt_frmt);
1581
+		$field->set_time_format($this->_tm_frmt);
1582
+		switch ($what) {
1583
+			case 'T' :
1584
+				$this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1585
+					$datetime_value,
1586
+					$this->_fields[ $fieldname ]
1587
+				);
1588
+				break;
1589
+			case 'D' :
1590
+				$this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1591
+					$datetime_value,
1592
+					$this->_fields[ $fieldname ]
1593
+				);
1594
+				break;
1595
+			case 'B' :
1596
+				$this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1597
+				break;
1598
+		}
1599
+		$this->_clear_cached_property($fieldname);
1600
+	}
1601
+
1602
+
1603
+	/**
1604
+	 * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1605
+	 * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1606
+	 * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1607
+	 * that could lead to some unexpected results!
1608
+	 *
1609
+	 * @access public
1610
+	 * @param string $field_name               This is the name of the field on the object that contains the date/time
1611
+	 *                                         value being returned.
1612
+	 * @param string $callback                 must match a valid method in this class (defaults to get_datetime)
1613
+	 * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1614
+	 * @param string $prepend                  You can include something to prepend on the timestamp
1615
+	 * @param string $append                   You can include something to append on the timestamp
1616
+	 * @throws ReflectionException
1617
+	 * @throws InvalidArgumentException
1618
+	 * @throws InvalidInterfaceException
1619
+	 * @throws InvalidDataTypeException
1620
+	 * @throws EE_Error
1621
+	 * @return string timestamp
1622
+	 */
1623
+	public function display_in_my_timezone(
1624
+		$field_name,
1625
+		$callback = 'get_datetime',
1626
+		$args = null,
1627
+		$prepend = '',
1628
+		$append = ''
1629
+	) {
1630
+		$timezone = EEH_DTT_Helper::get_timezone();
1631
+		if ($timezone === $this->_timezone) {
1632
+			return '';
1633
+		}
1634
+		$original_timezone = $this->_timezone;
1635
+		$this->set_timezone($timezone);
1636
+		$fn   = (array) $field_name;
1637
+		$args = array_merge($fn, (array) $args);
1638
+		if (! method_exists($this, $callback)) {
1639
+			throw new EE_Error(
1640
+				sprintf(
1641
+					esc_html__(
1642
+						'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1643
+						'event_espresso'
1644
+					),
1645
+					$callback
1646
+				)
1647
+			);
1648
+		}
1649
+		$args   = (array) $args;
1650
+		$return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1651
+		$this->set_timezone($original_timezone);
1652
+		return $return;
1653
+	}
1654
+
1655
+
1656
+	/**
1657
+	 * Deletes this model object.
1658
+	 * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1659
+	 * override
1660
+	 * `EE_Base_Class::_delete` NOT this class.
1661
+	 *
1662
+	 * @return boolean | int
1663
+	 * @throws ReflectionException
1664
+	 * @throws InvalidArgumentException
1665
+	 * @throws InvalidInterfaceException
1666
+	 * @throws InvalidDataTypeException
1667
+	 * @throws EE_Error
1668
+	 */
1669
+	public function delete()
1670
+	{
1671
+		/**
1672
+		 * Called just before the `EE_Base_Class::_delete` method call.
1673
+		 * Note:
1674
+		 * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1675
+		 * should be aware that `_delete` may not always result in a permanent delete.
1676
+		 * For example, `EE_Soft_Delete_Base_Class::_delete`
1677
+		 * soft deletes (trash) the object and does not permanently delete it.
1678
+		 *
1679
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1680
+		 */
1681
+		do_action('AHEE__EE_Base_Class__delete__before', $this);
1682
+		$result = $this->_delete();
1683
+		/**
1684
+		 * Called just after the `EE_Base_Class::_delete` method call.
1685
+		 * Note:
1686
+		 * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1687
+		 * should be aware that `_delete` may not always result in a permanent delete.
1688
+		 * For example `EE_Soft_Base_Class::_delete`
1689
+		 * soft deletes (trash) the object and does not permanently delete it.
1690
+		 *
1691
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1692
+		 * @param boolean       $result
1693
+		 */
1694
+		do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1695
+		return $result;
1696
+	}
1697
+
1698
+
1699
+	/**
1700
+	 * Calls the specific delete method for the instantiated class.
1701
+	 * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1702
+	 * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1703
+	 * `EE_Base_Class::delete`
1704
+	 *
1705
+	 * @return bool|int
1706
+	 * @throws ReflectionException
1707
+	 * @throws InvalidArgumentException
1708
+	 * @throws InvalidInterfaceException
1709
+	 * @throws InvalidDataTypeException
1710
+	 * @throws EE_Error
1711
+	 */
1712
+	protected function _delete()
1713
+	{
1714
+		return $this->delete_permanently();
1715
+	}
1716
+
1717
+
1718
+	/**
1719
+	 * Deletes this model object permanently from db
1720
+	 * (but keep in mind related models may block the delete and return an error)
1721
+	 *
1722
+	 * @return bool | int
1723
+	 * @throws ReflectionException
1724
+	 * @throws InvalidArgumentException
1725
+	 * @throws InvalidInterfaceException
1726
+	 * @throws InvalidDataTypeException
1727
+	 * @throws EE_Error
1728
+	 */
1729
+	public function delete_permanently()
1730
+	{
1731
+		/**
1732
+		 * Called just before HARD deleting a model object
1733
+		 *
1734
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1735
+		 */
1736
+		do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1737
+		$model  = $this->get_model();
1738
+		$result = $model->delete_permanently_by_ID($this->ID());
1739
+		$this->refresh_cache_of_related_objects();
1740
+		/**
1741
+		 * Called just after HARD deleting a model object
1742
+		 *
1743
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1744
+		 * @param boolean       $result
1745
+		 */
1746
+		do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1747
+		return $result;
1748
+	}
1749
+
1750
+
1751
+	/**
1752
+	 * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1753
+	 * related model objects
1754
+	 *
1755
+	 * @throws ReflectionException
1756
+	 * @throws InvalidArgumentException
1757
+	 * @throws InvalidInterfaceException
1758
+	 * @throws InvalidDataTypeException
1759
+	 * @throws EE_Error
1760
+	 */
1761
+	public function refresh_cache_of_related_objects()
1762
+	{
1763
+		$model = $this->get_model();
1764
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1765
+			if (! empty($this->_model_relations[ $relation_name ])) {
1766
+				$related_objects = $this->_model_relations[ $relation_name ];
1767
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
1768
+					//this relation only stores a single model object, not an array
1769
+					//but let's make it consistent
1770
+					$related_objects = array($related_objects);
1771
+				}
1772
+				foreach ($related_objects as $related_object) {
1773
+					//only refresh their cache if they're in memory
1774
+					if ($related_object instanceof EE_Base_Class) {
1775
+						$related_object->clear_cache(
1776
+							$model->get_this_model_name(),
1777
+							$this
1778
+						);
1779
+					}
1780
+				}
1781
+			}
1782
+		}
1783
+	}
1784
+
1785
+
1786
+	/**
1787
+	 *        Saves this object to the database. An array may be supplied to set some values on this
1788
+	 * object just before saving.
1789
+	 *
1790
+	 * @access public
1791
+	 * @param array $set_cols_n_values keys are field names, values are their new values,
1792
+	 *                                 if provided during the save() method (often client code will change the fields'
1793
+	 *                                 values before calling save)
1794
+	 * @throws InvalidArgumentException
1795
+	 * @throws InvalidInterfaceException
1796
+	 * @throws InvalidDataTypeException
1797
+	 * @throws EE_Error
1798
+	 * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1799
+	 *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1800
+	 * @throws ReflectionException
1801
+	 * @throws ReflectionException
1802
+	 * @throws ReflectionException
1803
+	 */
1804
+	public function save($set_cols_n_values = array())
1805
+	{
1806
+		$model = $this->get_model();
1807
+		/**
1808
+		 * Filters the fields we're about to save on the model object
1809
+		 *
1810
+		 * @param array         $set_cols_n_values
1811
+		 * @param EE_Base_Class $model_object
1812
+		 */
1813
+		$set_cols_n_values = (array) apply_filters(
1814
+			'FHEE__EE_Base_Class__save__set_cols_n_values',
1815
+			$set_cols_n_values,
1816
+			$this
1817
+		);
1818
+		//set attributes as provided in $set_cols_n_values
1819
+		foreach ($set_cols_n_values as $column => $value) {
1820
+			$this->set($column, $value);
1821
+		}
1822
+		// no changes ? then don't do anything
1823
+		if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1824
+			return 0;
1825
+		}
1826
+		/**
1827
+		 * Saving a model object.
1828
+		 * Before we perform a save, this action is fired.
1829
+		 *
1830
+		 * @param EE_Base_Class $model_object the model object about to be saved.
1831
+		 */
1832
+		do_action('AHEE__EE_Base_Class__save__begin', $this);
1833
+		if (! $this->allow_persist()) {
1834
+			return 0;
1835
+		}
1836
+		// now get current attribute values
1837
+		$save_cols_n_values = $this->_fields;
1838
+		// if the object already has an ID, update it. Otherwise, insert it
1839
+		// also: change the assumption about values passed to the model NOT being prepare dby the model object.
1840
+		// They have been
1841
+		$old_assumption_concerning_value_preparation = $model
1842
+			->get_assumption_concerning_values_already_prepared_by_model_object();
1843
+		$model->assume_values_already_prepared_by_model_object(true);
1844
+		//does this model have an autoincrement PK?
1845
+		if ($model->has_primary_key_field()) {
1846
+			if ($model->get_primary_key_field()->is_auto_increment()) {
1847
+				//ok check if it's set, if so: update; if not, insert
1848
+				if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1849
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1850
+				} else {
1851
+					unset($save_cols_n_values[ $model->primary_key_name() ]);
1852
+					$results = $model->insert($save_cols_n_values);
1853
+					if ($results) {
1854
+						//if successful, set the primary key
1855
+						//but don't use the normal SET method, because it will check if
1856
+						//an item with the same ID exists in the mapper & db, then
1857
+						//will find it in the db (because we just added it) and THAT object
1858
+						//will get added to the mapper before we can add this one!
1859
+						//but if we just avoid using the SET method, all that headache can be avoided
1860
+						$pk_field_name                   = $model->primary_key_name();
1861
+						$this->_fields[ $pk_field_name ] = $results;
1862
+						$this->_clear_cached_property($pk_field_name);
1863
+						$model->add_to_entity_map($this);
1864
+						$this->_update_cached_related_model_objs_fks();
1865
+					}
1866
+				}
1867
+			} else {//PK is NOT auto-increment
1868
+				//so check if one like it already exists in the db
1869
+				if ($model->exists_by_ID($this->ID())) {
1870
+					if (WP_DEBUG && ! $this->in_entity_map()) {
1871
+						throw new EE_Error(
1872
+							sprintf(
1873
+								esc_html__(
1874
+									'Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1875
+									'event_espresso'
1876
+								),
1877
+								get_class($this),
1878
+								get_class($model) . '::instance()->add_to_entity_map()',
1879
+								get_class($model) . '::instance()->get_one_by_ID()',
1880
+								'<br />'
1881
+							)
1882
+						);
1883
+					}
1884
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1885
+				} else {
1886
+					$results = $model->insert($save_cols_n_values);
1887
+					$this->_update_cached_related_model_objs_fks();
1888
+				}
1889
+			}
1890
+		} else {//there is NO primary key
1891
+			$already_in_db = false;
1892
+			foreach ($model->unique_indexes() as $index) {
1893
+				$uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1894
+				if ($model->exists(array($uniqueness_where_params))) {
1895
+					$already_in_db = true;
1896
+				}
1897
+			}
1898
+			if ($already_in_db) {
1899
+				$combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1900
+					$model->get_combined_primary_key_fields());
1901
+				$results                     = $model->update(
1902
+					$save_cols_n_values,
1903
+					$combined_pk_fields_n_values
1904
+				);
1905
+			} else {
1906
+				$results = $model->insert($save_cols_n_values);
1907
+			}
1908
+		}
1909
+		//restore the old assumption about values being prepared by the model object
1910
+		$model->assume_values_already_prepared_by_model_object(
1911
+				$old_assumption_concerning_value_preparation
1912
+			);
1913
+		/**
1914
+		 * After saving the model object this action is called
1915
+		 *
1916
+		 * @param EE_Base_Class $model_object which was just saved
1917
+		 * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1918
+		 *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1919
+		 */
1920
+		do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1921
+		$this->_has_changes = false;
1922
+		return $results;
1923
+	}
1924
+
1925
+
1926
+	/**
1927
+	 * Updates the foreign key on related models objects pointing to this to have this model object's ID
1928
+	 * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1929
+	 * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1930
+	 * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1931
+	 * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1932
+	 * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1933
+	 * or not they exist in the DB (if they do, their DB records will be automatically updated)
1934
+	 *
1935
+	 * @return void
1936
+	 * @throws ReflectionException
1937
+	 * @throws InvalidArgumentException
1938
+	 * @throws InvalidInterfaceException
1939
+	 * @throws InvalidDataTypeException
1940
+	 * @throws EE_Error
1941
+	 */
1942
+	protected function _update_cached_related_model_objs_fks()
1943
+	{
1944
+		$model = $this->get_model();
1945
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1946
+			if ($relation_obj instanceof EE_Has_Many_Relation) {
1947
+				foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1948
+					$fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1949
+						$model->get_this_model_name()
1950
+					);
1951
+					$related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1952
+					if ($related_model_obj_in_cache->ID()) {
1953
+						$related_model_obj_in_cache->save();
1954
+					}
1955
+				}
1956
+			}
1957
+		}
1958
+	}
1959
+
1960
+
1961
+	/**
1962
+	 * Saves this model object and its NEW cached relations to the database.
1963
+	 * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1964
+	 * In order for that to work, we would need to mark model objects as dirty/clean...
1965
+	 * because otherwise, there's a potential for infinite looping of saving
1966
+	 * Saves the cached related model objects, and ensures the relation between them
1967
+	 * and this object and properly setup
1968
+	 *
1969
+	 * @return int ID of new model object on save; 0 on failure+
1970
+	 * @throws ReflectionException
1971
+	 * @throws InvalidArgumentException
1972
+	 * @throws InvalidInterfaceException
1973
+	 * @throws InvalidDataTypeException
1974
+	 * @throws EE_Error
1975
+	 */
1976
+	public function save_new_cached_related_model_objs()
1977
+	{
1978
+		//make sure this has been saved
1979
+		if (! $this->ID()) {
1980
+			$id = $this->save();
1981
+		} else {
1982
+			$id = $this->ID();
1983
+		}
1984
+		//now save all the NEW cached model objects  (ie they don't exist in the DB)
1985
+		foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1986
+			if ($this->_model_relations[ $relationName ]) {
1987
+				//is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1988
+				//or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1989
+				/* @var $related_model_obj EE_Base_Class */
1990
+				if ($relationObj instanceof EE_Belongs_To_Relation) {
1991
+					//add a relation to that relation type (which saves the appropriate thing in the process)
1992
+					//but ONLY if it DOES NOT exist in the DB
1993
+					$related_model_obj = $this->_model_relations[ $relationName ];
1994
+					//					if( ! $related_model_obj->ID()){
1995
+					$this->_add_relation_to($related_model_obj, $relationName);
1996
+					$related_model_obj->save_new_cached_related_model_objs();
1997
+					//					}
1998
+				} else {
1999
+					foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2000
+						//add a relation to that relation type (which saves the appropriate thing in the process)
2001
+						//but ONLY if it DOES NOT exist in the DB
2002
+						//						if( ! $related_model_obj->ID()){
2003
+						$this->_add_relation_to($related_model_obj, $relationName);
2004
+						$related_model_obj->save_new_cached_related_model_objs();
2005
+						//						}
2006
+					}
2007
+				}
2008
+			}
2009
+		}
2010
+		return $id;
2011
+	}
2012
+
2013
+
2014
+	/**
2015
+	 * for getting a model while instantiated.
2016
+	 *
2017
+	 * @return EEM_Base | EEM_CPT_Base
2018
+	 * @throws ReflectionException
2019
+	 * @throws InvalidArgumentException
2020
+	 * @throws InvalidInterfaceException
2021
+	 * @throws InvalidDataTypeException
2022
+	 * @throws EE_Error
2023
+	 */
2024
+	public function get_model()
2025
+	{
2026
+		if (! $this->_model) {
2027
+			$modelName    = self::_get_model_classname(get_class($this));
2028
+			$this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2029
+		} else {
2030
+			$this->_model->set_timezone($this->_timezone);
2031
+		}
2032
+		return $this->_model;
2033
+	}
2034
+
2035
+
2036
+	/**
2037
+	 * @param $props_n_values
2038
+	 * @param $classname
2039
+	 * @return mixed bool|EE_Base_Class|EEM_CPT_Base
2040
+	 * @throws ReflectionException
2041
+	 * @throws InvalidArgumentException
2042
+	 * @throws InvalidInterfaceException
2043
+	 * @throws InvalidDataTypeException
2044
+	 * @throws EE_Error
2045
+	 */
2046
+	protected static function _get_object_from_entity_mapper($props_n_values, $classname)
2047
+	{
2048
+		//TODO: will not work for Term_Relationships because they have no PK!
2049
+		$primary_id_ref = self::_get_primary_key_name($classname);
2050
+		if (
2051
+			array_key_exists($primary_id_ref, $props_n_values)
2052
+			&& ! empty($props_n_values[ $primary_id_ref ])
2053
+		) {
2054
+			$id = $props_n_values[ $primary_id_ref ];
2055
+			return self::_get_model($classname)->get_from_entity_map($id);
2056
+		}
2057
+		return false;
2058
+	}
2059
+
2060
+
2061
+	/**
2062
+	 * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
2063
+	 * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
2064
+	 * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
2065
+	 * we return false.
2066
+	 *
2067
+	 * @param  array  $props_n_values   incoming array of properties and their values
2068
+	 * @param  string $classname        the classname of the child class
2069
+	 * @param null    $timezone
2070
+	 * @param array   $date_formats     incoming date_formats in an array where the first value is the
2071
+	 *                                  date_format and the second value is the time format
2072
+	 * @return mixed (EE_Base_Class|bool)
2073
+	 * @throws InvalidArgumentException
2074
+	 * @throws InvalidInterfaceException
2075
+	 * @throws InvalidDataTypeException
2076
+	 * @throws EE_Error
2077
+	 * @throws ReflectionException
2078
+	 * @throws ReflectionException
2079
+	 * @throws ReflectionException
2080
+	 */
2081
+	protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
2082
+	{
2083
+		$existing = null;
2084
+		$model    = self::_get_model($classname, $timezone);
2085
+		if ($model->has_primary_key_field()) {
2086
+			$primary_id_ref = self::_get_primary_key_name($classname);
2087
+			if (array_key_exists($primary_id_ref, $props_n_values)
2088
+				&& ! empty($props_n_values[ $primary_id_ref ])
2089
+			) {
2090
+				$existing = $model->get_one_by_ID(
2091
+					$props_n_values[ $primary_id_ref ]
2092
+				);
2093
+			}
2094
+		} elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
2095
+			//no primary key on this model, but there's still a matching item in the DB
2096
+			$existing = self::_get_model($classname, $timezone)->get_one_by_ID(
2097
+				self::_get_model($classname, $timezone)
2098
+					->get_index_primary_key_string($props_n_values)
2099
+			);
2100
+		}
2101
+		if ($existing) {
2102
+			//set date formats if present before setting values
2103
+			if (! empty($date_formats) && is_array($date_formats)) {
2104
+				$existing->set_date_format($date_formats[0]);
2105
+				$existing->set_time_format($date_formats[1]);
2106
+			} else {
2107
+				//set default formats for date and time
2108
+				$existing->set_date_format(get_option('date_format'));
2109
+				$existing->set_time_format(get_option('time_format'));
2110
+			}
2111
+			foreach ($props_n_values as $property => $field_value) {
2112
+				$existing->set($property, $field_value);
2113
+			}
2114
+			return $existing;
2115
+		}
2116
+		return false;
2117
+	}
2118
+
2119
+
2120
+	/**
2121
+	 * Gets the EEM_*_Model for this class
2122
+	 *
2123
+	 * @access public now, as this is more convenient
2124
+	 * @param      $classname
2125
+	 * @param null $timezone
2126
+	 * @throws ReflectionException
2127
+	 * @throws InvalidArgumentException
2128
+	 * @throws InvalidInterfaceException
2129
+	 * @throws InvalidDataTypeException
2130
+	 * @throws EE_Error
2131
+	 * @return EEM_Base
2132
+	 */
2133
+	protected static function _get_model($classname, $timezone = null)
2134
+	{
2135
+		//find model for this class
2136
+		if (! $classname) {
2137
+			throw new EE_Error(
2138
+				sprintf(
2139
+					esc_html__(
2140
+						'What were you thinking calling _get_model(%s)?? You need to specify the class name',
2141
+						'event_espresso'
2142
+					),
2143
+					$classname
2144
+				)
2145
+			);
2146
+		}
2147
+		$modelName = self::_get_model_classname($classname);
2148
+		return self::_get_model_instance_with_name($modelName, $timezone);
2149
+	}
2150
+
2151
+
2152
+	/**
2153
+	 * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2154
+	 *
2155
+	 * @param string $model_classname
2156
+	 * @param null   $timezone
2157
+	 * @return EEM_Base
2158
+	 * @throws ReflectionException
2159
+	 * @throws InvalidArgumentException
2160
+	 * @throws InvalidInterfaceException
2161
+	 * @throws InvalidDataTypeException
2162
+	 * @throws EE_Error
2163
+	 */
2164
+	protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2165
+	{
2166
+		$model_classname = str_replace('EEM_', '', $model_classname);
2167
+		$model           = EE_Registry::instance()->load_model($model_classname);
2168
+		$model->set_timezone($timezone);
2169
+		return $model;
2170
+	}
2171
+
2172
+
2173
+	/**
2174
+	 * If a model name is provided (eg Registration), gets the model classname for that model.
2175
+	 * Also works if a model class's classname is provided (eg EE_Registration).
2176
+	 *
2177
+	 * @param null $model_name
2178
+	 * @return string like EEM_Attendee
2179
+	 */
2180
+	private static function _get_model_classname($model_name = null)
2181
+	{
2182
+		if (strpos($model_name, 'EE_') === 0) {
2183
+			$model_classname = str_replace('EE_', 'EEM_', $model_name);
2184
+		} else {
2185
+			$model_classname = 'EEM_' . $model_name;
2186
+		}
2187
+		return $model_classname;
2188
+	}
2189
+
2190
+
2191
+	/**
2192
+	 * returns the name of the primary key attribute
2193
+	 *
2194
+	 * @param null $classname
2195
+	 * @throws ReflectionException
2196
+	 * @throws InvalidArgumentException
2197
+	 * @throws InvalidInterfaceException
2198
+	 * @throws InvalidDataTypeException
2199
+	 * @throws EE_Error
2200
+	 * @return string
2201
+	 */
2202
+	protected static function _get_primary_key_name($classname = null)
2203
+	{
2204
+		if (! $classname) {
2205
+			throw new EE_Error(
2206
+				sprintf(
2207
+					esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
2208
+					$classname
2209
+				)
2210
+			);
2211
+		}
2212
+		return self::_get_model($classname)->get_primary_key_field()->get_name();
2213
+	}
2214
+
2215
+
2216
+	/**
2217
+	 * Gets the value of the primary key.
2218
+	 * If the object hasn't yet been saved, it should be whatever the model field's default was
2219
+	 * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2220
+	 * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2221
+	 *
2222
+	 * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2223
+	 * @throws ReflectionException
2224
+	 * @throws InvalidArgumentException
2225
+	 * @throws InvalidInterfaceException
2226
+	 * @throws InvalidDataTypeException
2227
+	 * @throws EE_Error
2228
+	 */
2229
+	public function ID()
2230
+	{
2231
+		$model = $this->get_model();
2232
+		//now that we know the name of the variable, use a variable variable to get its value and return its
2233
+		if ($model->has_primary_key_field()) {
2234
+			return $this->_fields[ $model->primary_key_name() ];
2235
+		}
2236
+		return $model->get_index_primary_key_string($this->_fields);
2237
+	}
2238
+
2239
+
2240
+	/**
2241
+	 * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2242
+	 * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2243
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2244
+	 *
2245
+	 * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2246
+	 * @param string $relationName                     eg 'Events','Question',etc.
2247
+	 *                                                 an attendee to a group, you also want to specify which role they
2248
+	 *                                                 will have in that group. So you would use this parameter to
2249
+	 *                                                 specify array('role-column-name'=>'role-id')
2250
+	 * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2251
+	 *                                                 allow you to further constrict the relation to being added.
2252
+	 *                                                 However, keep in mind that the columns (keys) given must match a
2253
+	 *                                                 column on the JOIN table and currently only the HABTM models
2254
+	 *                                                 accept these additional conditions.  Also remember that if an
2255
+	 *                                                 exact match isn't found for these extra cols/val pairs, then a
2256
+	 *                                                 NEW row is created in the join table.
2257
+	 * @param null   $cache_id
2258
+	 * @throws ReflectionException
2259
+	 * @throws InvalidArgumentException
2260
+	 * @throws InvalidInterfaceException
2261
+	 * @throws InvalidDataTypeException
2262
+	 * @throws EE_Error
2263
+	 * @return EE_Base_Class the object the relation was added to
2264
+	 */
2265
+	public function _add_relation_to(
2266
+		$otherObjectModelObjectOrID,
2267
+		$relationName,
2268
+		$extra_join_model_fields_n_values = array(),
2269
+		$cache_id = null
2270
+	) {
2271
+		$model = $this->get_model();
2272
+		//if this thing exists in the DB, save the relation to the DB
2273
+		if ($this->ID()) {
2274
+			$otherObject = $model->add_relationship_to(
2275
+				$this,
2276
+				$otherObjectModelObjectOrID,
2277
+				$relationName,
2278
+				$extra_join_model_fields_n_values
2279
+			);
2280
+			//clear cache so future get_many_related and get_first_related() return new results.
2281
+			$this->clear_cache($relationName, $otherObject, true);
2282
+			if ($otherObject instanceof EE_Base_Class) {
2283
+				$otherObject->clear_cache($model->get_this_model_name(), $this);
2284
+			}
2285
+		} else {
2286
+			//this thing doesn't exist in the DB,  so just cache it
2287
+			if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2288
+				throw new EE_Error(
2289
+					sprintf(
2290
+						esc_html__(
2291
+							'Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2292
+							'event_espresso'
2293
+						),
2294
+						$otherObjectModelObjectOrID,
2295
+						get_class($this)
2296
+					)
2297
+				);
2298
+			}
2299
+			$otherObject = $otherObjectModelObjectOrID;
2300
+			$this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2301
+		}
2302
+		if ($otherObject instanceof EE_Base_Class) {
2303
+			//fix the reciprocal relation too
2304
+			if ($otherObject->ID()) {
2305
+				//its saved so assumed relations exist in the DB, so we can just
2306
+				//clear the cache so future queries use the updated info in the DB
2307
+				$otherObject->clear_cache(
2308
+					$model->get_this_model_name(),
2309
+					null,
2310
+					true
2311
+				);
2312
+			} else {
2313
+				//it's not saved, so it caches relations like this
2314
+				$otherObject->cache($model->get_this_model_name(), $this);
2315
+			}
2316
+		}
2317
+		return $otherObject;
2318
+	}
2319
+
2320
+
2321
+	/**
2322
+	 * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2323
+	 * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2324
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2325
+	 * from the cache
2326
+	 *
2327
+	 * @param mixed  $otherObjectModelObjectOrID
2328
+	 *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2329
+	 *                to the DB yet
2330
+	 * @param string $relationName
2331
+	 * @param array  $where_query
2332
+	 *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2333
+	 *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2334
+	 *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2335
+	 *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2336
+	 *                created in the join table.
2337
+	 * @return EE_Base_Class the relation was removed from
2338
+	 * @throws ReflectionException
2339
+	 * @throws InvalidArgumentException
2340
+	 * @throws InvalidInterfaceException
2341
+	 * @throws InvalidDataTypeException
2342
+	 * @throws EE_Error
2343
+	 */
2344
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2345
+	{
2346
+		if ($this->ID()) {
2347
+			//if this exists in the DB, save the relation change to the DB too
2348
+			$otherObject = $this->get_model()->remove_relationship_to(
2349
+				$this,
2350
+				$otherObjectModelObjectOrID,
2351
+				$relationName,
2352
+				$where_query
2353
+			);
2354
+			$this->clear_cache(
2355
+				$relationName,
2356
+				$otherObject
2357
+			);
2358
+		} else {
2359
+			//this doesn't exist in the DB, just remove it from the cache
2360
+			$otherObject = $this->clear_cache(
2361
+				$relationName,
2362
+				$otherObjectModelObjectOrID
2363
+			);
2364
+		}
2365
+		if ($otherObject instanceof EE_Base_Class) {
2366
+			$otherObject->clear_cache(
2367
+				$this->get_model()->get_this_model_name(),
2368
+				$this
2369
+			);
2370
+		}
2371
+		return $otherObject;
2372
+	}
2373
+
2374
+
2375
+	/**
2376
+	 * Removes ALL the related things for the $relationName.
2377
+	 *
2378
+	 * @param string $relationName
2379
+	 * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2380
+	 * @return EE_Base_Class
2381
+	 * @throws ReflectionException
2382
+	 * @throws InvalidArgumentException
2383
+	 * @throws InvalidInterfaceException
2384
+	 * @throws InvalidDataTypeException
2385
+	 * @throws EE_Error
2386
+	 */
2387
+	public function _remove_relations($relationName, $where_query_params = array())
2388
+	{
2389
+		if ($this->ID()) {
2390
+			//if this exists in the DB, save the relation change to the DB too
2391
+			$otherObjects = $this->get_model()->remove_relations(
2392
+				$this,
2393
+				$relationName,
2394
+				$where_query_params
2395
+			);
2396
+			$this->clear_cache(
2397
+				$relationName,
2398
+				null,
2399
+				true
2400
+			);
2401
+		} else {
2402
+			//this doesn't exist in the DB, just remove it from the cache
2403
+			$otherObjects = $this->clear_cache(
2404
+				$relationName,
2405
+				null,
2406
+				true
2407
+			);
2408
+		}
2409
+		if (is_array($otherObjects)) {
2410
+			foreach ($otherObjects as $otherObject) {
2411
+				$otherObject->clear_cache(
2412
+					$this->get_model()->get_this_model_name(),
2413
+					$this
2414
+				);
2415
+			}
2416
+		}
2417
+		return $otherObjects;
2418
+	}
2419
+
2420
+
2421
+	/**
2422
+	 * Gets all the related model objects of the specified type. Eg, if the current class if
2423
+	 * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2424
+	 * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2425
+	 * because we want to get even deleted items etc.
2426
+	 *
2427
+	 * @param string $relationName key in the model's _model_relations array
2428
+	 * @param array  $query_params like EEM_Base::get_all
2429
+	 * @return EE_Base_Class[]     Results not necessarily indexed by IDs, because some results might not have primary
2430
+	 *                             keys or might not be saved yet. Consider using EEM_Base::get_IDs() on these
2431
+	 *                             results if you want IDs
2432
+	 * @throws ReflectionException
2433
+	 * @throws InvalidArgumentException
2434
+	 * @throws InvalidInterfaceException
2435
+	 * @throws InvalidDataTypeException
2436
+	 * @throws EE_Error
2437
+	 */
2438
+	public function get_many_related($relationName, $query_params = array())
2439
+	{
2440
+		if ($this->ID()) {
2441
+			//this exists in the DB, so get the related things from either the cache or the DB
2442
+			//if there are query parameters, forget about caching the related model objects.
2443
+			if ($query_params) {
2444
+				$related_model_objects = $this->get_model()->get_all_related(
2445
+					$this,
2446
+					$relationName,
2447
+					$query_params
2448
+				);
2449
+			} else {
2450
+				//did we already cache the result of this query?
2451
+				$cached_results = $this->get_all_from_cache($relationName);
2452
+				if (! $cached_results) {
2453
+					$related_model_objects = $this->get_model()->get_all_related(
2454
+						$this,
2455
+						$relationName,
2456
+						$query_params
2457
+					);
2458
+					//if no query parameters were passed, then we got all the related model objects
2459
+					//for that relation. We can cache them then.
2460
+					foreach ($related_model_objects as $related_model_object) {
2461
+						$this->cache($relationName, $related_model_object);
2462
+					}
2463
+				} else {
2464
+					$related_model_objects = $cached_results;
2465
+				}
2466
+			}
2467
+		} else {
2468
+			//this doesn't exist in the DB, so just get the related things from the cache
2469
+			$related_model_objects = $this->get_all_from_cache($relationName);
2470
+		}
2471
+		return $related_model_objects;
2472
+	}
2473
+
2474
+
2475
+	/**
2476
+	 * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2477
+	 * unless otherwise specified in the $query_params
2478
+	 *
2479
+	 * @param string $relation_name  model_name like 'Event', or 'Registration'
2480
+	 * @param array  $query_params   like EEM_Base::get_all's
2481
+	 * @param string $field_to_count name of field to count by. By default, uses primary key
2482
+	 * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2483
+	 *                               that by the setting $distinct to TRUE;
2484
+	 * @return int
2485
+	 * @throws ReflectionException
2486
+	 * @throws InvalidArgumentException
2487
+	 * @throws InvalidInterfaceException
2488
+	 * @throws InvalidDataTypeException
2489
+	 * @throws EE_Error
2490
+	 */
2491
+	public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2492
+	{
2493
+		return $this->get_model()->count_related(
2494
+			$this,
2495
+			$relation_name,
2496
+			$query_params,
2497
+			$field_to_count,
2498
+			$distinct
2499
+		);
2500
+	}
2501
+
2502
+
2503
+	/**
2504
+	 * Instead of getting the related model objects, simply sums up the values of the specified field.
2505
+	 * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2506
+	 *
2507
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2508
+	 * @param array  $query_params  like EEM_Base::get_all's
2509
+	 * @param string $field_to_sum  name of field to count by.
2510
+	 *                              By default, uses primary key
2511
+	 *                              (which doesn't make much sense, so you should probably change it)
2512
+	 * @return int
2513
+	 * @throws ReflectionException
2514
+	 * @throws InvalidArgumentException
2515
+	 * @throws InvalidInterfaceException
2516
+	 * @throws InvalidDataTypeException
2517
+	 * @throws EE_Error
2518
+	 */
2519
+	public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2520
+	{
2521
+		return $this->get_model()->sum_related(
2522
+			$this,
2523
+			$relation_name,
2524
+			$query_params,
2525
+			$field_to_sum
2526
+		);
2527
+	}
2528
+
2529
+
2530
+	/**
2531
+	 * Gets the first (ie, one) related model object of the specified type.
2532
+	 *
2533
+	 * @param string $relationName key in the model's _model_relations array
2534
+	 * @param array  $query_params like EEM_Base::get_all
2535
+	 * @return EE_Base_Class (not an array, a single object)
2536
+	 * @throws ReflectionException
2537
+	 * @throws InvalidArgumentException
2538
+	 * @throws InvalidInterfaceException
2539
+	 * @throws InvalidDataTypeException
2540
+	 * @throws EE_Error
2541
+	 */
2542
+	public function get_first_related($relationName, $query_params = array())
2543
+	{
2544
+		$model = $this->get_model();
2545
+		if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2546
+			//if they've provided some query parameters, don't bother trying to cache the result
2547
+			//also make sure we're not caching the result of get_first_related
2548
+			//on a relation which should have an array of objects (because the cache might have an array of objects)
2549
+			if ($query_params
2550
+				|| ! $model->related_settings_for($relationName)
2551
+					 instanceof
2552
+					 EE_Belongs_To_Relation
2553
+			) {
2554
+				$related_model_object = $model->get_first_related(
2555
+					$this,
2556
+					$relationName,
2557
+					$query_params
2558
+				);
2559
+			} else {
2560
+				//first, check if we've already cached the result of this query
2561
+				$cached_result = $this->get_one_from_cache($relationName);
2562
+				if (! $cached_result) {
2563
+					$related_model_object = $model->get_first_related(
2564
+						$this,
2565
+						$relationName,
2566
+						$query_params
2567
+					);
2568
+					$this->cache($relationName, $related_model_object);
2569
+				} else {
2570
+					$related_model_object = $cached_result;
2571
+				}
2572
+			}
2573
+		} else {
2574
+			$related_model_object = null;
2575
+			// this doesn't exist in the Db,
2576
+			// but maybe the relation is of type belongs to, and so the related thing might
2577
+			if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2578
+				$related_model_object = $model->get_first_related(
2579
+					$this,
2580
+					$relationName,
2581
+					$query_params
2582
+				);
2583
+			}
2584
+			// this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2585
+			// just get what's cached on this object
2586
+			if (! $related_model_object) {
2587
+				$related_model_object = $this->get_one_from_cache($relationName);
2588
+			}
2589
+		}
2590
+		return $related_model_object;
2591
+	}
2592
+
2593
+
2594
+	/**
2595
+	 * Does a delete on all related objects of type $relationName and removes
2596
+	 * the current model object's relation to them. If they can't be deleted (because
2597
+	 * of blocking related model objects) does nothing. If the related model objects are
2598
+	 * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2599
+	 * If this model object doesn't exist yet in the DB, just removes its related things
2600
+	 *
2601
+	 * @param string $relationName
2602
+	 * @param array  $query_params like EEM_Base::get_all's
2603
+	 * @return int how many deleted
2604
+	 * @throws ReflectionException
2605
+	 * @throws InvalidArgumentException
2606
+	 * @throws InvalidInterfaceException
2607
+	 * @throws InvalidDataTypeException
2608
+	 * @throws EE_Error
2609
+	 */
2610
+	public function delete_related($relationName, $query_params = array())
2611
+	{
2612
+		if ($this->ID()) {
2613
+			$count = $this->get_model()->delete_related(
2614
+				$this,
2615
+				$relationName,
2616
+				$query_params
2617
+			);
2618
+		} else {
2619
+			$count = count($this->get_all_from_cache($relationName));
2620
+			$this->clear_cache($relationName, null, true);
2621
+		}
2622
+		return $count;
2623
+	}
2624
+
2625
+
2626
+	/**
2627
+	 * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2628
+	 * the current model object's relation to them. If they can't be deleted (because
2629
+	 * of blocking related model objects) just does a soft delete on it instead, if possible.
2630
+	 * If the related thing isn't a soft-deletable model object, this function is identical
2631
+	 * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2632
+	 *
2633
+	 * @param string $relationName
2634
+	 * @param array  $query_params like EEM_Base::get_all's
2635
+	 * @return int how many deleted (including those soft deleted)
2636
+	 * @throws ReflectionException
2637
+	 * @throws InvalidArgumentException
2638
+	 * @throws InvalidInterfaceException
2639
+	 * @throws InvalidDataTypeException
2640
+	 * @throws EE_Error
2641
+	 */
2642
+	public function delete_related_permanently($relationName, $query_params = array())
2643
+	{
2644
+		if ($this->ID()) {
2645
+			$count = $this->get_model()->delete_related_permanently(
2646
+				$this,
2647
+				$relationName,
2648
+				$query_params
2649
+			);
2650
+		} else {
2651
+			$count = count($this->get_all_from_cache($relationName));
2652
+		}
2653
+		$this->clear_cache($relationName, null, true);
2654
+		return $count;
2655
+	}
2656
+
2657
+
2658
+	/**
2659
+	 * is_set
2660
+	 * Just a simple utility function children can use for checking if property exists
2661
+	 *
2662
+	 * @access  public
2663
+	 * @param  string $field_name property to check
2664
+	 * @return bool                              TRUE if existing,FALSE if not.
2665
+	 */
2666
+	public function is_set($field_name)
2667
+	{
2668
+		return isset($this->_fields[ $field_name ]);
2669
+	}
2670
+
2671
+
2672
+	/**
2673
+	 * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2674
+	 * EE_Error exception if they don't
2675
+	 *
2676
+	 * @param  mixed (string|array) $properties properties to check
2677
+	 * @throws EE_Error
2678
+	 * @return bool                              TRUE if existing, throw EE_Error if not.
2679
+	 */
2680
+	protected function _property_exists($properties)
2681
+	{
2682
+		foreach ((array) $properties as $property_name) {
2683
+			//first make sure this property exists
2684
+			if (! $this->_fields[ $property_name ]) {
2685
+				throw new EE_Error(
2686
+					sprintf(
2687
+						esc_html__(
2688
+							'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2689
+							'event_espresso'
2690
+						),
2691
+						$property_name
2692
+					)
2693
+				);
2694
+			}
2695
+		}
2696
+		return true;
2697
+	}
2698
+
2699
+
2700
+	/**
2701
+	 * This simply returns an array of model fields for this object
2702
+	 *
2703
+	 * @return array
2704
+	 * @throws ReflectionException
2705
+	 * @throws InvalidArgumentException
2706
+	 * @throws InvalidInterfaceException
2707
+	 * @throws InvalidDataTypeException
2708
+	 * @throws EE_Error
2709
+	 */
2710
+	public function model_field_array()
2711
+	{
2712
+		$fields     = $this->get_model()->field_settings(false);
2713
+		$properties = array();
2714
+		//remove prepended underscore
2715
+		foreach ($fields as $field_name => $settings) {
2716
+			$properties[ $field_name ] = $this->get($field_name);
2717
+		}
2718
+		return $properties;
2719
+	}
2720
+
2721
+
2722
+	/**
2723
+	 * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2724
+	 * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2725
+	 * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments.
2726
+	 * Instead of requiring a plugin to extend the EE_Base_Class
2727
+	 * (which works fine is there's only 1 plugin, but when will that happen?)
2728
+	 * they can add a hook onto 'filters_hook_espresso__{className}__{methodName}'
2729
+	 * (eg, filters_hook_espresso__EE_Answer__my_great_function)
2730
+	 * and accepts 2 arguments: the object on which the function was called,
2731
+	 * and an array of the original arguments passed to the function.
2732
+	 * Whatever their callback function returns will be returned by this function.
2733
+	 * Example: in functions.php (or in a plugin):
2734
+	 *      add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3);
2735
+	 *      function my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2736
+	 *          $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2737
+	 *          return $previousReturnValue.$returnString;
2738
+	 *      }
2739
+	 * require('EE_Answer.class.php');
2740
+	 * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2741
+	 * echo $answer->my_callback('monkeys',100);
2742
+	 * //will output "you called my_callback! and passed args:monkeys,100"
2743
+	 *
2744
+	 * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2745
+	 * @param array  $args       array of original arguments passed to the function
2746
+	 * @throws EE_Error
2747
+	 * @return mixed whatever the plugin which calls add_filter decides
2748
+	 */
2749
+	public function __call($methodName, $args)
2750
+	{
2751
+		$className = get_class($this);
2752
+		$tagName   = "FHEE__{$className}__{$methodName}";
2753
+		if (! has_filter($tagName)) {
2754
+			throw new EE_Error(
2755
+				sprintf(
2756
+					esc_html__(
2757
+						"Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2758
+						'event_espresso'
2759
+					),
2760
+					$methodName,
2761
+					$className,
2762
+					$tagName
2763
+				)
2764
+			);
2765
+		}
2766
+		return apply_filters($tagName, null, $this, $args);
2767
+	}
2768
+
2769
+
2770
+	/**
2771
+	 * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2772
+	 * A $previous_value can be specified in case there are many meta rows with the same key
2773
+	 *
2774
+	 * @param string $meta_key
2775
+	 * @param mixed  $meta_value
2776
+	 * @param mixed  $previous_value
2777
+	 * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2778
+	 *                  NOTE: if the values haven't changed, returns 0
2779
+	 * @throws InvalidArgumentException
2780
+	 * @throws InvalidInterfaceException
2781
+	 * @throws InvalidDataTypeException
2782
+	 * @throws EE_Error
2783
+	 * @throws ReflectionException
2784
+	 */
2785
+	public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2786
+	{
2787
+		$query_params = array(
2788
+			array(
2789
+				'EXM_key'  => $meta_key,
2790
+				'OBJ_ID'   => $this->ID(),
2791
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2792
+			),
2793
+		);
2794
+		if ($previous_value !== null) {
2795
+			$query_params[0]['EXM_value'] = $meta_value;
2796
+		}
2797
+		$existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2798
+		if (! $existing_rows_like_that) {
2799
+			return $this->add_extra_meta($meta_key, $meta_value);
2800
+		}
2801
+		foreach ($existing_rows_like_that as $existing_row) {
2802
+			$existing_row->save(array('EXM_value' => $meta_value));
2803
+		}
2804
+		return count($existing_rows_like_that);
2805
+	}
2806
+
2807
+
2808
+	/**
2809
+	 * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2810
+	 * no other extra meta for this model object have the same key. Returns TRUE if the
2811
+	 * extra meta row was entered, false if not
2812
+	 *
2813
+	 * @param string  $meta_key
2814
+	 * @param mixed   $meta_value
2815
+	 * @param boolean $unique
2816
+	 * @return boolean
2817
+	 * @throws InvalidArgumentException
2818
+	 * @throws InvalidInterfaceException
2819
+	 * @throws InvalidDataTypeException
2820
+	 * @throws EE_Error
2821
+	 * @throws ReflectionException
2822
+	 * @throws ReflectionException
2823
+	 */
2824
+	public function add_extra_meta($meta_key, $meta_value, $unique = false)
2825
+	{
2826
+		if ($unique) {
2827
+			$existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2828
+				array(
2829
+					array(
2830
+						'EXM_key'  => $meta_key,
2831
+						'OBJ_ID'   => $this->ID(),
2832
+						'EXM_type' => $this->get_model()->get_this_model_name(),
2833
+					),
2834
+				)
2835
+			);
2836
+			if ($existing_extra_meta) {
2837
+				return false;
2838
+			}
2839
+		}
2840
+		$new_extra_meta = EE_Extra_Meta::new_instance(
2841
+			array(
2842
+				'EXM_key'   => $meta_key,
2843
+				'EXM_value' => $meta_value,
2844
+				'OBJ_ID'    => $this->ID(),
2845
+				'EXM_type'  => $this->get_model()->get_this_model_name(),
2846
+			)
2847
+		);
2848
+		$new_extra_meta->save();
2849
+		return true;
2850
+	}
2851
+
2852
+
2853
+	/**
2854
+	 * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2855
+	 * is specified, only deletes extra meta records with that value.
2856
+	 *
2857
+	 * @param string $meta_key
2858
+	 * @param mixed  $meta_value
2859
+	 * @return int number of extra meta rows deleted
2860
+	 * @throws InvalidArgumentException
2861
+	 * @throws InvalidInterfaceException
2862
+	 * @throws InvalidDataTypeException
2863
+	 * @throws EE_Error
2864
+	 * @throws ReflectionException
2865
+	 */
2866
+	public function delete_extra_meta($meta_key, $meta_value = null)
2867
+	{
2868
+		$query_params = array(
2869
+			array(
2870
+				'EXM_key'  => $meta_key,
2871
+				'OBJ_ID'   => $this->ID(),
2872
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2873
+			),
2874
+		);
2875
+		if ($meta_value !== null) {
2876
+			$query_params[0]['EXM_value'] = $meta_value;
2877
+		}
2878
+		return EEM_Extra_Meta::instance()->delete($query_params);
2879
+	}
2880
+
2881
+
2882
+	/**
2883
+	 * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2884
+	 * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2885
+	 * You can specify $default is case you haven't found the extra meta
2886
+	 *
2887
+	 * @param string  $meta_key
2888
+	 * @param boolean $single
2889
+	 * @param mixed   $default if we don't find anything, what should we return?
2890
+	 * @return mixed single value if $single; array if ! $single
2891
+	 * @throws ReflectionException
2892
+	 * @throws InvalidArgumentException
2893
+	 * @throws InvalidInterfaceException
2894
+	 * @throws InvalidDataTypeException
2895
+	 * @throws EE_Error
2896
+	 */
2897
+	public function get_extra_meta($meta_key, $single = false, $default = null)
2898
+	{
2899
+		if ($single) {
2900
+			$result = $this->get_first_related(
2901
+				'Extra_Meta',
2902
+				array(array('EXM_key' => $meta_key))
2903
+			);
2904
+			if ($result instanceof EE_Extra_Meta) {
2905
+				return $result->value();
2906
+			}
2907
+		} else {
2908
+			$results = $this->get_many_related(
2909
+				'Extra_Meta',
2910
+				array(array('EXM_key' => $meta_key))
2911
+			);
2912
+			if ($results) {
2913
+				$values = array();
2914
+				foreach ($results as $result) {
2915
+					if ($result instanceof EE_Extra_Meta) {
2916
+						$values[ $result->ID() ] = $result->value();
2917
+					}
2918
+				}
2919
+				return $values;
2920
+			}
2921
+		}
2922
+		//if nothing discovered yet return default.
2923
+		return apply_filters(
2924
+			'FHEE__EE_Base_Class__get_extra_meta__default_value',
2925
+			$default,
2926
+			$meta_key,
2927
+			$single,
2928
+			$this
2929
+		);
2930
+	}
2931
+
2932
+
2933
+	/**
2934
+	 * Returns a simple array of all the extra meta associated with this model object.
2935
+	 * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2936
+	 * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2937
+	 * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2938
+	 * If $one_of_each_key is false, it will return an array with the top-level keys being
2939
+	 * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2940
+	 * finally the extra meta's value as each sub-value. (eg
2941
+	 * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2942
+	 *
2943
+	 * @param boolean $one_of_each_key
2944
+	 * @return array
2945
+	 * @throws ReflectionException
2946
+	 * @throws InvalidArgumentException
2947
+	 * @throws InvalidInterfaceException
2948
+	 * @throws InvalidDataTypeException
2949
+	 * @throws EE_Error
2950
+	 */
2951
+	public function all_extra_meta_array($one_of_each_key = true)
2952
+	{
2953
+		$return_array = array();
2954
+		if ($one_of_each_key) {
2955
+			$extra_meta_objs = $this->get_many_related(
2956
+				'Extra_Meta',
2957
+				array('group_by' => 'EXM_key')
2958
+			);
2959
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2960
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2961
+					$return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2962
+				}
2963
+			}
2964
+		} else {
2965
+			$extra_meta_objs = $this->get_many_related('Extra_Meta');
2966
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2967
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2968
+					if (! isset($return_array[ $extra_meta_obj->key() ])) {
2969
+						$return_array[ $extra_meta_obj->key() ] = array();
2970
+					}
2971
+					$return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2972
+				}
2973
+			}
2974
+		}
2975
+		return $return_array;
2976
+	}
2977
+
2978
+
2979
+	/**
2980
+	 * Gets a pretty nice displayable nice for this model object. Often overridden
2981
+	 *
2982
+	 * @return string
2983
+	 * @throws ReflectionException
2984
+	 * @throws InvalidArgumentException
2985
+	 * @throws InvalidInterfaceException
2986
+	 * @throws InvalidDataTypeException
2987
+	 * @throws EE_Error
2988
+	 */
2989
+	public function name()
2990
+	{
2991
+		//find a field that's not a text field
2992
+		$field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2993
+		if ($field_we_can_use) {
2994
+			return $this->get($field_we_can_use->get_name());
2995
+		}
2996
+		$first_few_properties = $this->model_field_array();
2997
+		$first_few_properties = array_slice($first_few_properties, 0, 3);
2998
+		$name_parts           = array();
2999
+		foreach ($first_few_properties as $name => $value) {
3000
+			$name_parts[] = "$name:$value";
3001
+		}
3002
+		return implode(',', $name_parts);
3003
+	}
3004
+
3005
+
3006
+	/**
3007
+	 * in_entity_map
3008
+	 * Checks if this model object has been proven to already be in the entity map
3009
+	 *
3010
+	 * @return boolean
3011
+	 * @throws ReflectionException
3012
+	 * @throws InvalidArgumentException
3013
+	 * @throws InvalidInterfaceException
3014
+	 * @throws InvalidDataTypeException
3015
+	 * @throws EE_Error
3016
+	 */
3017
+	public function in_entity_map()
3018
+	{
3019
+		// well, if we looked, did we find it in the entity map?
3020
+		return $this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this;
3021
+	}
3022
+
3023
+
3024
+	/**
3025
+	 * refresh_from_db
3026
+	 * Makes sure the fields and values on this model object are in-sync with what's in the database.
3027
+	 *
3028
+	 * @throws ReflectionException
3029
+	 * @throws InvalidArgumentException
3030
+	 * @throws InvalidInterfaceException
3031
+	 * @throws InvalidDataTypeException
3032
+	 * @throws EE_Error if this model object isn't in the entity mapper (because then you should
3033
+	 * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
3034
+	 */
3035
+	public function refresh_from_db()
3036
+	{
3037
+		if ($this->ID() && $this->in_entity_map()) {
3038
+			$this->get_model()->refresh_entity_map_from_db($this->ID());
3039
+		} else {
3040
+			//if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
3041
+			//if it has an ID but it's not in the map, and you're asking me to refresh it
3042
+			//that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
3043
+			//absolutely nothing in it for this ID
3044
+			if (WP_DEBUG) {
3045
+				throw new EE_Error(
3046
+					sprintf(
3047
+						esc_html__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
3048
+							'event_espresso'),
3049
+						$this->ID(),
3050
+						get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3051
+						get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3052
+					)
3053
+				);
3054
+			}
3055
+		}
3056
+	}
3057
+
3058
+
3059
+	/**
3060
+	 * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
3061
+	 * (probably a bad assumption they have made, oh well)
3062
+	 *
3063
+	 * @return string
3064
+	 */
3065
+	public function __toString()
3066
+	{
3067
+		try {
3068
+			return sprintf('%s (%s)', $this->name(), $this->ID());
3069
+		} catch (Exception $e) {
3070
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
3071
+			return '';
3072
+		}
3073
+	}
3074
+
3075
+
3076
+	/**
3077
+	 * Clear related model objects if they're already in the DB, because otherwise when we
3078
+	 * UN-serialize this model object we'll need to be careful to add them to the entity map.
3079
+	 * This means if we have made changes to those related model objects, and want to unserialize
3080
+	 * the this model object on a subsequent request, changes to those related model objects will be lost.
3081
+	 * Instead, those related model objects should be directly serialized and stored.
3082
+	 * Eg, the following won't work:
3083
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3084
+	 * $att = $reg->attendee();
3085
+	 * $att->set( 'ATT_fname', 'Dirk' );
3086
+	 * update_option( 'my_option', serialize( $reg ) );
3087
+	 * //END REQUEST
3088
+	 * //START NEXT REQUEST
3089
+	 * $reg = get_option( 'my_option' );
3090
+	 * $reg->attendee()->save();
3091
+	 * And would need to be replace with:
3092
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3093
+	 * $att = $reg->attendee();
3094
+	 * $att->set( 'ATT_fname', 'Dirk' );
3095
+	 * update_option( 'my_option', serialize( $reg ) );
3096
+	 * //END REQUEST
3097
+	 * //START NEXT REQUEST
3098
+	 * $att = get_option( 'my_option' );
3099
+	 * $att->save();
3100
+	 *
3101
+	 * @return array
3102
+	 * @throws ReflectionException
3103
+	 * @throws InvalidArgumentException
3104
+	 * @throws InvalidInterfaceException
3105
+	 * @throws InvalidDataTypeException
3106
+	 * @throws EE_Error
3107
+	 */
3108
+	public function __sleep()
3109
+	{
3110
+		$model = $this->get_model();
3111
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3112
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
3113
+				$classname = 'EE_' . $model->get_this_model_name();
3114
+				if (
3115
+					$this->get_one_from_cache($relation_name) instanceof $classname
3116
+					&& $this->get_one_from_cache($relation_name)->ID()
3117
+				) {
3118
+					$this->clear_cache(
3119
+						$relation_name,
3120
+						$this->get_one_from_cache($relation_name)->ID()
3121
+					);
3122
+				}
3123
+			}
3124
+		}
3125
+		$this->_props_n_values_provided_in_constructor = array();
3126
+		$properties_to_serialize                       = get_object_vars($this);
3127
+		//don't serialize the model. It's big and that risks recursion
3128
+		unset($properties_to_serialize['_model']);
3129
+		return array_keys($properties_to_serialize);
3130
+	}
3131
+
3132
+
3133
+	/**
3134
+	 * restore _props_n_values_provided_in_constructor
3135
+	 * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
3136
+	 * and therefore should NOT be used to determine if state change has occurred since initial construction.
3137
+	 * At best, you would only be able to detect if state change has occurred during THIS request.
3138
+	 */
3139
+	public function __wakeup()
3140
+	{
3141
+		$this->_props_n_values_provided_in_constructor = $this->_fields;
3142
+	}
3143 3143
 }
3144 3144
 
3145 3145
 
Please login to merge, or discard this patch.
Spacing   +117 added lines, -117 removed lines patch added patch discarded remove patch
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
         $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149 149
         // verify client code has not passed any invalid field names
150 150
         foreach ($fieldValues as $field_name => $field_value) {
151
-            if (! isset($model_fields[ $field_name ])) {
151
+            if ( ! isset($model_fields[$field_name])) {
152 152
                 throw new EE_Error(
153 153
                     sprintf(
154 154
                         esc_html__(
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
             }
164 164
         }
165 165
         $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
-        if (! empty($date_formats) && is_array($date_formats)) {
166
+        if ( ! empty($date_formats) && is_array($date_formats)) {
167 167
             list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168 168
         } else {
169 169
             //set default formats for date and time
@@ -176,7 +176,7 @@  discard block
 block discarded – undo
176 176
             foreach ($model_fields as $fieldName => $field) {
177 177
                 $this->set_from_db(
178 178
                     $fieldName,
179
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
179
+                    isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null
180 180
                 );
181 181
             }
182 182
         } else {
@@ -185,22 +185,22 @@  discard block
 block discarded – undo
185 185
             foreach ($model_fields as $fieldName => $field) {
186 186
                 $this->set(
187 187
                     $fieldName,
188
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
188
+                    isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true
189 189
                 );
190 190
             }
191 191
         }
192 192
         //remember what values were passed to this constructor
193 193
         $this->_props_n_values_provided_in_constructor = $fieldValues;
194 194
         //remember in entity mapper
195
-        if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
195
+        if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
196 196
             $model->add_to_entity_map($this);
197 197
         }
198 198
         //setup all the relations
199 199
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200 200
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
-                $this->_model_relations[ $relation_name ] = null;
201
+                $this->_model_relations[$relation_name] = null;
202 202
             } else {
203
-                $this->_model_relations[ $relation_name ] = array();
203
+                $this->_model_relations[$relation_name] = array();
204 204
             }
205 205
         }
206 206
         /**
@@ -251,10 +251,10 @@  discard block
 block discarded – undo
251 251
      */
252 252
     public function get_original($field_name)
253 253
     {
254
-        if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
254
+        if (isset($this->_props_n_values_provided_in_constructor[$field_name])
255 255
             && $field_settings = $this->get_model()->field_settings_for($field_name)
256 256
         ) {
257
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
257
+            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
258 258
         }
259 259
         return null;
260 260
     }
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
         // then don't do anything
292 292
         if (
293 293
             ! $use_default
294
-            && $this->_fields[ $field_name ] === $field_value
294
+            && $this->_fields[$field_name] === $field_value
295 295
             && $this->ID()
296 296
         ) {
297 297
             return;
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
             $holder_of_value = $field_obj->prepare_for_set($field_value);
310 310
             //should the value be null?
311 311
             if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
-                $this->_fields[ $field_name ] = $field_obj->get_default_value();
312
+                $this->_fields[$field_name] = $field_obj->get_default_value();
313 313
                 /**
314 314
                  * To save having to refactor all the models, if a default value is used for a
315 315
                  * EE_Datetime_Field, and that value is not null nor is it a DateTime
@@ -320,15 +320,15 @@  discard block
 block discarded – undo
320 320
                  */
321 321
                 if (
322 322
                     $field_obj instanceof EE_Datetime_Field
323
-                    && $this->_fields[ $field_name ] !== null
324
-                    && ! $this->_fields[ $field_name ] instanceof DateTime
323
+                    && $this->_fields[$field_name] !== null
324
+                    && ! $this->_fields[$field_name] instanceof DateTime
325 325
                 ) {
326
-                    empty($this->_fields[ $field_name ])
326
+                    empty($this->_fields[$field_name])
327 327
                         ? $this->set($field_name, time())
328
-                        : $this->set($field_name, $this->_fields[ $field_name ]);
328
+                        : $this->set($field_name, $this->_fields[$field_name]);
329 329
                 }
330 330
             } else {
331
-                $this->_fields[ $field_name ] = $holder_of_value;
331
+                $this->_fields[$field_name] = $holder_of_value;
332 332
             }
333 333
             //if we're not in the constructor...
334 334
             //now check if what we set was a primary key
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
                 $fields_on_model = self::_get_model(get_class($this))->field_settings();
346 346
                 $obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347 347
                 foreach ($fields_on_model as $field_obj) {
348
-                    if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
348
+                    if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349 349
                         && $field_obj->get_name() !== $field_name
350 350
                     ) {
351 351
                         $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
@@ -390,8 +390,8 @@  discard block
 block discarded – undo
390 390
      */
391 391
     public function getCustomSelect($alias)
392 392
     {
393
-        return isset($this->custom_selection_results[ $alias ])
394
-            ? $this->custom_selection_results[ $alias ]
393
+        return isset($this->custom_selection_results[$alias])
394
+            ? $this->custom_selection_results[$alias]
395 395
             : null;
396 396
     }
397 397
 
@@ -478,8 +478,8 @@  discard block
 block discarded – undo
478 478
         foreach ($model_fields as $field_name => $field_obj) {
479 479
             if ($field_obj instanceof EE_Datetime_Field) {
480 480
                 $field_obj->set_timezone($this->_timezone);
481
-                if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
-                    $this->_fields[ $field_name ]->setTimezone(new DateTimeZone($this->_timezone));
481
+                if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
482
+                    $this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
483 483
                 }
484 484
             }
485 485
         }
@@ -537,7 +537,7 @@  discard block
 block discarded – undo
537 537
      */
538 538
     public function get_format($full = true)
539 539
     {
540
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
540
+        return $full ? $this->_dt_frmt.' '.$this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541 541
     }
542 542
 
543 543
 
@@ -563,11 +563,11 @@  discard block
 block discarded – undo
563 563
     public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564 564
     {
565 565
         // its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
-        if (! $object_to_cache instanceof EE_Base_Class) {
566
+        if ( ! $object_to_cache instanceof EE_Base_Class) {
567 567
             return false;
568 568
         }
569 569
         // also get "how" the object is related, or throw an error
570
-        if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
570
+        if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571 571
             throw new EE_Error(
572 572
                 sprintf(
573 573
                     esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
@@ -581,38 +581,38 @@  discard block
 block discarded – undo
581 581
             // if it's a "belongs to" relationship, then there's only one related model object
582 582
             // eg, if this is a registration, there's only 1 attendee for it
583 583
             // so for these model objects just set it to be cached
584
-            $this->_model_relations[ $relationName ] = $object_to_cache;
584
+            $this->_model_relations[$relationName] = $object_to_cache;
585 585
             $return                                  = true;
586 586
         } else {
587 587
             // otherwise, this is the "many" side of a one to many relationship,
588 588
             // so we'll add the object to the array of related objects for that type.
589 589
             // eg: if this is an event, there are many registrations for that event,
590 590
             // so we cache the registrations in an array
591
-            if (! is_array($this->_model_relations[ $relationName ])) {
591
+            if ( ! is_array($this->_model_relations[$relationName])) {
592 592
                 // if for some reason, the cached item is a model object,
593 593
                 // then stick that in the array, otherwise start with an empty array
594
-                $this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
594
+                $this->_model_relations[$relationName] = $this->_model_relations[$relationName]
595 595
                                                            instanceof
596 596
                                                            EE_Base_Class
597
-                    ? array($this->_model_relations[ $relationName ]) : array();
597
+                    ? array($this->_model_relations[$relationName]) : array();
598 598
             }
599 599
             // first check for a cache_id which is normally empty
600
-            if (! empty($cache_id)) {
600
+            if ( ! empty($cache_id)) {
601 601
                 // if the cache_id exists, then it means we are purposely trying to cache this
602 602
                 // with a known key that can then be used to retrieve the object later on
603
-                $this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
603
+                $this->_model_relations[$relationName][$cache_id] = $object_to_cache;
604 604
                 $return                                               = $cache_id;
605 605
             } elseif ($object_to_cache->ID()) {
606 606
                 // OR the cached object originally came from the db, so let's just use it's PK for an ID
607
-                $this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
607
+                $this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
608 608
                 $return                                                            = $object_to_cache->ID();
609 609
             } else {
610 610
                 // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
-                $this->_model_relations[ $relationName ][] = $object_to_cache;
611
+                $this->_model_relations[$relationName][] = $object_to_cache;
612 612
                 // move the internal pointer to the end of the array
613
-                end($this->_model_relations[ $relationName ]);
613
+                end($this->_model_relations[$relationName]);
614 614
                 // and grab the key so that we can return it
615
-                $return = key($this->_model_relations[ $relationName ]);
615
+                $return = key($this->_model_relations[$relationName]);
616 616
             }
617 617
         }
618 618
         return $return;
@@ -638,7 +638,7 @@  discard block
 block discarded – undo
638 638
         //first make sure this property exists
639 639
         $this->get_model()->field_settings_for($fieldname);
640 640
         $cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
-        $this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
641
+        $this->_cached_properties[$fieldname][$cache_type] = $value;
642 642
     }
643 643
 
644 644
 
@@ -667,9 +667,9 @@  discard block
 block discarded – undo
667 667
         $model = $this->get_model();
668 668
         $model->field_settings_for($fieldname);
669 669
         $cache_type = $pretty ? 'pretty' : 'standard';
670
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
-        if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
-            return $this->_cached_properties[ $fieldname ][ $cache_type ];
670
+        $cache_type .= ! empty($extra_cache_ref) ? '_'.$extra_cache_ref : '';
671
+        if (isset($this->_cached_properties[$fieldname][$cache_type])) {
672
+            return $this->_cached_properties[$fieldname][$cache_type];
673 673
         }
674 674
         $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675 675
         $this->_set_cached_property($fieldname, $value, $cache_type);
@@ -697,12 +697,12 @@  discard block
 block discarded – undo
697 697
         if ($field_obj instanceof EE_Datetime_Field) {
698 698
             $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699 699
         }
700
-        if (! isset($this->_fields[ $fieldname ])) {
701
-            $this->_fields[ $fieldname ] = null;
700
+        if ( ! isset($this->_fields[$fieldname])) {
701
+            $this->_fields[$fieldname] = null;
702 702
         }
703 703
         $value = $pretty
704
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
-            : $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
704
+            ? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
705
+            : $field_obj->prepare_for_get($this->_fields[$fieldname]);
706 706
         return $value;
707 707
     }
708 708
 
@@ -760,8 +760,8 @@  discard block
 block discarded – undo
760 760
      */
761 761
     protected function _clear_cached_property($property_name)
762 762
     {
763
-        if (isset($this->_cached_properties[ $property_name ])) {
764
-            unset($this->_cached_properties[ $property_name ]);
763
+        if (isset($this->_cached_properties[$property_name])) {
764
+            unset($this->_cached_properties[$property_name]);
765 765
         }
766 766
     }
767 767
 
@@ -813,7 +813,7 @@  discard block
 block discarded – undo
813 813
     {
814 814
         $relationship_to_model = $this->get_model()->related_settings_for($relationName);
815 815
         $index_in_cache        = '';
816
-        if (! $relationship_to_model) {
816
+        if ( ! $relationship_to_model) {
817 817
             throw new EE_Error(
818 818
                 sprintf(
819 819
                     esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
@@ -824,21 +824,21 @@  discard block
 block discarded – undo
824 824
         }
825 825
         if ($clear_all) {
826 826
             $obj_removed                             = true;
827
-            $this->_model_relations[ $relationName ] = null;
827
+            $this->_model_relations[$relationName] = null;
828 828
         } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
-            $obj_removed                             = $this->_model_relations[ $relationName ];
830
-            $this->_model_relations[ $relationName ] = null;
829
+            $obj_removed                             = $this->_model_relations[$relationName];
830
+            $this->_model_relations[$relationName] = null;
831 831
         } else {
832 832
             if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833 833
                 && $object_to_remove_or_index_into_array->ID()
834 834
             ) {
835 835
                 $index_in_cache = $object_to_remove_or_index_into_array->ID();
836
-                if (is_array($this->_model_relations[ $relationName ])
837
-                    && ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
836
+                if (is_array($this->_model_relations[$relationName])
837
+                    && ! isset($this->_model_relations[$relationName][$index_in_cache])
838 838
                 ) {
839 839
                     $index_found_at = null;
840 840
                     //find this object in the array even though it has a different key
841
-                    foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
841
+                    foreach ($this->_model_relations[$relationName] as $index => $obj) {
842 842
                         /** @noinspection TypeUnsafeComparisonInspection */
843 843
                         if (
844 844
                             $obj instanceof EE_Base_Class
@@ -872,9 +872,9 @@  discard block
 block discarded – undo
872 872
             }
873 873
             //supposedly we've found it. But it could just be that the client code
874 874
             //provided a bad index/object
875
-            if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
-                $obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
-                unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
875
+            if (isset($this->_model_relations[$relationName][$index_in_cache])) {
876
+                $obj_removed = $this->_model_relations[$relationName][$index_in_cache];
877
+                unset($this->_model_relations[$relationName][$index_in_cache]);
878 878
             } else {
879 879
                 //that thing was never cached anyways.
880 880
                 $obj_removed = null;
@@ -905,7 +905,7 @@  discard block
 block discarded – undo
905 905
         $current_cache_id = ''
906 906
     ) {
907 907
         // verify that incoming object is of the correct type
908
-        $obj_class = 'EE_' . $relationName;
908
+        $obj_class = 'EE_'.$relationName;
909 909
         if ($newly_saved_object instanceof $obj_class) {
910 910
             /* @type EE_Base_Class $newly_saved_object */
911 911
             // now get the type of relation
@@ -913,17 +913,17 @@  discard block
 block discarded – undo
913 913
             // if this is a 1:1 relationship
914 914
             if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915 915
                 // then just replace the cached object with the newly saved object
916
-                $this->_model_relations[ $relationName ] = $newly_saved_object;
916
+                $this->_model_relations[$relationName] = $newly_saved_object;
917 917
                 return true;
918 918
                 // or if it's some kind of sordid feral polyamorous relationship...
919 919
             }
920
-            if (is_array($this->_model_relations[ $relationName ])
921
-                      && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
920
+            if (is_array($this->_model_relations[$relationName])
921
+                      && isset($this->_model_relations[$relationName][$current_cache_id])
922 922
             ) {
923 923
                 // then remove the current cached item
924
-                unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
924
+                unset($this->_model_relations[$relationName][$current_cache_id]);
925 925
                 // and cache the newly saved object using it's new ID
926
-                $this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
926
+                $this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
927 927
                 return true;
928 928
             }
929 929
         }
@@ -940,8 +940,8 @@  discard block
 block discarded – undo
940 940
      */
941 941
     public function get_one_from_cache($relationName)
942 942
     {
943
-        $cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
-            ? $this->_model_relations[ $relationName ]
943
+        $cached_array_or_object = isset($this->_model_relations[$relationName])
944
+            ? $this->_model_relations[$relationName]
945 945
             : null;
946 946
         if (is_array($cached_array_or_object)) {
947 947
             return array_shift($cached_array_or_object);
@@ -964,7 +964,7 @@  discard block
 block discarded – undo
964 964
      */
965 965
     public function get_all_from_cache($relationName)
966 966
     {
967
-        $objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
967
+        $objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
968 968
         // if the result is not an array, but exists, make it an array
969 969
         $objects = is_array($objects) ? $objects : array($objects);
970 970
         //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
@@ -1148,7 +1148,7 @@  discard block
 block discarded – undo
1148 1148
             } else {
1149 1149
                 $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150 1150
             }
1151
-            $this->_fields[ $field_name ] = $field_value;
1151
+            $this->_fields[$field_name] = $field_value;
1152 1152
             $this->_clear_cached_property($field_name);
1153 1153
         }
1154 1154
     }
@@ -1188,9 +1188,9 @@  discard block
 block discarded – undo
1188 1188
     public function get_raw($field_name)
1189 1189
     {
1190 1190
         $field_settings = $this->get_model()->field_settings_for($field_name);
1191
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
-            ? $this->_fields[ $field_name ]->format('U')
1193
-            : $this->_fields[ $field_name ];
1191
+        return $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime
1192
+            ? $this->_fields[$field_name]->format('U')
1193
+            : $this->_fields[$field_name];
1194 1194
     }
1195 1195
 
1196 1196
 
@@ -1213,7 +1213,7 @@  discard block
 block discarded – undo
1213 1213
     public function get_DateTime_object($field_name)
1214 1214
     {
1215 1215
         $field_settings = $this->get_model()->field_settings_for($field_name);
1216
-        if (! $field_settings instanceof EE_Datetime_Field) {
1216
+        if ( ! $field_settings instanceof EE_Datetime_Field) {
1217 1217
             EE_Error::add_error(
1218 1218
                 sprintf(
1219 1219
                     esc_html__(
@@ -1228,7 +1228,7 @@  discard block
 block discarded – undo
1228 1228
             );
1229 1229
             return false;
1230 1230
         }
1231
-        return $this->_fields[ $field_name ];
1231
+        return $this->_fields[$field_name];
1232 1232
     }
1233 1233
 
1234 1234
 
@@ -1469,7 +1469,7 @@  discard block
 block discarded – undo
1469 1469
      */
1470 1470
     public function get_i18n_datetime($field_name, $format = '')
1471 1471
     {
1472
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1472
+        $format = empty($format) ? $this->_dt_frmt.' '.$this->_tm_frmt : $format;
1473 1473
         return date_i18n(
1474 1474
             $format,
1475 1475
             EEH_DTT_Helper::get_timestamp_with_offset(
@@ -1581,19 +1581,19 @@  discard block
 block discarded – undo
1581 1581
         $field->set_time_format($this->_tm_frmt);
1582 1582
         switch ($what) {
1583 1583
             case 'T' :
1584
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1584
+                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1585 1585
                     $datetime_value,
1586
-                    $this->_fields[ $fieldname ]
1586
+                    $this->_fields[$fieldname]
1587 1587
                 );
1588 1588
                 break;
1589 1589
             case 'D' :
1590
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1590
+                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1591 1591
                     $datetime_value,
1592
-                    $this->_fields[ $fieldname ]
1592
+                    $this->_fields[$fieldname]
1593 1593
                 );
1594 1594
                 break;
1595 1595
             case 'B' :
1596
-                $this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1596
+                $this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1597 1597
                 break;
1598 1598
         }
1599 1599
         $this->_clear_cached_property($fieldname);
@@ -1635,7 +1635,7 @@  discard block
 block discarded – undo
1635 1635
         $this->set_timezone($timezone);
1636 1636
         $fn   = (array) $field_name;
1637 1637
         $args = array_merge($fn, (array) $args);
1638
-        if (! method_exists($this, $callback)) {
1638
+        if ( ! method_exists($this, $callback)) {
1639 1639
             throw new EE_Error(
1640 1640
                 sprintf(
1641 1641
                     esc_html__(
@@ -1647,7 +1647,7 @@  discard block
 block discarded – undo
1647 1647
             );
1648 1648
         }
1649 1649
         $args   = (array) $args;
1650
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1650
+        $return = $prepend.call_user_func_array(array($this, $callback), $args).$append;
1651 1651
         $this->set_timezone($original_timezone);
1652 1652
         return $return;
1653 1653
     }
@@ -1762,8 +1762,8 @@  discard block
 block discarded – undo
1762 1762
     {
1763 1763
         $model = $this->get_model();
1764 1764
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1765
-            if (! empty($this->_model_relations[ $relation_name ])) {
1766
-                $related_objects = $this->_model_relations[ $relation_name ];
1765
+            if ( ! empty($this->_model_relations[$relation_name])) {
1766
+                $related_objects = $this->_model_relations[$relation_name];
1767 1767
                 if ($relation_obj instanceof EE_Belongs_To_Relation) {
1768 1768
                     //this relation only stores a single model object, not an array
1769 1769
                     //but let's make it consistent
@@ -1820,7 +1820,7 @@  discard block
 block discarded – undo
1820 1820
             $this->set($column, $value);
1821 1821
         }
1822 1822
         // no changes ? then don't do anything
1823
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1823
+        if ( ! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1824 1824
             return 0;
1825 1825
         }
1826 1826
         /**
@@ -1830,7 +1830,7 @@  discard block
 block discarded – undo
1830 1830
          * @param EE_Base_Class $model_object the model object about to be saved.
1831 1831
          */
1832 1832
         do_action('AHEE__EE_Base_Class__save__begin', $this);
1833
-        if (! $this->allow_persist()) {
1833
+        if ( ! $this->allow_persist()) {
1834 1834
             return 0;
1835 1835
         }
1836 1836
         // now get current attribute values
@@ -1845,10 +1845,10 @@  discard block
 block discarded – undo
1845 1845
         if ($model->has_primary_key_field()) {
1846 1846
             if ($model->get_primary_key_field()->is_auto_increment()) {
1847 1847
                 //ok check if it's set, if so: update; if not, insert
1848
-                if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1848
+                if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1849 1849
                     $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1850 1850
                 } else {
1851
-                    unset($save_cols_n_values[ $model->primary_key_name() ]);
1851
+                    unset($save_cols_n_values[$model->primary_key_name()]);
1852 1852
                     $results = $model->insert($save_cols_n_values);
1853 1853
                     if ($results) {
1854 1854
                         //if successful, set the primary key
@@ -1858,7 +1858,7 @@  discard block
 block discarded – undo
1858 1858
                         //will get added to the mapper before we can add this one!
1859 1859
                         //but if we just avoid using the SET method, all that headache can be avoided
1860 1860
                         $pk_field_name                   = $model->primary_key_name();
1861
-                        $this->_fields[ $pk_field_name ] = $results;
1861
+                        $this->_fields[$pk_field_name] = $results;
1862 1862
                         $this->_clear_cached_property($pk_field_name);
1863 1863
                         $model->add_to_entity_map($this);
1864 1864
                         $this->_update_cached_related_model_objs_fks();
@@ -1875,8 +1875,8 @@  discard block
 block discarded – undo
1875 1875
                                     'event_espresso'
1876 1876
                                 ),
1877 1877
                                 get_class($this),
1878
-                                get_class($model) . '::instance()->add_to_entity_map()',
1879
-                                get_class($model) . '::instance()->get_one_by_ID()',
1878
+                                get_class($model).'::instance()->add_to_entity_map()',
1879
+                                get_class($model).'::instance()->get_one_by_ID()',
1880 1880
                                 '<br />'
1881 1881
                             )
1882 1882
                         );
@@ -1976,27 +1976,27 @@  discard block
 block discarded – undo
1976 1976
     public function save_new_cached_related_model_objs()
1977 1977
     {
1978 1978
         //make sure this has been saved
1979
-        if (! $this->ID()) {
1979
+        if ( ! $this->ID()) {
1980 1980
             $id = $this->save();
1981 1981
         } else {
1982 1982
             $id = $this->ID();
1983 1983
         }
1984 1984
         //now save all the NEW cached model objects  (ie they don't exist in the DB)
1985 1985
         foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1986
-            if ($this->_model_relations[ $relationName ]) {
1986
+            if ($this->_model_relations[$relationName]) {
1987 1987
                 //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1988 1988
                 //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1989 1989
                 /* @var $related_model_obj EE_Base_Class */
1990 1990
                 if ($relationObj instanceof EE_Belongs_To_Relation) {
1991 1991
                     //add a relation to that relation type (which saves the appropriate thing in the process)
1992 1992
                     //but ONLY if it DOES NOT exist in the DB
1993
-                    $related_model_obj = $this->_model_relations[ $relationName ];
1993
+                    $related_model_obj = $this->_model_relations[$relationName];
1994 1994
                     //					if( ! $related_model_obj->ID()){
1995 1995
                     $this->_add_relation_to($related_model_obj, $relationName);
1996 1996
                     $related_model_obj->save_new_cached_related_model_objs();
1997 1997
                     //					}
1998 1998
                 } else {
1999
-                    foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
1999
+                    foreach ($this->_model_relations[$relationName] as $related_model_obj) {
2000 2000
                         //add a relation to that relation type (which saves the appropriate thing in the process)
2001 2001
                         //but ONLY if it DOES NOT exist in the DB
2002 2002
                         //						if( ! $related_model_obj->ID()){
@@ -2023,7 +2023,7 @@  discard block
 block discarded – undo
2023 2023
      */
2024 2024
     public function get_model()
2025 2025
     {
2026
-        if (! $this->_model) {
2026
+        if ( ! $this->_model) {
2027 2027
             $modelName    = self::_get_model_classname(get_class($this));
2028 2028
             $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2029 2029
         } else {
@@ -2049,9 +2049,9 @@  discard block
 block discarded – undo
2049 2049
         $primary_id_ref = self::_get_primary_key_name($classname);
2050 2050
         if (
2051 2051
             array_key_exists($primary_id_ref, $props_n_values)
2052
-            && ! empty($props_n_values[ $primary_id_ref ])
2052
+            && ! empty($props_n_values[$primary_id_ref])
2053 2053
         ) {
2054
-            $id = $props_n_values[ $primary_id_ref ];
2054
+            $id = $props_n_values[$primary_id_ref];
2055 2055
             return self::_get_model($classname)->get_from_entity_map($id);
2056 2056
         }
2057 2057
         return false;
@@ -2085,10 +2085,10 @@  discard block
 block discarded – undo
2085 2085
         if ($model->has_primary_key_field()) {
2086 2086
             $primary_id_ref = self::_get_primary_key_name($classname);
2087 2087
             if (array_key_exists($primary_id_ref, $props_n_values)
2088
-                && ! empty($props_n_values[ $primary_id_ref ])
2088
+                && ! empty($props_n_values[$primary_id_ref])
2089 2089
             ) {
2090 2090
                 $existing = $model->get_one_by_ID(
2091
-                    $props_n_values[ $primary_id_ref ]
2091
+                    $props_n_values[$primary_id_ref]
2092 2092
                 );
2093 2093
             }
2094 2094
         } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
@@ -2100,7 +2100,7 @@  discard block
 block discarded – undo
2100 2100
         }
2101 2101
         if ($existing) {
2102 2102
             //set date formats if present before setting values
2103
-            if (! empty($date_formats) && is_array($date_formats)) {
2103
+            if ( ! empty($date_formats) && is_array($date_formats)) {
2104 2104
                 $existing->set_date_format($date_formats[0]);
2105 2105
                 $existing->set_time_format($date_formats[1]);
2106 2106
             } else {
@@ -2133,7 +2133,7 @@  discard block
 block discarded – undo
2133 2133
     protected static function _get_model($classname, $timezone = null)
2134 2134
     {
2135 2135
         //find model for this class
2136
-        if (! $classname) {
2136
+        if ( ! $classname) {
2137 2137
             throw new EE_Error(
2138 2138
                 sprintf(
2139 2139
                     esc_html__(
@@ -2182,7 +2182,7 @@  discard block
 block discarded – undo
2182 2182
         if (strpos($model_name, 'EE_') === 0) {
2183 2183
             $model_classname = str_replace('EE_', 'EEM_', $model_name);
2184 2184
         } else {
2185
-            $model_classname = 'EEM_' . $model_name;
2185
+            $model_classname = 'EEM_'.$model_name;
2186 2186
         }
2187 2187
         return $model_classname;
2188 2188
     }
@@ -2201,7 +2201,7 @@  discard block
 block discarded – undo
2201 2201
      */
2202 2202
     protected static function _get_primary_key_name($classname = null)
2203 2203
     {
2204
-        if (! $classname) {
2204
+        if ( ! $classname) {
2205 2205
             throw new EE_Error(
2206 2206
                 sprintf(
2207 2207
                     esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
@@ -2231,7 +2231,7 @@  discard block
 block discarded – undo
2231 2231
         $model = $this->get_model();
2232 2232
         //now that we know the name of the variable, use a variable variable to get its value and return its
2233 2233
         if ($model->has_primary_key_field()) {
2234
-            return $this->_fields[ $model->primary_key_name() ];
2234
+            return $this->_fields[$model->primary_key_name()];
2235 2235
         }
2236 2236
         return $model->get_index_primary_key_string($this->_fields);
2237 2237
     }
@@ -2284,7 +2284,7 @@  discard block
 block discarded – undo
2284 2284
             }
2285 2285
         } else {
2286 2286
             //this thing doesn't exist in the DB,  so just cache it
2287
-            if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2287
+            if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2288 2288
                 throw new EE_Error(
2289 2289
                     sprintf(
2290 2290
                         esc_html__(
@@ -2449,7 +2449,7 @@  discard block
 block discarded – undo
2449 2449
             } else {
2450 2450
                 //did we already cache the result of this query?
2451 2451
                 $cached_results = $this->get_all_from_cache($relationName);
2452
-                if (! $cached_results) {
2452
+                if ( ! $cached_results) {
2453 2453
                     $related_model_objects = $this->get_model()->get_all_related(
2454 2454
                         $this,
2455 2455
                         $relationName,
@@ -2559,7 +2559,7 @@  discard block
 block discarded – undo
2559 2559
             } else {
2560 2560
                 //first, check if we've already cached the result of this query
2561 2561
                 $cached_result = $this->get_one_from_cache($relationName);
2562
-                if (! $cached_result) {
2562
+                if ( ! $cached_result) {
2563 2563
                     $related_model_object = $model->get_first_related(
2564 2564
                         $this,
2565 2565
                         $relationName,
@@ -2583,7 +2583,7 @@  discard block
 block discarded – undo
2583 2583
             }
2584 2584
             // this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2585 2585
             // just get what's cached on this object
2586
-            if (! $related_model_object) {
2586
+            if ( ! $related_model_object) {
2587 2587
                 $related_model_object = $this->get_one_from_cache($relationName);
2588 2588
             }
2589 2589
         }
@@ -2665,7 +2665,7 @@  discard block
 block discarded – undo
2665 2665
      */
2666 2666
     public function is_set($field_name)
2667 2667
     {
2668
-        return isset($this->_fields[ $field_name ]);
2668
+        return isset($this->_fields[$field_name]);
2669 2669
     }
2670 2670
 
2671 2671
 
@@ -2681,7 +2681,7 @@  discard block
 block discarded – undo
2681 2681
     {
2682 2682
         foreach ((array) $properties as $property_name) {
2683 2683
             //first make sure this property exists
2684
-            if (! $this->_fields[ $property_name ]) {
2684
+            if ( ! $this->_fields[$property_name]) {
2685 2685
                 throw new EE_Error(
2686 2686
                     sprintf(
2687 2687
                         esc_html__(
@@ -2713,7 +2713,7 @@  discard block
 block discarded – undo
2713 2713
         $properties = array();
2714 2714
         //remove prepended underscore
2715 2715
         foreach ($fields as $field_name => $settings) {
2716
-            $properties[ $field_name ] = $this->get($field_name);
2716
+            $properties[$field_name] = $this->get($field_name);
2717 2717
         }
2718 2718
         return $properties;
2719 2719
     }
@@ -2750,7 +2750,7 @@  discard block
 block discarded – undo
2750 2750
     {
2751 2751
         $className = get_class($this);
2752 2752
         $tagName   = "FHEE__{$className}__{$methodName}";
2753
-        if (! has_filter($tagName)) {
2753
+        if ( ! has_filter($tagName)) {
2754 2754
             throw new EE_Error(
2755 2755
                 sprintf(
2756 2756
                     esc_html__(
@@ -2795,7 +2795,7 @@  discard block
 block discarded – undo
2795 2795
             $query_params[0]['EXM_value'] = $meta_value;
2796 2796
         }
2797 2797
         $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2798
-        if (! $existing_rows_like_that) {
2798
+        if ( ! $existing_rows_like_that) {
2799 2799
             return $this->add_extra_meta($meta_key, $meta_value);
2800 2800
         }
2801 2801
         foreach ($existing_rows_like_that as $existing_row) {
@@ -2913,7 +2913,7 @@  discard block
 block discarded – undo
2913 2913
                 $values = array();
2914 2914
                 foreach ($results as $result) {
2915 2915
                     if ($result instanceof EE_Extra_Meta) {
2916
-                        $values[ $result->ID() ] = $result->value();
2916
+                        $values[$result->ID()] = $result->value();
2917 2917
                     }
2918 2918
                 }
2919 2919
                 return $values;
@@ -2958,17 +2958,17 @@  discard block
 block discarded – undo
2958 2958
             );
2959 2959
             foreach ($extra_meta_objs as $extra_meta_obj) {
2960 2960
                 if ($extra_meta_obj instanceof EE_Extra_Meta) {
2961
-                    $return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2961
+                    $return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2962 2962
                 }
2963 2963
             }
2964 2964
         } else {
2965 2965
             $extra_meta_objs = $this->get_many_related('Extra_Meta');
2966 2966
             foreach ($extra_meta_objs as $extra_meta_obj) {
2967 2967
                 if ($extra_meta_obj instanceof EE_Extra_Meta) {
2968
-                    if (! isset($return_array[ $extra_meta_obj->key() ])) {
2969
-                        $return_array[ $extra_meta_obj->key() ] = array();
2968
+                    if ( ! isset($return_array[$extra_meta_obj->key()])) {
2969
+                        $return_array[$extra_meta_obj->key()] = array();
2970 2970
                     }
2971
-                    $return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2971
+                    $return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2972 2972
                 }
2973 2973
             }
2974 2974
         }
@@ -3047,8 +3047,8 @@  discard block
 block discarded – undo
3047 3047
                         esc_html__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
3048 3048
                             'event_espresso'),
3049 3049
                         $this->ID(),
3050
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3051
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3050
+                        get_class($this->get_model()).'::instance()->add_to_entity_map()',
3051
+                        get_class($this->get_model()).'::instance()->refresh_entity_map()'
3052 3052
                     )
3053 3053
                 );
3054 3054
             }
@@ -3110,7 +3110,7 @@  discard block
 block discarded – undo
3110 3110
         $model = $this->get_model();
3111 3111
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3112 3112
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
3113
-                $classname = 'EE_' . $model->get_this_model_name();
3113
+                $classname = 'EE_'.$model->get_this_model_name();
3114 3114
                 if (
3115 3115
                     $this->get_one_from_cache($relation_name) instanceof $classname
3116 3116
                     && $this->get_one_from_cache($relation_name)->ID()
Please login to merge, or discard this patch.