Completed
Branch BUG/11288/fix-datepicker (d15367)
by
unknown
108:07 queued 94:31
created
core/business/EE_Registration_Processor.class.php 1 patch
Indentation   +775 added lines, -775 removed lines patch added patch discarded remove patch
@@ -27,781 +27,781 @@
 block discarded – undo
27 27
 class EE_Registration_Processor extends EE_Processor_Base
28 28
 {
29 29
 
30
-    /**
31
-     * @var EE_Registration_Processor $_instance
32
-     * @access    private
33
-     */
34
-    private static $_instance;
35
-
36
-    /**
37
-     * initial reg status at the beginning of this request.
38
-     * indexed by registration ID
39
-     *
40
-     * @var array
41
-     */
42
-    protected $_old_reg_status = array();
43
-
44
-    /**
45
-     * reg status at the end of the request after all processing.
46
-     * indexed by registration ID
47
-     *
48
-     * @var array
49
-     */
50
-    protected $_new_reg_status = array();
51
-
52
-    /**
53
-     * amounts paid at the end of the request after all processing.
54
-     * indexed by registration ID
55
-     *
56
-     * @var array
57
-     */
58
-    protected static $_amount_paid = array();
59
-
60
-    /**
61
-     * Cache of the reg final price for registrations corresponding to a ticket line item
62
-     *
63
-     * @deprecated
64
-     * @var array @see EEH_Line_Item::calculate_reg_final_prices_per_line_item()'s return value
65
-     */
66
-    protected $_reg_final_price_per_tkt_line_item;
67
-
68
-    /**
69
-     * @var EE_Request $request
70
-     */
71
-    protected $request;
72
-
73
-
74
-
75
-    /**
76
-     * @singleton method used to instantiate class object
77
-     * @param EE_Request|null $request
78
-     * @return EE_Registration_Processor instance
79
-     * @throws \InvalidArgumentException
80
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
81
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
82
-     */
83
-    public static function instance(EE_Request $request = null)
84
-    {
85
-        // check if class object is instantiated
86
-        if (! self::$_instance instanceof EE_Registration_Processor) {
87
-            if(! $request instanceof EE_Request) {
88
-                $request = LoaderFactory::getLoader()->getShared('EE_Request');
89
-            }
90
-            self::$_instance = new self($request);
91
-        }
92
-        return self::$_instance;
93
-    }
94
-
95
-
96
-    /**
97
-     * EE_Registration_Processor constructor.
98
-     *
99
-     * @param EE_Request $request
100
-     */
101
-    public function __construct(EE_Request $request)
102
-    {
103
-        $this->request = $request;
104
-    }
105
-
106
-
107
-
108
-    /**
109
-     * @param int $REG_ID
110
-     * @return string
111
-     */
112
-    public function old_reg_status($REG_ID)
113
-    {
114
-        return isset($this->_old_reg_status[$REG_ID]) ? $this->_old_reg_status[$REG_ID] : null;
115
-    }
116
-
117
-
118
-
119
-    /**
120
-     * @param int    $REG_ID
121
-     * @param string $old_reg_status
122
-     */
123
-    public function set_old_reg_status($REG_ID, $old_reg_status)
124
-    {
125
-        // only set the first time
126
-        if (! isset($this->_old_reg_status[$REG_ID])) {
127
-            $this->_old_reg_status[$REG_ID] = $old_reg_status;
128
-        }
129
-    }
130
-
131
-
132
-
133
-    /**
134
-     * @param int $REG_ID
135
-     * @return string
136
-     */
137
-    public function new_reg_status($REG_ID)
138
-    {
139
-        return isset($this->_new_reg_status[$REG_ID]) ? $this->_new_reg_status[$REG_ID] : null;
140
-    }
141
-
142
-
143
-
144
-    /**
145
-     * @param int    $REG_ID
146
-     * @param string $new_reg_status
147
-     */
148
-    public function set_new_reg_status($REG_ID, $new_reg_status)
149
-    {
150
-        $this->_new_reg_status[$REG_ID] = $new_reg_status;
151
-    }
152
-
153
-
154
-
155
-    /**
156
-     * reg_status_updated
157
-     *
158
-     * @param int $REG_ID
159
-     * @return bool
160
-     */
161
-    public function reg_status_updated($REG_ID)
162
-    {
163
-        return $this->new_reg_status($REG_ID) !== $this->old_reg_status($REG_ID);
164
-    }
165
-
166
-
167
-
168
-    /**
169
-     * @param EE_Registration $registration
170
-     * @throws EE_Error
171
-     * @throws EntityNotFoundException
172
-     * @throws InvalidArgumentException
173
-     * @throws InvalidDataTypeException
174
-     * @throws InvalidInterfaceException
175
-     * @throws ReflectionException
176
-     * @throws RuntimeException
177
-     */
178
-    public function update_registration_status_and_trigger_notifications(EE_Registration $registration)
179
-    {
180
-        $this->toggle_incomplete_registration_status_to_default($registration, false);
181
-        $this->toggle_registration_status_for_default_approved_events($registration, false);
182
-        $this->toggle_registration_status_if_no_monies_owing($registration, false);
183
-        $registration->save();
184
-        // trigger notifications
185
-        $this->trigger_registration_update_notifications($registration);
186
-    }
187
-
188
-
189
-
190
-    /**
191
-     *    manually_update_registration_status
192
-     *
193
-     * @access public
194
-     * @param EE_Registration $registration
195
-     * @param string          $new_reg_status
196
-     * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
197
-     *                              to client code
198
-     * @return bool
199
-     * @throws EE_Error
200
-     * @throws EntityNotFoundException
201
-     * @throws InvalidArgumentException
202
-     * @throws InvalidDataTypeException
203
-     * @throws InvalidInterfaceException
204
-     * @throws ReflectionException
205
-     * @throws RuntimeException
206
-     */
207
-    public function manually_update_registration_status(
208
-        EE_Registration $registration,
209
-        $new_reg_status = '',
210
-        $save = true
211
-    ) {
212
-        // set initial REG_Status
213
-        $this->set_old_reg_status($registration->ID(), $registration->status_ID());
214
-        // set incoming REG_Status
215
-        $this->set_new_reg_status($registration->ID(), $new_reg_status);
216
-        // toggle reg status but only if it has changed and the user can do so
217
-        if (
218
-            $this->reg_status_updated($registration->ID())
219
-            && (
220
-                (! $this->request->isAdmin() || $this->request->isFrontAjax())
221
-                || EE_Registry::instance()->CAP->current_user_can(
222
-                    'ee_edit_registration',
223
-                    'toggle_registration_status',
224
-                    $registration->ID()
225
-                )
226
-            )
227
-        ) {
228
-            // change status to new value
229
-            $updated = $registration->set_status($this->new_reg_status($registration->ID()));
230
-            if ($updated && $save) {
231
-                $registration->save();
232
-            }
233
-            return true;
234
-        }
235
-        return false;
236
-    }
237
-
238
-
239
-
240
-    /**
241
-     *    toggle_incomplete_registration_status_to_default
242
-     *        changes any incomplete registrations to either the event or global default registration status
243
-     *
244
-     * @access public
245
-     * @param EE_Registration $registration
246
-     * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
247
-     *                              to client code
248
-     * @param ContextInterface|null    $context
249
-     * @return void
250
-     * @throws EE_Error
251
-     * @throws InvalidArgumentException
252
-     * @throws ReflectionException
253
-     * @throws RuntimeException
254
-     * @throws EntityNotFoundException
255
-     * @throws InvalidDataTypeException
256
-     * @throws InvalidInterfaceException
257
-     */
258
-    public function toggle_incomplete_registration_status_to_default(
259
-        EE_Registration $registration,
260
-        $save = true,
261
-        ContextInterface $context = null
262
-    ) {
263
-        $existing_reg_status = $registration->status_ID();
264
-        // set initial REG_Status
265
-        $this->set_old_reg_status($registration->ID(), $existing_reg_status);
266
-        // is the registration currently incomplete ?
267
-        if ($registration->status_ID() === EEM_Registration::status_id_incomplete) {
268
-            // grab default reg status for the event, if set
269
-            $event_default_registration_status = $registration->event()->default_registration_status();
270
-            // if no default reg status is set for the event, then use the global value
271
-            $STS_ID = ! empty($event_default_registration_status)
272
-                ? $event_default_registration_status
273
-                : EE_Registry::instance()->CFG->registration->default_STS_ID;
274
-            // if the event default reg status is approved, then downgrade temporarily to payment pending to ensure that payments are triggered
275
-            $STS_ID = $STS_ID === EEM_Registration::status_id_approved ? EEM_Registration::status_id_pending_payment
276
-                : $STS_ID;
277
-            // set incoming REG_Status
278
-            $this->set_new_reg_status($registration->ID(), $STS_ID);
279
-            $registration->set_status($STS_ID, false, $context);
280
-            if ($save) {
281
-                $registration->save();
282
-            }
283
-            // don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
284
-            if (! EE_Processor_Base::$IPN) {
285
-                // otherwise, send out notifications
286
-                add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
287
-            }
288
-            // DEBUG LOG
289
-            //$this->log(
290
-            //	__CLASS__, __FUNCTION__, __LINE__,
291
-            //	$registration->transaction(),
292
-            //	array(
293
-            //		'IPN'                   => EE_Processor_Base::$IPN,
294
-            //		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
295
-            //	)
296
-            //);
297
-        }
298
-    }
299
-
300
-
301
-
302
-    /**
303
-     *    toggle_registration_status_for_default_approved_events
304
-     *
305
-     * @access public
306
-     * @param EE_Registration $registration
307
-     * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
308
-     *                              to client code
309
-     * @return bool
310
-     * @throws EE_Error
311
-     * @throws EntityNotFoundException
312
-     * @throws InvalidArgumentException
313
-     * @throws InvalidDataTypeException
314
-     * @throws InvalidInterfaceException
315
-     * @throws ReflectionException
316
-     * @throws RuntimeException
317
-     */
318
-    public function toggle_registration_status_for_default_approved_events(EE_Registration $registration, $save = true)
319
-    {
320
-        $reg_status = $registration->status_ID();
321
-        // set initial REG_Status
322
-        $this->set_old_reg_status($registration->ID(), $reg_status);
323
-        // if not already, toggle reg status to approved IF the event default reg status is approved
324
-        // ( as long as the registration wasn't cancelled or declined at some point )
325
-        if (
326
-            $reg_status !== EEM_Registration::status_id_cancelled
327
-            && $reg_status
328
-               !== EEM_Registration::status_id_declined
329
-            && $reg_status !== EEM_Registration::status_id_approved
330
-            && $registration->event()->default_registration_status() === EEM_Registration::status_id_approved
331
-        ) {
332
-            // set incoming REG_Status
333
-            $this->set_new_reg_status($registration->ID(), EEM_Registration::status_id_approved);
334
-            // toggle status to approved
335
-            $registration->set_status(EEM_Registration::status_id_approved);
336
-            if ($save) {
337
-                $registration->save();
338
-            }
339
-            // don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
340
-            if (! EE_Processor_Base::$IPN) {
341
-                // otherwise, send out notifications
342
-                add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
343
-            }
344
-            // DEBUG LOG
345
-            //$this->log(
346
-            //	__CLASS__, __FUNCTION__, __LINE__,
347
-            //	$registration->transaction(),
348
-            //	array(
349
-            //		'IPN'                   => EE_Processor_Base::$IPN,
350
-            //		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
351
-            //	)
352
-            //);
353
-            return true;
354
-        }
355
-        return false;
356
-    }
357
-
358
-
359
-
360
-    /**
361
-     *    toggle_registration_statuses_if_no_monies_owing
362
-     *
363
-     * @access public
364
-     * @param EE_Registration $registration
365
-     * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
366
-     *                              to client code
367
-     * @param array           $additional_details
368
-     * @return bool
369
-     * @throws EE_Error
370
-     * @throws EntityNotFoundException
371
-     * @throws InvalidArgumentException
372
-     * @throws InvalidDataTypeException
373
-     * @throws InvalidInterfaceException
374
-     * @throws ReflectionException
375
-     * @throws RuntimeException
376
-     */
377
-    public function toggle_registration_status_if_no_monies_owing(
378
-        EE_Registration $registration,
379
-        $save = true,
380
-        array $additional_details = array()
381
-    ) {
382
-        // set initial REG_Status
383
-        $this->set_old_reg_status($registration->ID(), $registration->status_ID());
384
-        // was a payment just made ?
385
-        $payment    = isset($additional_details['payment_updates'], $additional_details['last_payment'])
386
-                      && $additional_details['payment_updates']
387
-                      && $additional_details['last_payment'] instanceof EE_Payment
388
-            ? $additional_details['last_payment']
389
-            : null;
390
-        $total_paid = array_sum(self::$_amount_paid);
391
-        // toggle reg status to approved IF
392
-        if (
393
-            // REG status is pending payment
394
-            $registration->status_ID() === EEM_Registration::status_id_pending_payment
395
-            // AND no monies are owing
396
-            && (
397
-                (
398
-                    $registration->transaction()->is_completed()
399
-                    || $registration->transaction()->is_overpaid()
400
-                    || $registration->transaction()->is_free()
401
-                    || apply_filters(
402
-                        'FHEE__EE_Registration_Processor__toggle_registration_status_if_no_monies_owing',
403
-                        false,
404
-                        $registration
405
-                    )
406
-                )
407
-                || (
408
-                    $payment instanceof EE_Payment && $payment->is_approved()
409
-                    && // this specific registration has not yet been paid for
410
-                    ! isset(self::$_amount_paid[$registration->ID()])
411
-                    && // payment amount, less what we have already attributed to other registrations, is greater than this reg's final price
412
-                    $payment->amount() - $total_paid >= $registration->final_price()
413
-                )
414
-            )
415
-        ) {
416
-            // mark as paid
417
-            self::$_amount_paid[$registration->ID()] = $registration->final_price();
418
-            // track new REG_Status
419
-            $this->set_new_reg_status($registration->ID(), EEM_Registration::status_id_approved);
420
-            // toggle status to approved
421
-            $registration->set_status(EEM_Registration::status_id_approved);
422
-            if ($save) {
423
-                $registration->save();
424
-            }
425
-            // don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
426
-            if (! EE_Processor_Base::$IPN) {
427
-                // otherwise, send out notifications
428
-                add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
429
-            }
430
-            // DEBUG LOG
431
-            //$this->log(
432
-            //	__CLASS__, __FUNCTION__, __LINE__,
433
-            //	$registration->transaction(),
434
-            //	array(
435
-            //		'IPN'                   => EE_Processor_Base::$IPN,
436
-            //		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
437
-            //	)
438
-            //);
439
-            return true;
440
-        }
441
-        return false;
442
-    }
443
-
444
-
445
-
446
-    /**
447
-     *    registration_status_changed
448
-     *
449
-     * @access public
450
-     * @param EE_Registration $registration
451
-     * @param array           $additional_details
452
-     * @return void
453
-     */
454
-    public function trigger_registration_update_notifications($registration, array $additional_details = array())
455
-    {
456
-        try {
457
-            if (! $registration instanceof EE_Registration) {
458
-                throw new EE_Error(
459
-                    esc_html__('An invalid registration was received.', 'event_espresso')
460
-                );
461
-            }
462
-            // EE_Registry::instance()->load_helper( 'Debug_Tools' );
463
-            // EEH_Debug_Tools::log(
464
-            // 	__CLASS__,
465
-            // 	__FUNCTION__,
466
-            // 	__LINE__,
467
-            // 	array( $registration->transaction(), $additional_details ),
468
-            // 	false,
469
-            // 	'EE_Transaction: ' . $registration->transaction()->ID()
470
-            // );
471
-            if (! $registration->is_primary_registrant()) {
472
-                return;
473
-            }
474
-            do_action(
475
-                'AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
476
-                $registration,
477
-                $additional_details
478
-            );
479
-        } catch (Exception $e) {
480
-            EE_Error::add_error($e->getMessage(), $e->getFile(), 'unknown_function_from_exception', $e->getLine());
481
-        }
482
-    }
483
-
484
-
485
-
486
-    /**
487
-     * sets reg status based either on passed param or on transaction status and event pre-approval setting
488
-     *
489
-     * @param EE_Registration $registration
490
-     * @param array           $additional_details
491
-     * @return bool
492
-     * @throws EE_Error
493
-     * @throws EntityNotFoundException
494
-     * @throws InvalidArgumentException
495
-     * @throws InvalidDataTypeException
496
-     * @throws InvalidInterfaceException
497
-     * @throws ReflectionException
498
-     * @throws RuntimeException
499
-     */
500
-    public function update_registration_after_checkout_or_payment(
501
-        EE_Registration $registration,
502
-        array $additional_details = array()
503
-    ) {
504
-        // set initial REG_Status
505
-        $this->set_old_reg_status($registration->ID(), $registration->status_ID());
506
-        // if the registration status gets updated, then save the registration
507
-        if (
508
-            $this->toggle_registration_status_for_default_approved_events($registration, false)
509
-            || $this->toggle_registration_status_if_no_monies_owing(
510
-                $registration,
511
-                false,
512
-                $additional_details
513
-            )
514
-        ) {
515
-            $registration->save();
516
-        }
517
-        // set new  REG_Status
518
-        $this->set_new_reg_status($registration->ID(), $registration->status_ID());
519
-        return $this->reg_status_updated($registration->ID())
520
-               && $this->new_reg_status($registration->ID()) === EEM_Registration::status_id_approved;
521
-    }
522
-
523
-
524
-
525
-    /**
526
-     * Updates the registration' final prices based on the current line item tree (taking into account
527
-     * discounts, taxes, and other line items unrelated to tickets.)
528
-     *
529
-     * @param EE_Transaction $transaction
530
-     * @param boolean        $save_regs whether to immediately save registrations in this function or not
531
-     * @return void
532
-     * @throws EE_Error
533
-     * @throws InvalidArgumentException
534
-     * @throws InvalidDataTypeException
535
-     * @throws InvalidInterfaceException
536
-     * @throws RuntimeException
537
-     */
538
-    public function update_registration_final_prices($transaction, $save_regs = true)
539
-    {
540
-        $reg_final_price_per_ticket_line_item = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
541
-            $transaction->total_line_item()
542
-        );
543
-        foreach ($transaction->registrations() as $registration) {
544
-            /** @var EE_Line_Item $line_item */
545
-            $line_item = EEM_Line_Item::instance()->get_line_item_for_registration($registration);
546
-            if (isset($reg_final_price_per_ticket_line_item[$line_item->ID()])) {
547
-                $registration->set_final_price($reg_final_price_per_ticket_line_item[$line_item->ID()]);
548
-                if ($save_regs) {
549
-                    $registration->save();
550
-                }
551
-            }
552
-        }
553
-        //and make sure there's no rounding problem
554
-        $this->fix_reg_final_price_rounding_issue($transaction);
555
-    }
556
-
557
-
558
-
559
-    /**
560
-     * Makes sure there is no rounding errors for the REG_final_prices.
561
-     * Eg, if we have 3 registrations for $1, and there is a $0.01 discount between the three of them,
562
-     * they will each be for $0.99333333, which gets rounded to $1 again.
563
-     * So the transaction total will be $2.99, but each registration will be for $1,
564
-     * so if each registrant paid individually they will have overpaid by $0.01.
565
-     * So in order to overcome this, we check for any difference, and if there is a difference
566
-     * we just grab one registrant at random and make them responsible for it.
567
-     * This should be used after setting REG_final_prices (it's done automatically as part of
568
-     * EE_Registration_Processor::update_registration_final_prices())
569
-     *
570
-     * @param EE_Transaction $transaction
571
-     * @return bool success verifying that there is NO difference after this method is done
572
-     * @throws EE_Error
573
-     * @throws InvalidArgumentException
574
-     * @throws InvalidDataTypeException
575
-     * @throws InvalidInterfaceException
576
-     */
577
-    public function fix_reg_final_price_rounding_issue($transaction)
578
-    {
579
-        $reg_final_price_sum = EEM_Registration::instance()->sum(
580
-            array(
581
-                array(
582
-                    'TXN_ID' => $transaction->ID(),
583
-                ),
584
-            ),
585
-            'REG_final_price'
586
-        );
587
-        $diff = $transaction->total() - $reg_final_price_sum;
588
-        //ok then, just grab one of the registrations
589
-        if ($diff !== 0) {
590
-            $a_reg   = EEM_Registration::instance()->get_one(
591
-                array(
592
-                    array(
593
-                        'TXN_ID' => $transaction->ID(),
594
-                    ),
595
-                )
596
-            );
597
-            return $a_reg instanceof EE_Registration
598
-                ? (bool) $a_reg->save(array('REG_final_price' => $a_reg->final_price() + $diff))
599
-                : false;
600
-        }
601
-        return true;
602
-    }
603
-
604
-
605
-
606
-    /**
607
-     * update_registration_after_being_canceled_or_declined
608
-     *
609
-     * @param EE_Registration $registration
610
-     * @param array           $closed_reg_statuses
611
-     * @param bool            $update_reg
612
-     * @return bool
613
-     * @throws EE_Error
614
-     * @throws RuntimeException
615
-     */
616
-    public function update_registration_after_being_canceled_or_declined(
617
-        EE_Registration $registration,
618
-        array $closed_reg_statuses = array(),
619
-        $update_reg = true
620
-    ) {
621
-        // these reg statuses should not be considered in any calculations involving monies owing
622
-        $closed_reg_statuses = ! empty($closed_reg_statuses)
623
-            ? $closed_reg_statuses
624
-            : EEM_Registration::closed_reg_statuses();
625
-        if (! in_array($registration->status_ID(), $closed_reg_statuses, true)) {
626
-            return false;
627
-        }
628
-        // release a reserved ticket by decrementing ticket and datetime reserved values
629
-        $registration->release_reserved_ticket(true);
630
-        $registration->set_final_price(0);
631
-        if ($update_reg) {
632
-            $registration->save();
633
-        }
634
-        return true;
635
-    }
636
-
637
-
638
-
639
-    /**
640
-     * update_canceled_or_declined_registration_after_being_reinstated
641
-     *
642
-     * @param EE_Registration $registration
643
-     * @param array           $closed_reg_statuses
644
-     * @param bool            $update_reg
645
-     * @return bool
646
-     * @throws EE_Error
647
-     * @throws RuntimeException
648
-     */
649
-    public function update_canceled_or_declined_registration_after_being_reinstated(
650
-        EE_Registration $registration,
651
-        array $closed_reg_statuses = array(),
652
-        $update_reg = true
653
-    ) {
654
-        // these reg statuses should not be considered in any calculations involving monies owing
655
-        $closed_reg_statuses = ! empty($closed_reg_statuses) ? $closed_reg_statuses
656
-            : EEM_Registration::closed_reg_statuses();
657
-        if (in_array($registration->status_ID(), $closed_reg_statuses, true)) {
658
-            return false;
659
-        }
660
-        $ticket = $registration->ticket();
661
-        if (! $ticket instanceof EE_Ticket) {
662
-            throw new EE_Error(
663
-                sprintf(
664
-                    esc_html__(
665
-                        'The Ticket for Registration %1$d was not found or is invalid.',
666
-                        'event_espresso'
667
-                    ),
668
-                    $registration->ticket_ID()
669
-                )
670
-            );
671
-        }
672
-        $registration->set_final_price($ticket->price());
673
-        if ($update_reg) {
674
-            $registration->save();
675
-        }
676
-        return true;
677
-    }
678
-
679
-
680
-
681
-    /**
682
-     * generate_ONE_registration_from_line_item
683
-     * Although a ticket line item may have a quantity greater than 1,
684
-     * this method will ONLY CREATE ONE REGISTRATION !!!
685
-     * Regardless of the ticket line item quantity.
686
-     * This means that any code calling this method is responsible for ensuring
687
-     * that the final registration count matches the ticket line item quantity.
688
-     * This was done to make it easier to match the number of registrations
689
-     * to the number of tickets in the cart, when the cart has been edited
690
-     * after SPCO has already been initialized. So if an additional ticket was added to the cart, you can simply pass
691
-     * the line item to this method to add a second ticket, and in this case, you would not want to add 2 tickets.
692
-     *
693
-     * @deprecated
694
-     * @since 4.9.1
695
-     * @param EE_Line_Item    $line_item
696
-     * @param \EE_Transaction $transaction
697
-     * @param int             $att_nmbr
698
-     * @param int             $total_ticket_count
699
-     * @return EE_Registration | null
700
-     * @throws \OutOfRangeException
701
-     * @throws \EventEspresso\core\exceptions\UnexpectedEntityException
702
-     * @throws \EE_Error
703
-     */
704
-    public function generate_ONE_registration_from_line_item(
705
-        EE_Line_Item $line_item,
706
-        EE_Transaction $transaction,
707
-        $att_nmbr = 1,
708
-        $total_ticket_count = 1
709
-    ) {
710
-        EE_Error::doing_it_wrong(
711
-            __CLASS__ . '::' . __FUNCTION__,
712
-            sprintf(
713
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
714
-                '\EventEspresso\core\domain\services\registration\CreateRegistrationService::create()'
715
-            ),
716
-            '4.9.1',
717
-            '5.0.0'
718
-        );
719
-        // grab the related ticket object for this line_item
720
-        $ticket = $line_item->ticket();
721
-        if (! $ticket instanceof EE_Ticket) {
722
-            EE_Error::add_error(
723
-                sprintf(
724
-                    esc_html__('Line item %s did not contain a valid ticket', 'event_espresso'),
725
-                    $line_item->ID()
726
-                ),
727
-                __FILE__,
728
-                __FUNCTION__,
729
-                __LINE__
730
-            );
731
-            return null;
732
-        }
733
-        $registration_service = new CreateRegistrationService();
734
-        // then generate a new registration from that
735
-        return $registration_service->create(
736
-            $ticket->get_related_event(),
737
-            $transaction,
738
-            $ticket,
739
-            $line_item,
740
-            $att_nmbr,
741
-            $total_ticket_count
742
-        );
743
-    }
744
-
745
-
746
-
747
-    /**
748
-     * generates reg_url_link
749
-     *
750
-     * @deprecated
751
-     * @since 4.9.1
752
-     * @param int                   $att_nmbr
753
-     * @param EE_Line_Item | string $item
754
-     * @return string
755
-     * @throws InvalidArgumentException
756
-     */
757
-    public function generate_reg_url_link($att_nmbr, $item)
758
-    {
759
-        EE_Error::doing_it_wrong(
760
-            __CLASS__ . '::' . __FUNCTION__,
761
-            sprintf(
762
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
763
-                'EventEspresso\core\domain\entities\RegUrlLink'
764
-            ),
765
-            '4.9.1',
766
-            '5.0.0'
767
-        );
768
-        return new RegUrlLink($att_nmbr, $item);
769
-    }
770
-
771
-
772
-
773
-    /**
774
-     * generates reg code
775
-     *
776
-     * @deprecated
777
-     * @since 4.9.1
778
-     * @param EE_Registration $registration
779
-     * @return string
780
-     * @throws EE_Error
781
-     * @throws EntityNotFoundException
782
-     * @throws InvalidArgumentException
783
-     */
784
-    public function generate_reg_code(EE_Registration $registration)
785
-    {
786
-        EE_Error::doing_it_wrong(
787
-            __CLASS__ . '::' . __FUNCTION__,
788
-            sprintf(
789
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
790
-                'EventEspresso\core\domain\entities\RegCode'
791
-            ),
792
-            '4.9.1',
793
-            '5.0.0'
794
-        );
795
-        return apply_filters(
796
-            'FHEE__EE_Registration_Processor___generate_reg_code__new_reg_code',
797
-            new RegCode(
798
-                RegUrlLink::fromRegistration($registration),
799
-                $registration->transaction(),
800
-                $registration->ticket()
801
-            ),
802
-            $registration
803
-        );
804
-    }
30
+	/**
31
+	 * @var EE_Registration_Processor $_instance
32
+	 * @access    private
33
+	 */
34
+	private static $_instance;
35
+
36
+	/**
37
+	 * initial reg status at the beginning of this request.
38
+	 * indexed by registration ID
39
+	 *
40
+	 * @var array
41
+	 */
42
+	protected $_old_reg_status = array();
43
+
44
+	/**
45
+	 * reg status at the end of the request after all processing.
46
+	 * indexed by registration ID
47
+	 *
48
+	 * @var array
49
+	 */
50
+	protected $_new_reg_status = array();
51
+
52
+	/**
53
+	 * amounts paid at the end of the request after all processing.
54
+	 * indexed by registration ID
55
+	 *
56
+	 * @var array
57
+	 */
58
+	protected static $_amount_paid = array();
59
+
60
+	/**
61
+	 * Cache of the reg final price for registrations corresponding to a ticket line item
62
+	 *
63
+	 * @deprecated
64
+	 * @var array @see EEH_Line_Item::calculate_reg_final_prices_per_line_item()'s return value
65
+	 */
66
+	protected $_reg_final_price_per_tkt_line_item;
67
+
68
+	/**
69
+	 * @var EE_Request $request
70
+	 */
71
+	protected $request;
72
+
73
+
74
+
75
+	/**
76
+	 * @singleton method used to instantiate class object
77
+	 * @param EE_Request|null $request
78
+	 * @return EE_Registration_Processor instance
79
+	 * @throws \InvalidArgumentException
80
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
81
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
82
+	 */
83
+	public static function instance(EE_Request $request = null)
84
+	{
85
+		// check if class object is instantiated
86
+		if (! self::$_instance instanceof EE_Registration_Processor) {
87
+			if(! $request instanceof EE_Request) {
88
+				$request = LoaderFactory::getLoader()->getShared('EE_Request');
89
+			}
90
+			self::$_instance = new self($request);
91
+		}
92
+		return self::$_instance;
93
+	}
94
+
95
+
96
+	/**
97
+	 * EE_Registration_Processor constructor.
98
+	 *
99
+	 * @param EE_Request $request
100
+	 */
101
+	public function __construct(EE_Request $request)
102
+	{
103
+		$this->request = $request;
104
+	}
105
+
106
+
107
+
108
+	/**
109
+	 * @param int $REG_ID
110
+	 * @return string
111
+	 */
112
+	public function old_reg_status($REG_ID)
113
+	{
114
+		return isset($this->_old_reg_status[$REG_ID]) ? $this->_old_reg_status[$REG_ID] : null;
115
+	}
116
+
117
+
118
+
119
+	/**
120
+	 * @param int    $REG_ID
121
+	 * @param string $old_reg_status
122
+	 */
123
+	public function set_old_reg_status($REG_ID, $old_reg_status)
124
+	{
125
+		// only set the first time
126
+		if (! isset($this->_old_reg_status[$REG_ID])) {
127
+			$this->_old_reg_status[$REG_ID] = $old_reg_status;
128
+		}
129
+	}
130
+
131
+
132
+
133
+	/**
134
+	 * @param int $REG_ID
135
+	 * @return string
136
+	 */
137
+	public function new_reg_status($REG_ID)
138
+	{
139
+		return isset($this->_new_reg_status[$REG_ID]) ? $this->_new_reg_status[$REG_ID] : null;
140
+	}
141
+
142
+
143
+
144
+	/**
145
+	 * @param int    $REG_ID
146
+	 * @param string $new_reg_status
147
+	 */
148
+	public function set_new_reg_status($REG_ID, $new_reg_status)
149
+	{
150
+		$this->_new_reg_status[$REG_ID] = $new_reg_status;
151
+	}
152
+
153
+
154
+
155
+	/**
156
+	 * reg_status_updated
157
+	 *
158
+	 * @param int $REG_ID
159
+	 * @return bool
160
+	 */
161
+	public function reg_status_updated($REG_ID)
162
+	{
163
+		return $this->new_reg_status($REG_ID) !== $this->old_reg_status($REG_ID);
164
+	}
165
+
166
+
167
+
168
+	/**
169
+	 * @param EE_Registration $registration
170
+	 * @throws EE_Error
171
+	 * @throws EntityNotFoundException
172
+	 * @throws InvalidArgumentException
173
+	 * @throws InvalidDataTypeException
174
+	 * @throws InvalidInterfaceException
175
+	 * @throws ReflectionException
176
+	 * @throws RuntimeException
177
+	 */
178
+	public function update_registration_status_and_trigger_notifications(EE_Registration $registration)
179
+	{
180
+		$this->toggle_incomplete_registration_status_to_default($registration, false);
181
+		$this->toggle_registration_status_for_default_approved_events($registration, false);
182
+		$this->toggle_registration_status_if_no_monies_owing($registration, false);
183
+		$registration->save();
184
+		// trigger notifications
185
+		$this->trigger_registration_update_notifications($registration);
186
+	}
187
+
188
+
189
+
190
+	/**
191
+	 *    manually_update_registration_status
192
+	 *
193
+	 * @access public
194
+	 * @param EE_Registration $registration
195
+	 * @param string          $new_reg_status
196
+	 * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
197
+	 *                              to client code
198
+	 * @return bool
199
+	 * @throws EE_Error
200
+	 * @throws EntityNotFoundException
201
+	 * @throws InvalidArgumentException
202
+	 * @throws InvalidDataTypeException
203
+	 * @throws InvalidInterfaceException
204
+	 * @throws ReflectionException
205
+	 * @throws RuntimeException
206
+	 */
207
+	public function manually_update_registration_status(
208
+		EE_Registration $registration,
209
+		$new_reg_status = '',
210
+		$save = true
211
+	) {
212
+		// set initial REG_Status
213
+		$this->set_old_reg_status($registration->ID(), $registration->status_ID());
214
+		// set incoming REG_Status
215
+		$this->set_new_reg_status($registration->ID(), $new_reg_status);
216
+		// toggle reg status but only if it has changed and the user can do so
217
+		if (
218
+			$this->reg_status_updated($registration->ID())
219
+			&& (
220
+				(! $this->request->isAdmin() || $this->request->isFrontAjax())
221
+				|| EE_Registry::instance()->CAP->current_user_can(
222
+					'ee_edit_registration',
223
+					'toggle_registration_status',
224
+					$registration->ID()
225
+				)
226
+			)
227
+		) {
228
+			// change status to new value
229
+			$updated = $registration->set_status($this->new_reg_status($registration->ID()));
230
+			if ($updated && $save) {
231
+				$registration->save();
232
+			}
233
+			return true;
234
+		}
235
+		return false;
236
+	}
237
+
238
+
239
+
240
+	/**
241
+	 *    toggle_incomplete_registration_status_to_default
242
+	 *        changes any incomplete registrations to either the event or global default registration status
243
+	 *
244
+	 * @access public
245
+	 * @param EE_Registration $registration
246
+	 * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
247
+	 *                              to client code
248
+	 * @param ContextInterface|null    $context
249
+	 * @return void
250
+	 * @throws EE_Error
251
+	 * @throws InvalidArgumentException
252
+	 * @throws ReflectionException
253
+	 * @throws RuntimeException
254
+	 * @throws EntityNotFoundException
255
+	 * @throws InvalidDataTypeException
256
+	 * @throws InvalidInterfaceException
257
+	 */
258
+	public function toggle_incomplete_registration_status_to_default(
259
+		EE_Registration $registration,
260
+		$save = true,
261
+		ContextInterface $context = null
262
+	) {
263
+		$existing_reg_status = $registration->status_ID();
264
+		// set initial REG_Status
265
+		$this->set_old_reg_status($registration->ID(), $existing_reg_status);
266
+		// is the registration currently incomplete ?
267
+		if ($registration->status_ID() === EEM_Registration::status_id_incomplete) {
268
+			// grab default reg status for the event, if set
269
+			$event_default_registration_status = $registration->event()->default_registration_status();
270
+			// if no default reg status is set for the event, then use the global value
271
+			$STS_ID = ! empty($event_default_registration_status)
272
+				? $event_default_registration_status
273
+				: EE_Registry::instance()->CFG->registration->default_STS_ID;
274
+			// if the event default reg status is approved, then downgrade temporarily to payment pending to ensure that payments are triggered
275
+			$STS_ID = $STS_ID === EEM_Registration::status_id_approved ? EEM_Registration::status_id_pending_payment
276
+				: $STS_ID;
277
+			// set incoming REG_Status
278
+			$this->set_new_reg_status($registration->ID(), $STS_ID);
279
+			$registration->set_status($STS_ID, false, $context);
280
+			if ($save) {
281
+				$registration->save();
282
+			}
283
+			// don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
284
+			if (! EE_Processor_Base::$IPN) {
285
+				// otherwise, send out notifications
286
+				add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
287
+			}
288
+			// DEBUG LOG
289
+			//$this->log(
290
+			//	__CLASS__, __FUNCTION__, __LINE__,
291
+			//	$registration->transaction(),
292
+			//	array(
293
+			//		'IPN'                   => EE_Processor_Base::$IPN,
294
+			//		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
295
+			//	)
296
+			//);
297
+		}
298
+	}
299
+
300
+
301
+
302
+	/**
303
+	 *    toggle_registration_status_for_default_approved_events
304
+	 *
305
+	 * @access public
306
+	 * @param EE_Registration $registration
307
+	 * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
308
+	 *                              to client code
309
+	 * @return bool
310
+	 * @throws EE_Error
311
+	 * @throws EntityNotFoundException
312
+	 * @throws InvalidArgumentException
313
+	 * @throws InvalidDataTypeException
314
+	 * @throws InvalidInterfaceException
315
+	 * @throws ReflectionException
316
+	 * @throws RuntimeException
317
+	 */
318
+	public function toggle_registration_status_for_default_approved_events(EE_Registration $registration, $save = true)
319
+	{
320
+		$reg_status = $registration->status_ID();
321
+		// set initial REG_Status
322
+		$this->set_old_reg_status($registration->ID(), $reg_status);
323
+		// if not already, toggle reg status to approved IF the event default reg status is approved
324
+		// ( as long as the registration wasn't cancelled or declined at some point )
325
+		if (
326
+			$reg_status !== EEM_Registration::status_id_cancelled
327
+			&& $reg_status
328
+			   !== EEM_Registration::status_id_declined
329
+			&& $reg_status !== EEM_Registration::status_id_approved
330
+			&& $registration->event()->default_registration_status() === EEM_Registration::status_id_approved
331
+		) {
332
+			// set incoming REG_Status
333
+			$this->set_new_reg_status($registration->ID(), EEM_Registration::status_id_approved);
334
+			// toggle status to approved
335
+			$registration->set_status(EEM_Registration::status_id_approved);
336
+			if ($save) {
337
+				$registration->save();
338
+			}
339
+			// don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
340
+			if (! EE_Processor_Base::$IPN) {
341
+				// otherwise, send out notifications
342
+				add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
343
+			}
344
+			// DEBUG LOG
345
+			//$this->log(
346
+			//	__CLASS__, __FUNCTION__, __LINE__,
347
+			//	$registration->transaction(),
348
+			//	array(
349
+			//		'IPN'                   => EE_Processor_Base::$IPN,
350
+			//		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
351
+			//	)
352
+			//);
353
+			return true;
354
+		}
355
+		return false;
356
+	}
357
+
358
+
359
+
360
+	/**
361
+	 *    toggle_registration_statuses_if_no_monies_owing
362
+	 *
363
+	 * @access public
364
+	 * @param EE_Registration $registration
365
+	 * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
366
+	 *                              to client code
367
+	 * @param array           $additional_details
368
+	 * @return bool
369
+	 * @throws EE_Error
370
+	 * @throws EntityNotFoundException
371
+	 * @throws InvalidArgumentException
372
+	 * @throws InvalidDataTypeException
373
+	 * @throws InvalidInterfaceException
374
+	 * @throws ReflectionException
375
+	 * @throws RuntimeException
376
+	 */
377
+	public function toggle_registration_status_if_no_monies_owing(
378
+		EE_Registration $registration,
379
+		$save = true,
380
+		array $additional_details = array()
381
+	) {
382
+		// set initial REG_Status
383
+		$this->set_old_reg_status($registration->ID(), $registration->status_ID());
384
+		// was a payment just made ?
385
+		$payment    = isset($additional_details['payment_updates'], $additional_details['last_payment'])
386
+					  && $additional_details['payment_updates']
387
+					  && $additional_details['last_payment'] instanceof EE_Payment
388
+			? $additional_details['last_payment']
389
+			: null;
390
+		$total_paid = array_sum(self::$_amount_paid);
391
+		// toggle reg status to approved IF
392
+		if (
393
+			// REG status is pending payment
394
+			$registration->status_ID() === EEM_Registration::status_id_pending_payment
395
+			// AND no monies are owing
396
+			&& (
397
+				(
398
+					$registration->transaction()->is_completed()
399
+					|| $registration->transaction()->is_overpaid()
400
+					|| $registration->transaction()->is_free()
401
+					|| apply_filters(
402
+						'FHEE__EE_Registration_Processor__toggle_registration_status_if_no_monies_owing',
403
+						false,
404
+						$registration
405
+					)
406
+				)
407
+				|| (
408
+					$payment instanceof EE_Payment && $payment->is_approved()
409
+					&& // this specific registration has not yet been paid for
410
+					! isset(self::$_amount_paid[$registration->ID()])
411
+					&& // payment amount, less what we have already attributed to other registrations, is greater than this reg's final price
412
+					$payment->amount() - $total_paid >= $registration->final_price()
413
+				)
414
+			)
415
+		) {
416
+			// mark as paid
417
+			self::$_amount_paid[$registration->ID()] = $registration->final_price();
418
+			// track new REG_Status
419
+			$this->set_new_reg_status($registration->ID(), EEM_Registration::status_id_approved);
420
+			// toggle status to approved
421
+			$registration->set_status(EEM_Registration::status_id_approved);
422
+			if ($save) {
423
+				$registration->save();
424
+			}
425
+			// don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
426
+			if (! EE_Processor_Base::$IPN) {
427
+				// otherwise, send out notifications
428
+				add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
429
+			}
430
+			// DEBUG LOG
431
+			//$this->log(
432
+			//	__CLASS__, __FUNCTION__, __LINE__,
433
+			//	$registration->transaction(),
434
+			//	array(
435
+			//		'IPN'                   => EE_Processor_Base::$IPN,
436
+			//		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
437
+			//	)
438
+			//);
439
+			return true;
440
+		}
441
+		return false;
442
+	}
443
+
444
+
445
+
446
+	/**
447
+	 *    registration_status_changed
448
+	 *
449
+	 * @access public
450
+	 * @param EE_Registration $registration
451
+	 * @param array           $additional_details
452
+	 * @return void
453
+	 */
454
+	public function trigger_registration_update_notifications($registration, array $additional_details = array())
455
+	{
456
+		try {
457
+			if (! $registration instanceof EE_Registration) {
458
+				throw new EE_Error(
459
+					esc_html__('An invalid registration was received.', 'event_espresso')
460
+				);
461
+			}
462
+			// EE_Registry::instance()->load_helper( 'Debug_Tools' );
463
+			// EEH_Debug_Tools::log(
464
+			// 	__CLASS__,
465
+			// 	__FUNCTION__,
466
+			// 	__LINE__,
467
+			// 	array( $registration->transaction(), $additional_details ),
468
+			// 	false,
469
+			// 	'EE_Transaction: ' . $registration->transaction()->ID()
470
+			// );
471
+			if (! $registration->is_primary_registrant()) {
472
+				return;
473
+			}
474
+			do_action(
475
+				'AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
476
+				$registration,
477
+				$additional_details
478
+			);
479
+		} catch (Exception $e) {
480
+			EE_Error::add_error($e->getMessage(), $e->getFile(), 'unknown_function_from_exception', $e->getLine());
481
+		}
482
+	}
483
+
484
+
485
+
486
+	/**
487
+	 * sets reg status based either on passed param or on transaction status and event pre-approval setting
488
+	 *
489
+	 * @param EE_Registration $registration
490
+	 * @param array           $additional_details
491
+	 * @return bool
492
+	 * @throws EE_Error
493
+	 * @throws EntityNotFoundException
494
+	 * @throws InvalidArgumentException
495
+	 * @throws InvalidDataTypeException
496
+	 * @throws InvalidInterfaceException
497
+	 * @throws ReflectionException
498
+	 * @throws RuntimeException
499
+	 */
500
+	public function update_registration_after_checkout_or_payment(
501
+		EE_Registration $registration,
502
+		array $additional_details = array()
503
+	) {
504
+		// set initial REG_Status
505
+		$this->set_old_reg_status($registration->ID(), $registration->status_ID());
506
+		// if the registration status gets updated, then save the registration
507
+		if (
508
+			$this->toggle_registration_status_for_default_approved_events($registration, false)
509
+			|| $this->toggle_registration_status_if_no_monies_owing(
510
+				$registration,
511
+				false,
512
+				$additional_details
513
+			)
514
+		) {
515
+			$registration->save();
516
+		}
517
+		// set new  REG_Status
518
+		$this->set_new_reg_status($registration->ID(), $registration->status_ID());
519
+		return $this->reg_status_updated($registration->ID())
520
+			   && $this->new_reg_status($registration->ID()) === EEM_Registration::status_id_approved;
521
+	}
522
+
523
+
524
+
525
+	/**
526
+	 * Updates the registration' final prices based on the current line item tree (taking into account
527
+	 * discounts, taxes, and other line items unrelated to tickets.)
528
+	 *
529
+	 * @param EE_Transaction $transaction
530
+	 * @param boolean        $save_regs whether to immediately save registrations in this function or not
531
+	 * @return void
532
+	 * @throws EE_Error
533
+	 * @throws InvalidArgumentException
534
+	 * @throws InvalidDataTypeException
535
+	 * @throws InvalidInterfaceException
536
+	 * @throws RuntimeException
537
+	 */
538
+	public function update_registration_final_prices($transaction, $save_regs = true)
539
+	{
540
+		$reg_final_price_per_ticket_line_item = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
541
+			$transaction->total_line_item()
542
+		);
543
+		foreach ($transaction->registrations() as $registration) {
544
+			/** @var EE_Line_Item $line_item */
545
+			$line_item = EEM_Line_Item::instance()->get_line_item_for_registration($registration);
546
+			if (isset($reg_final_price_per_ticket_line_item[$line_item->ID()])) {
547
+				$registration->set_final_price($reg_final_price_per_ticket_line_item[$line_item->ID()]);
548
+				if ($save_regs) {
549
+					$registration->save();
550
+				}
551
+			}
552
+		}
553
+		//and make sure there's no rounding problem
554
+		$this->fix_reg_final_price_rounding_issue($transaction);
555
+	}
556
+
557
+
558
+
559
+	/**
560
+	 * Makes sure there is no rounding errors for the REG_final_prices.
561
+	 * Eg, if we have 3 registrations for $1, and there is a $0.01 discount between the three of them,
562
+	 * they will each be for $0.99333333, which gets rounded to $1 again.
563
+	 * So the transaction total will be $2.99, but each registration will be for $1,
564
+	 * so if each registrant paid individually they will have overpaid by $0.01.
565
+	 * So in order to overcome this, we check for any difference, and if there is a difference
566
+	 * we just grab one registrant at random and make them responsible for it.
567
+	 * This should be used after setting REG_final_prices (it's done automatically as part of
568
+	 * EE_Registration_Processor::update_registration_final_prices())
569
+	 *
570
+	 * @param EE_Transaction $transaction
571
+	 * @return bool success verifying that there is NO difference after this method is done
572
+	 * @throws EE_Error
573
+	 * @throws InvalidArgumentException
574
+	 * @throws InvalidDataTypeException
575
+	 * @throws InvalidInterfaceException
576
+	 */
577
+	public function fix_reg_final_price_rounding_issue($transaction)
578
+	{
579
+		$reg_final_price_sum = EEM_Registration::instance()->sum(
580
+			array(
581
+				array(
582
+					'TXN_ID' => $transaction->ID(),
583
+				),
584
+			),
585
+			'REG_final_price'
586
+		);
587
+		$diff = $transaction->total() - $reg_final_price_sum;
588
+		//ok then, just grab one of the registrations
589
+		if ($diff !== 0) {
590
+			$a_reg   = EEM_Registration::instance()->get_one(
591
+				array(
592
+					array(
593
+						'TXN_ID' => $transaction->ID(),
594
+					),
595
+				)
596
+			);
597
+			return $a_reg instanceof EE_Registration
598
+				? (bool) $a_reg->save(array('REG_final_price' => $a_reg->final_price() + $diff))
599
+				: false;
600
+		}
601
+		return true;
602
+	}
603
+
604
+
605
+
606
+	/**
607
+	 * update_registration_after_being_canceled_or_declined
608
+	 *
609
+	 * @param EE_Registration $registration
610
+	 * @param array           $closed_reg_statuses
611
+	 * @param bool            $update_reg
612
+	 * @return bool
613
+	 * @throws EE_Error
614
+	 * @throws RuntimeException
615
+	 */
616
+	public function update_registration_after_being_canceled_or_declined(
617
+		EE_Registration $registration,
618
+		array $closed_reg_statuses = array(),
619
+		$update_reg = true
620
+	) {
621
+		// these reg statuses should not be considered in any calculations involving monies owing
622
+		$closed_reg_statuses = ! empty($closed_reg_statuses)
623
+			? $closed_reg_statuses
624
+			: EEM_Registration::closed_reg_statuses();
625
+		if (! in_array($registration->status_ID(), $closed_reg_statuses, true)) {
626
+			return false;
627
+		}
628
+		// release a reserved ticket by decrementing ticket and datetime reserved values
629
+		$registration->release_reserved_ticket(true);
630
+		$registration->set_final_price(0);
631
+		if ($update_reg) {
632
+			$registration->save();
633
+		}
634
+		return true;
635
+	}
636
+
637
+
638
+
639
+	/**
640
+	 * update_canceled_or_declined_registration_after_being_reinstated
641
+	 *
642
+	 * @param EE_Registration $registration
643
+	 * @param array           $closed_reg_statuses
644
+	 * @param bool            $update_reg
645
+	 * @return bool
646
+	 * @throws EE_Error
647
+	 * @throws RuntimeException
648
+	 */
649
+	public function update_canceled_or_declined_registration_after_being_reinstated(
650
+		EE_Registration $registration,
651
+		array $closed_reg_statuses = array(),
652
+		$update_reg = true
653
+	) {
654
+		// these reg statuses should not be considered in any calculations involving monies owing
655
+		$closed_reg_statuses = ! empty($closed_reg_statuses) ? $closed_reg_statuses
656
+			: EEM_Registration::closed_reg_statuses();
657
+		if (in_array($registration->status_ID(), $closed_reg_statuses, true)) {
658
+			return false;
659
+		}
660
+		$ticket = $registration->ticket();
661
+		if (! $ticket instanceof EE_Ticket) {
662
+			throw new EE_Error(
663
+				sprintf(
664
+					esc_html__(
665
+						'The Ticket for Registration %1$d was not found or is invalid.',
666
+						'event_espresso'
667
+					),
668
+					$registration->ticket_ID()
669
+				)
670
+			);
671
+		}
672
+		$registration->set_final_price($ticket->price());
673
+		if ($update_reg) {
674
+			$registration->save();
675
+		}
676
+		return true;
677
+	}
678
+
679
+
680
+
681
+	/**
682
+	 * generate_ONE_registration_from_line_item
683
+	 * Although a ticket line item may have a quantity greater than 1,
684
+	 * this method will ONLY CREATE ONE REGISTRATION !!!
685
+	 * Regardless of the ticket line item quantity.
686
+	 * This means that any code calling this method is responsible for ensuring
687
+	 * that the final registration count matches the ticket line item quantity.
688
+	 * This was done to make it easier to match the number of registrations
689
+	 * to the number of tickets in the cart, when the cart has been edited
690
+	 * after SPCO has already been initialized. So if an additional ticket was added to the cart, you can simply pass
691
+	 * the line item to this method to add a second ticket, and in this case, you would not want to add 2 tickets.
692
+	 *
693
+	 * @deprecated
694
+	 * @since 4.9.1
695
+	 * @param EE_Line_Item    $line_item
696
+	 * @param \EE_Transaction $transaction
697
+	 * @param int             $att_nmbr
698
+	 * @param int             $total_ticket_count
699
+	 * @return EE_Registration | null
700
+	 * @throws \OutOfRangeException
701
+	 * @throws \EventEspresso\core\exceptions\UnexpectedEntityException
702
+	 * @throws \EE_Error
703
+	 */
704
+	public function generate_ONE_registration_from_line_item(
705
+		EE_Line_Item $line_item,
706
+		EE_Transaction $transaction,
707
+		$att_nmbr = 1,
708
+		$total_ticket_count = 1
709
+	) {
710
+		EE_Error::doing_it_wrong(
711
+			__CLASS__ . '::' . __FUNCTION__,
712
+			sprintf(
713
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
714
+				'\EventEspresso\core\domain\services\registration\CreateRegistrationService::create()'
715
+			),
716
+			'4.9.1',
717
+			'5.0.0'
718
+		);
719
+		// grab the related ticket object for this line_item
720
+		$ticket = $line_item->ticket();
721
+		if (! $ticket instanceof EE_Ticket) {
722
+			EE_Error::add_error(
723
+				sprintf(
724
+					esc_html__('Line item %s did not contain a valid ticket', 'event_espresso'),
725
+					$line_item->ID()
726
+				),
727
+				__FILE__,
728
+				__FUNCTION__,
729
+				__LINE__
730
+			);
731
+			return null;
732
+		}
733
+		$registration_service = new CreateRegistrationService();
734
+		// then generate a new registration from that
735
+		return $registration_service->create(
736
+			$ticket->get_related_event(),
737
+			$transaction,
738
+			$ticket,
739
+			$line_item,
740
+			$att_nmbr,
741
+			$total_ticket_count
742
+		);
743
+	}
744
+
745
+
746
+
747
+	/**
748
+	 * generates reg_url_link
749
+	 *
750
+	 * @deprecated
751
+	 * @since 4.9.1
752
+	 * @param int                   $att_nmbr
753
+	 * @param EE_Line_Item | string $item
754
+	 * @return string
755
+	 * @throws InvalidArgumentException
756
+	 */
757
+	public function generate_reg_url_link($att_nmbr, $item)
758
+	{
759
+		EE_Error::doing_it_wrong(
760
+			__CLASS__ . '::' . __FUNCTION__,
761
+			sprintf(
762
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
763
+				'EventEspresso\core\domain\entities\RegUrlLink'
764
+			),
765
+			'4.9.1',
766
+			'5.0.0'
767
+		);
768
+		return new RegUrlLink($att_nmbr, $item);
769
+	}
770
+
771
+
772
+
773
+	/**
774
+	 * generates reg code
775
+	 *
776
+	 * @deprecated
777
+	 * @since 4.9.1
778
+	 * @param EE_Registration $registration
779
+	 * @return string
780
+	 * @throws EE_Error
781
+	 * @throws EntityNotFoundException
782
+	 * @throws InvalidArgumentException
783
+	 */
784
+	public function generate_reg_code(EE_Registration $registration)
785
+	{
786
+		EE_Error::doing_it_wrong(
787
+			__CLASS__ . '::' . __FUNCTION__,
788
+			sprintf(
789
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
790
+				'EventEspresso\core\domain\entities\RegCode'
791
+			),
792
+			'4.9.1',
793
+			'5.0.0'
794
+		);
795
+		return apply_filters(
796
+			'FHEE__EE_Registration_Processor___generate_reg_code__new_reg_code',
797
+			new RegCode(
798
+				RegUrlLink::fromRegistration($registration),
799
+				$registration->transaction(),
800
+				$registration->ticket()
801
+			),
802
+			$registration
803
+		);
804
+	}
805 805
 
806 806
 
807 807
 
Please login to merge, or discard this patch.
core/domain/entities/contexts/Context.php 1 patch
Indentation   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -17,64 +17,64 @@
 block discarded – undo
17 17
 class Context implements ContextInterface
18 18
 {
19 19
 
20
-    /**
21
-     * @var string $slug
22
-     */
23
-    private $slug;
24
-
25
-    /**
26
-     * @var string $description
27
-     */
28
-    private $description;
29
-
30
-
31
-    /**
32
-     * Context constructor.
33
-     *
34
-     * @param string $slug
35
-     * @param string $description
36
-     */
37
-    public function __construct($slug, $description)
38
-    {
39
-        $this->setSlug($slug);
40
-        $this->setDescription($description);
41
-    }
42
-
43
-
44
-    /**
45
-     * @return string
46
-     */
47
-    public function slug()
48
-    {
49
-        return $this->slug;
50
-    }
51
-
52
-
53
-    /**
54
-     * @param string $slug
55
-     */
56
-    private function setSlug($slug)
57
-    {
58
-        $this->slug = sanitize_key($slug);
59
-    }
60
-
61
-
62
-    /**
63
-     * @return string
64
-     */
65
-    public function description()
66
-    {
67
-        return $this->description;
68
-    }
69
-
70
-
71
-    /**
72
-     * @param string $description
73
-     */
74
-    private function setDescription($description)
75
-    {
76
-        $this->description = sanitize_text_field($description);
77
-    }
20
+	/**
21
+	 * @var string $slug
22
+	 */
23
+	private $slug;
24
+
25
+	/**
26
+	 * @var string $description
27
+	 */
28
+	private $description;
29
+
30
+
31
+	/**
32
+	 * Context constructor.
33
+	 *
34
+	 * @param string $slug
35
+	 * @param string $description
36
+	 */
37
+	public function __construct($slug, $description)
38
+	{
39
+		$this->setSlug($slug);
40
+		$this->setDescription($description);
41
+	}
42
+
43
+
44
+	/**
45
+	 * @return string
46
+	 */
47
+	public function slug()
48
+	{
49
+		return $this->slug;
50
+	}
51
+
52
+
53
+	/**
54
+	 * @param string $slug
55
+	 */
56
+	private function setSlug($slug)
57
+	{
58
+		$this->slug = sanitize_key($slug);
59
+	}
60
+
61
+
62
+	/**
63
+	 * @return string
64
+	 */
65
+	public function description()
66
+	{
67
+		return $this->description;
68
+	}
69
+
70
+
71
+	/**
72
+	 * @param string $description
73
+	 */
74
+	private function setDescription($description)
75
+	{
76
+		$this->description = sanitize_text_field($description);
77
+	}
78 78
 
79 79
 }
80 80
 // Location: Context.php
Please login to merge, or discard this patch.
core/db_models/fields/EE_Float_Field.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -11,7 +11,7 @@
 block discarded – undo
11 11
      * @param string $table_column
12 12
      * @param string $nicename
13 13
      * @param bool   $nullable
14
-     * @param null   $default_value
14
+     * @param integer|null   $default_value
15 15
      */
16 16
     public function __construct($table_column, $nicename, $nullable, $default_value = null)
17 17
     {
Please login to merge, or discard this patch.
Indentation   +51 added lines, -51 removed lines patch added patch discarded remove patch
@@ -8,60 +8,60 @@
 block discarded – undo
8 8
 class EE_Float_Field extends EE_Model_Field_Base
9 9
 {
10 10
 
11
-    /**
12
-     * @param string $table_column
13
-     * @param string $nicename
14
-     * @param bool   $nullable
15
-     * @param null   $default_value
16
-     */
17
-    public function __construct($table_column, $nicename, $nullable, $default_value = null)
18
-    {
19
-        parent::__construct($table_column, $nicename, $nullable, $default_value);
20
-        $this->setSchemaType('number');
21
-    }
11
+	/**
12
+	 * @param string $table_column
13
+	 * @param string $nicename
14
+	 * @param bool   $nullable
15
+	 * @param null   $default_value
16
+	 */
17
+	public function __construct($table_column, $nicename, $nullable, $default_value = null)
18
+	{
19
+		parent::__construct($table_column, $nicename, $nullable, $default_value);
20
+		$this->setSchemaType('number');
21
+	}
22 22
 
23 23
 
24
-    /**
25
-     * If provided a string, strips out number-related formatting, like commas, periods, spaces, other junk, etc.
26
-     * However, treats commas and periods as thousand-separators ro decimal marks, as indicate by the config's currency.
27
-     * So if you want to pass in a string that NEEDS to interpret periods as decimal marks, call floatval() on it first.
28
-     * Returns a float
29
-     *
30
-     * @param string|float|int $value_inputted_for_field_on_model_object
31
-     * @return float
32
-     */
33
-    function prepare_for_set($value_inputted_for_field_on_model_object)
34
-    {
35
-        //remove whitespaces and thousands separators
36
-        if (is_string($value_inputted_for_field_on_model_object)) {
37
-            $value_inputted_for_field_on_model_object = str_replace(array(" ", EE_Config::instance()->currency->thsnds),
38
-                "", $value_inputted_for_field_on_model_object);
39
-            //normalize it so periods are decimal marks (we don't care where you're from: we're talking PHP now)
40
-            $value_inputted_for_field_on_model_object = str_replace(EE_Config::instance()->currency->dec_mrk, ".",
41
-                $value_inputted_for_field_on_model_object);
42
-            //double-check there's absolutely nothing left on this string besides numbers
43
-            $value_inputted_for_field_on_model_object = preg_replace("/[^0-9,.]/", "",
44
-                $value_inputted_for_field_on_model_object);
45
-        }
46
-        return (float)$value_inputted_for_field_on_model_object;
47
-    }
24
+	/**
25
+	 * If provided a string, strips out number-related formatting, like commas, periods, spaces, other junk, etc.
26
+	 * However, treats commas and periods as thousand-separators ro decimal marks, as indicate by the config's currency.
27
+	 * So if you want to pass in a string that NEEDS to interpret periods as decimal marks, call floatval() on it first.
28
+	 * Returns a float
29
+	 *
30
+	 * @param string|float|int $value_inputted_for_field_on_model_object
31
+	 * @return float
32
+	 */
33
+	function prepare_for_set($value_inputted_for_field_on_model_object)
34
+	{
35
+		//remove whitespaces and thousands separators
36
+		if (is_string($value_inputted_for_field_on_model_object)) {
37
+			$value_inputted_for_field_on_model_object = str_replace(array(" ", EE_Config::instance()->currency->thsnds),
38
+				"", $value_inputted_for_field_on_model_object);
39
+			//normalize it so periods are decimal marks (we don't care where you're from: we're talking PHP now)
40
+			$value_inputted_for_field_on_model_object = str_replace(EE_Config::instance()->currency->dec_mrk, ".",
41
+				$value_inputted_for_field_on_model_object);
42
+			//double-check there's absolutely nothing left on this string besides numbers
43
+			$value_inputted_for_field_on_model_object = preg_replace("/[^0-9,.]/", "",
44
+				$value_inputted_for_field_on_model_object);
45
+		}
46
+		return (float)$value_inputted_for_field_on_model_object;
47
+	}
48 48
 
49
-    /**
50
-     * Returns the number formatted according to local custom (set by the country of the blog).
51
-     *
52
-     * @param float $value_on_field_to_be_outputted
53
-     * @return string
54
-     */
55
-    function prepare_for_pretty_echoing($value_on_field_to_be_outputted, $schema = null)
56
-    {
57
-        $EE = EE_Registry::instance();
58
-        return number_format($value_on_field_to_be_outputted, $EE->CFG->currency->dec_plc, $EE->CFG->currency->dec_mrk,
59
-            $EE->CFG->currency->thsnds);
60
-    }
49
+	/**
50
+	 * Returns the number formatted according to local custom (set by the country of the blog).
51
+	 *
52
+	 * @param float $value_on_field_to_be_outputted
53
+	 * @return string
54
+	 */
55
+	function prepare_for_pretty_echoing($value_on_field_to_be_outputted, $schema = null)
56
+	{
57
+		$EE = EE_Registry::instance();
58
+		return number_format($value_on_field_to_be_outputted, $EE->CFG->currency->dec_plc, $EE->CFG->currency->dec_mrk,
59
+			$EE->CFG->currency->thsnds);
60
+	}
61 61
 
62
-    function prepare_for_set_from_db($value_found_in_db_for_model_object)
63
-    {
62
+	function prepare_for_set_from_db($value_found_in_db_for_model_object)
63
+	{
64 64
 //		echo "prepare for set from db of ";d($value_found_in_db_for_model_object);
65
-        return floatval($value_found_in_db_for_model_object);
66
-    }
65
+		return floatval($value_found_in_db_for_model_object);
66
+	}
67 67
 }
68 68
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -43,7 +43,7 @@
 block discarded – undo
43 43
             $value_inputted_for_field_on_model_object = preg_replace("/[^0-9,.]/", "",
44 44
                 $value_inputted_for_field_on_model_object);
45 45
         }
46
-        return (float)$value_inputted_for_field_on_model_object;
46
+        return (float) $value_inputted_for_field_on_model_object;
47 47
     }
48 48
 
49 49
     /**
Please login to merge, or discard this patch.
core/domain/values/currency/Money.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
      */
84 84
     private function parseAmount($amount)
85 85
     {
86
-        if (! in_array(gettype($amount), array('integer', 'double', 'string'), true)) {
86
+        if ( ! in_array(gettype($amount), array('integer', 'double', 'string'), true)) {
87 87
             throw new InvalidDataTypeException(
88 88
                 '$amount',
89 89
                 $amount,
@@ -116,7 +116,7 @@  discard block
 block discarded – undo
116 116
         $amount *= pow(10, $this->precision());
117 117
         // then round up the remaining value if there is still a fractional amount left
118 118
         $amount = round($amount);
119
-        return (int)$amount;
119
+        return (int) $amount;
120 120
     }
121 121
 
122 122
 
Please login to merge, or discard this patch.
Indentation   +297 added lines, -297 removed lines patch added patch discarded remove patch
@@ -21,301 +21,301 @@
 block discarded – undo
21 21
 class Money
22 22
 {
23 23
 
24
-    /**
25
-     * number of decimal places to be added to currencies for internal computations,
26
-     * but removed before any output or formatting is applied.
27
-     * This allows us to avoid rounding errors during calculations.
28
-     */
29
-    const EXTRA_PRECISION = 3;
30
-
31
-    /**
32
-     * @var int $amount
33
-     */
34
-    private $amount;
35
-
36
-    /**
37
-     * @var Currency $currency
38
-     */
39
-    private $currency;
40
-
41
-    /**
42
-     * @var Calculator $calculator
43
-     */
44
-    protected $calculator;
45
-
46
-
47
-
48
-    /**
49
-     * Money constructor.
50
-     *
51
-     * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
52
-     *                                 example: $12.5 USD would equate to a value amount of 12.50
53
-     * @param Currency         $currency
54
-     * @param Calculator       $calculator
55
-     * @throws InvalidDataTypeException
56
-     */
57
-    public function __construct($amount, Currency $currency, Calculator $calculator)
58
-    {
59
-        $this->currency   = $currency;
60
-        $this->amount     = $this->parseAmount($amount);
61
-        $this->calculator = $calculator;
62
-    }
63
-
64
-
65
-
66
-    /**
67
-     * @return Calculator
68
-     */
69
-    protected function calculator()
70
-    {
71
-        return $this->calculator;
72
-    }
73
-
74
-
75
-
76
-    /**
77
-     * Convert's a standard unit amount into the subunits of the currency
78
-     *
79
-     * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
80
-     *                                 example: $12.5 USD would equate to a value amount of 12.50
81
-     * @return integer                 in the currency's subunit
82
-     * @throws InvalidDataTypeException
83
-     */
84
-    private function parseAmount($amount)
85
-    {
86
-        if (! in_array(gettype($amount), array('integer', 'double', 'string'), true)) {
87
-            throw new InvalidDataTypeException(
88
-                '$amount',
89
-                $amount,
90
-                'integer (or float or string)'
91
-            );
92
-        }
93
-        if ($this->currency->decimalMark() !== '.') {
94
-            // remove thousands separator and replace decimal place with standard decimal.
95
-            $amount = str_replace(
96
-                array(
97
-                    $this->currency->thousands(),
98
-                    $this->currency->decimalMark(),
99
-                ),
100
-                array(
101
-                    '',
102
-                    '.',
103
-                ),
104
-                $amount
105
-            );
106
-        }
107
-        // remove any non numeric values but leave the decimal
108
-        $amount = (float) preg_replace('/([^0-9\\.-])/', '', $amount);
109
-        // maybe convert the incoming  decimal amount to the currencies subunits
110
-        // ex: 12.5 for a currency with 100 subunits would become 1250
111
-        if ($this->currency()->subunits()) {
112
-            $amount *= $this->currency()->subunits();
113
-        }
114
-        // then shift the decimal position by the number of decimal places used internally
115
-        // so if our extra internal precision was 3, it would become 1250000
116
-        $amount *= pow(10, $this->precision());
117
-        // then round up the remaining value if there is still a fractional amount left
118
-        $amount = round($amount);
119
-        return (int)$amount;
120
-    }
121
-
122
-
123
-
124
-    /**
125
-     * adds or subtracts additional decimal places based on the value of the Money::EXTRA_PRECISION constant
126
-     *
127
-     * @param bool $adding_precision if true, will move the decimal to the right (increase amount)
128
-     *                               if false, will move the decimal to the left (decrease amount)
129
-     * @return integer
130
-     */
131
-    private function precision($adding_precision = true)
132
-    {
133
-        $sign = $adding_precision ? 1 : -1;
134
-        return Money::EXTRA_PRECISION * $sign;
135
-    }
136
-
137
-    /**
138
-     * Returns the money amount as an unformatted float
139
-     * @return float
140
-     */
141
-    public function floatAmount()
142
-    {
143
-        // shift the decimal position BACK by the number of decimal places used internally
144
-        // ex: if our extra internal precision was 3, then 1250000 would become 1250
145
-        $amount = $this->amount * pow(10, $this->precision(false));
146
-        // then maybe adjust for the currencies subunits
147
-        // ex: 1250 for a currency with 100 subunits would become 12.50
148
-        if ($this->currency()->subunits()) {
149
-            $amount /= $this->currency()->subunits();
150
-        }
151
-        return $amount;
152
-    }
153
-
154
-
155
-
156
-    /**
157
-     * Returns the money amount as an unformatted string
158
-     * IF YOU REQUIRE A FORMATTED STRING, THEN USE Money::format()
159
-     * In the currency's standard units
160
-     *
161
-     * @return string
162
-     */
163
-    public function amount()
164
-    {
165
-        // shave off our extra internal precision using the number of decimal places for the currency
166
-        return (string) round($this->floatAmount(), $this->currency()->decimalPlaces());
167
-    }
168
-
169
-
170
-
171
-    /**
172
-     * Returns the money SUBUNITS amount as an INTEGER
173
-     *
174
-     * @return integer
175
-     */
176
-    public function amountInSubunits()
177
-    {
178
-        // shift the decimal position BACK by the number of decimal places used internally
179
-        // for extra internal precision, but NOT for the number of decimals used by the currency
180
-        // ex: if our extra internal precision was 3, then 1250000 would become 1250
181
-        // and even if the currency used 100 subunits, we would return 1250 and NOT 12.50
182
-        $amount = (string) $this->amount * pow(10, $this->precision(false));
183
-        // then shave off anything after the decimal
184
-        $amount = round($amount);
185
-        return (int) $amount;
186
-    }
187
-
188
-
189
-
190
-    /**
191
-     * Returns the Currency object for this money
192
-     *
193
-     * @return Currency
194
-     */
195
-    public function currency()
196
-    {
197
-        return $this->currency;
198
-    }
199
-
200
-
201
-
202
-    /**
203
-     * adds the supplied Money amount to this Money amount
204
-     * and returns a new Money object
205
-     *
206
-     * @param Money $other
207
-     * @return Money
208
-     * @throws InvalidArgumentException
209
-     */
210
-    public function add(Money $other)
211
-    {
212
-        $this->verifySameCurrency($other->currency());
213
-        return new Money(
214
-            $this->calculator()->add(
215
-                $this->amount(),
216
-                $other->amount()
217
-            ),
218
-            $this->currency(),
219
-            $this->calculator()
220
-        );
221
-    }
222
-
223
-
224
-
225
-    /**
226
-     * subtracts the supplied Money amount from this Money amount
227
-     * and returns a new Money object
228
-     *
229
-     * @param Money $other
230
-     * @return Money
231
-     * @throws InvalidArgumentException
232
-     */
233
-    public function subtract(Money $other)
234
-    {
235
-        $this->verifySameCurrency($other->currency());
236
-        return new Money(
237
-            $this->calculator()->subtract(
238
-                $this->amount(),
239
-                $other->amount()
240
-            ),
241
-            $this->currency(),
242
-            $this->calculator()
243
-        );
244
-    }
245
-
246
-
247
-    /**
248
-     * multiplies this Money amount by the supplied $multiplier
249
-     * and returns a new Money object
250
-     *
251
-     * @param float|int|string $multiplier
252
-     * @param int              $rounding_mode
253
-     * @return Money
254
-     * @throws InvalidDataTypeException
255
-     */
256
-    public function multiply($multiplier, $rounding_mode = Calculator::ROUND_HALF_UP)
257
-    {
258
-        return new Money(
259
-            $this->calculator()->multiply(
260
-                $this->amount(),
261
-                $multiplier,
262
-                $this->precision(),
263
-                $rounding_mode
264
-            ),
265
-            $this->currency(),
266
-            $this->calculator()
267
-        );
268
-    }
269
-
270
-
271
-    /**
272
-     * divides this Money amount by the supplied $divisor
273
-     * and returns a new Money object
274
-     *
275
-     * @param float|int|string $divisor
276
-     * @param int              $rounding_mode
277
-     * @return Money
278
-     * @throws InvalidDataTypeException
279
-     */
280
-    public function divide($divisor, $rounding_mode = Calculator::ROUND_HALF_UP)
281
-    {
282
-        return new Money(
283
-            $this->calculator()->divide(
284
-                $this->amount(),
285
-                $divisor,
286
-                $this->precision(),
287
-                $rounding_mode
288
-            ),
289
-            $this->currency(),
290
-            $this->calculator()
291
-        );
292
-    }
293
-
294
-
295
-
296
-    /**
297
-     * @param Currency $other_currency
298
-     * @throws InvalidArgumentException
299
-     */
300
-    public function verifySameCurrency(Currency $other_currency)
301
-    {
302
-        if ($this->currency()->equals($other_currency) !== true) {
303
-            throw new InvalidArgumentException(
304
-                esc_html__(
305
-                    'Currencies must be the same in order to add or subtract their values.',
306
-                    'event_espresso'
307
-                )
308
-            );
309
-        }
310
-    }
311
-
312
-
313
-
314
-    /**
315
-     * @return string
316
-     */
317
-    public function __toString()
318
-    {
319
-        return $this->amount();
320
-    }
24
+	/**
25
+	 * number of decimal places to be added to currencies for internal computations,
26
+	 * but removed before any output or formatting is applied.
27
+	 * This allows us to avoid rounding errors during calculations.
28
+	 */
29
+	const EXTRA_PRECISION = 3;
30
+
31
+	/**
32
+	 * @var int $amount
33
+	 */
34
+	private $amount;
35
+
36
+	/**
37
+	 * @var Currency $currency
38
+	 */
39
+	private $currency;
40
+
41
+	/**
42
+	 * @var Calculator $calculator
43
+	 */
44
+	protected $calculator;
45
+
46
+
47
+
48
+	/**
49
+	 * Money constructor.
50
+	 *
51
+	 * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
52
+	 *                                 example: $12.5 USD would equate to a value amount of 12.50
53
+	 * @param Currency         $currency
54
+	 * @param Calculator       $calculator
55
+	 * @throws InvalidDataTypeException
56
+	 */
57
+	public function __construct($amount, Currency $currency, Calculator $calculator)
58
+	{
59
+		$this->currency   = $currency;
60
+		$this->amount     = $this->parseAmount($amount);
61
+		$this->calculator = $calculator;
62
+	}
63
+
64
+
65
+
66
+	/**
67
+	 * @return Calculator
68
+	 */
69
+	protected function calculator()
70
+	{
71
+		return $this->calculator;
72
+	}
73
+
74
+
75
+
76
+	/**
77
+	 * Convert's a standard unit amount into the subunits of the currency
78
+	 *
79
+	 * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
80
+	 *                                 example: $12.5 USD would equate to a value amount of 12.50
81
+	 * @return integer                 in the currency's subunit
82
+	 * @throws InvalidDataTypeException
83
+	 */
84
+	private function parseAmount($amount)
85
+	{
86
+		if (! in_array(gettype($amount), array('integer', 'double', 'string'), true)) {
87
+			throw new InvalidDataTypeException(
88
+				'$amount',
89
+				$amount,
90
+				'integer (or float or string)'
91
+			);
92
+		}
93
+		if ($this->currency->decimalMark() !== '.') {
94
+			// remove thousands separator and replace decimal place with standard decimal.
95
+			$amount = str_replace(
96
+				array(
97
+					$this->currency->thousands(),
98
+					$this->currency->decimalMark(),
99
+				),
100
+				array(
101
+					'',
102
+					'.',
103
+				),
104
+				$amount
105
+			);
106
+		}
107
+		// remove any non numeric values but leave the decimal
108
+		$amount = (float) preg_replace('/([^0-9\\.-])/', '', $amount);
109
+		// maybe convert the incoming  decimal amount to the currencies subunits
110
+		// ex: 12.5 for a currency with 100 subunits would become 1250
111
+		if ($this->currency()->subunits()) {
112
+			$amount *= $this->currency()->subunits();
113
+		}
114
+		// then shift the decimal position by the number of decimal places used internally
115
+		// so if our extra internal precision was 3, it would become 1250000
116
+		$amount *= pow(10, $this->precision());
117
+		// then round up the remaining value if there is still a fractional amount left
118
+		$amount = round($amount);
119
+		return (int)$amount;
120
+	}
121
+
122
+
123
+
124
+	/**
125
+	 * adds or subtracts additional decimal places based on the value of the Money::EXTRA_PRECISION constant
126
+	 *
127
+	 * @param bool $adding_precision if true, will move the decimal to the right (increase amount)
128
+	 *                               if false, will move the decimal to the left (decrease amount)
129
+	 * @return integer
130
+	 */
131
+	private function precision($adding_precision = true)
132
+	{
133
+		$sign = $adding_precision ? 1 : -1;
134
+		return Money::EXTRA_PRECISION * $sign;
135
+	}
136
+
137
+	/**
138
+	 * Returns the money amount as an unformatted float
139
+	 * @return float
140
+	 */
141
+	public function floatAmount()
142
+	{
143
+		// shift the decimal position BACK by the number of decimal places used internally
144
+		// ex: if our extra internal precision was 3, then 1250000 would become 1250
145
+		$amount = $this->amount * pow(10, $this->precision(false));
146
+		// then maybe adjust for the currencies subunits
147
+		// ex: 1250 for a currency with 100 subunits would become 12.50
148
+		if ($this->currency()->subunits()) {
149
+			$amount /= $this->currency()->subunits();
150
+		}
151
+		return $amount;
152
+	}
153
+
154
+
155
+
156
+	/**
157
+	 * Returns the money amount as an unformatted string
158
+	 * IF YOU REQUIRE A FORMATTED STRING, THEN USE Money::format()
159
+	 * In the currency's standard units
160
+	 *
161
+	 * @return string
162
+	 */
163
+	public function amount()
164
+	{
165
+		// shave off our extra internal precision using the number of decimal places for the currency
166
+		return (string) round($this->floatAmount(), $this->currency()->decimalPlaces());
167
+	}
168
+
169
+
170
+
171
+	/**
172
+	 * Returns the money SUBUNITS amount as an INTEGER
173
+	 *
174
+	 * @return integer
175
+	 */
176
+	public function amountInSubunits()
177
+	{
178
+		// shift the decimal position BACK by the number of decimal places used internally
179
+		// for extra internal precision, but NOT for the number of decimals used by the currency
180
+		// ex: if our extra internal precision was 3, then 1250000 would become 1250
181
+		// and even if the currency used 100 subunits, we would return 1250 and NOT 12.50
182
+		$amount = (string) $this->amount * pow(10, $this->precision(false));
183
+		// then shave off anything after the decimal
184
+		$amount = round($amount);
185
+		return (int) $amount;
186
+	}
187
+
188
+
189
+
190
+	/**
191
+	 * Returns the Currency object for this money
192
+	 *
193
+	 * @return Currency
194
+	 */
195
+	public function currency()
196
+	{
197
+		return $this->currency;
198
+	}
199
+
200
+
201
+
202
+	/**
203
+	 * adds the supplied Money amount to this Money amount
204
+	 * and returns a new Money object
205
+	 *
206
+	 * @param Money $other
207
+	 * @return Money
208
+	 * @throws InvalidArgumentException
209
+	 */
210
+	public function add(Money $other)
211
+	{
212
+		$this->verifySameCurrency($other->currency());
213
+		return new Money(
214
+			$this->calculator()->add(
215
+				$this->amount(),
216
+				$other->amount()
217
+			),
218
+			$this->currency(),
219
+			$this->calculator()
220
+		);
221
+	}
222
+
223
+
224
+
225
+	/**
226
+	 * subtracts the supplied Money amount from this Money amount
227
+	 * and returns a new Money object
228
+	 *
229
+	 * @param Money $other
230
+	 * @return Money
231
+	 * @throws InvalidArgumentException
232
+	 */
233
+	public function subtract(Money $other)
234
+	{
235
+		$this->verifySameCurrency($other->currency());
236
+		return new Money(
237
+			$this->calculator()->subtract(
238
+				$this->amount(),
239
+				$other->amount()
240
+			),
241
+			$this->currency(),
242
+			$this->calculator()
243
+		);
244
+	}
245
+
246
+
247
+	/**
248
+	 * multiplies this Money amount by the supplied $multiplier
249
+	 * and returns a new Money object
250
+	 *
251
+	 * @param float|int|string $multiplier
252
+	 * @param int              $rounding_mode
253
+	 * @return Money
254
+	 * @throws InvalidDataTypeException
255
+	 */
256
+	public function multiply($multiplier, $rounding_mode = Calculator::ROUND_HALF_UP)
257
+	{
258
+		return new Money(
259
+			$this->calculator()->multiply(
260
+				$this->amount(),
261
+				$multiplier,
262
+				$this->precision(),
263
+				$rounding_mode
264
+			),
265
+			$this->currency(),
266
+			$this->calculator()
267
+		);
268
+	}
269
+
270
+
271
+	/**
272
+	 * divides this Money amount by the supplied $divisor
273
+	 * and returns a new Money object
274
+	 *
275
+	 * @param float|int|string $divisor
276
+	 * @param int              $rounding_mode
277
+	 * @return Money
278
+	 * @throws InvalidDataTypeException
279
+	 */
280
+	public function divide($divisor, $rounding_mode = Calculator::ROUND_HALF_UP)
281
+	{
282
+		return new Money(
283
+			$this->calculator()->divide(
284
+				$this->amount(),
285
+				$divisor,
286
+				$this->precision(),
287
+				$rounding_mode
288
+			),
289
+			$this->currency(),
290
+			$this->calculator()
291
+		);
292
+	}
293
+
294
+
295
+
296
+	/**
297
+	 * @param Currency $other_currency
298
+	 * @throws InvalidArgumentException
299
+	 */
300
+	public function verifySameCurrency(Currency $other_currency)
301
+	{
302
+		if ($this->currency()->equals($other_currency) !== true) {
303
+			throw new InvalidArgumentException(
304
+				esc_html__(
305
+					'Currencies must be the same in order to add or subtract their values.',
306
+					'event_espresso'
307
+				)
308
+			);
309
+		}
310
+	}
311
+
312
+
313
+
314
+	/**
315
+	 * @return string
316
+	 */
317
+	public function __toString()
318
+	{
319
+		return $this->amount();
320
+	}
321 321
 }
Please login to merge, or discard this patch.
core/interfaces/EEI_Base.interface.php 1 patch
Indentation   +93 added lines, -93 removed lines patch added patch discarded remove patch
@@ -8,99 +8,99 @@
 block discarded – undo
8 8
 interface EEI_Base
9 9
 {
10 10
 
11
-    /**
12
-     * gets the unique ID of the model object. If it hasn't been saved yet
13
-     * to the database, this should be 0 or NULL
14
-     */
15
-    public function ID();
16
-
17
-
18
-
19
-    /**
20
-     * Returns an array where keys are field names and values are their values
21
-     *
22
-     * @return array
23
-     */
24
-    public function model_field_array();
25
-
26
-
27
-
28
-    /**
29
-     * Saves the thing to the database and returns success (or an ID)
30
-     *
31
-     * @return boolean success on insert; or int on update (ID of newly inserted thing)
32
-     */
33
-    public function save();
34
-
35
-
36
-
37
-    /**
38
-     * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
39
-     * A $previous_value can be specified in case there are many meta rows with the same key
40
-     *
41
-     * @param string $meta_key
42
-     * @param string $meta_value
43
-     * @param string $previous_value
44
-     * @return int records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
45
-     * NOTE: if the values haven't changed, returns 0
46
-     */
47
-    public function update_extra_meta($meta_key, $meta_value, $previous_value = null);
48
-
49
-
50
-
51
-    /**
52
-     * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
53
-     * no other extra meta for this model object have the same key. Returns TRUE if the
54
-     * extra meta row was entered, false if not
55
-     *
56
-     * @param string  $meta_key
57
-     * @param string  $meta_value
58
-     * @param boolean $unique
59
-     * @return boolean
60
-     */
61
-    public function add_extra_meta($meta_key, $meta_value, $unique = false);
62
-
63
-
64
-
65
-    /**
66
-     * Deletes all the extra meta rows for this record as specified by key. If $meta_value
67
-     * is specified, only deletes extra meta records with that value.
68
-     *
69
-     * @param string $meta_key
70
-     * @param string $meta_value
71
-     * @return int number of extra meta rows deleted
72
-     */
73
-    public function delete_extra_meta($meta_key, $meta_value = null);
74
-
75
-
76
-
77
-    /**
78
-     * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
79
-     * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
80
-     * You can specify $default is case you haven't found the extra meta
81
-     *
82
-     * @param string  $meta_key
83
-     * @param boolean $single
84
-     * @param mixed   $default if we don't find anything, what should we return?
85
-     * @return mixed single value if $single; array if ! $single
86
-     */
87
-    public function get_extra_meta($meta_key, $single = false, $default = NULL);
88
-
89
-
90
-
91
-    /**
92
-     * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
93
-     * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
94
-     * to see what options are available.
95
-     *
96
-     * @param string $field_name
97
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
98
-     *                                (in cases where the same property may be used for different outputs
99
-     *                                - i.e. datetime, money etc.)
100
-     * @return mixed
101
-     * @throws \EE_Error
102
-     */
103
-    public function get_pretty($field_name, $extra_cache_ref);
11
+	/**
12
+	 * gets the unique ID of the model object. If it hasn't been saved yet
13
+	 * to the database, this should be 0 or NULL
14
+	 */
15
+	public function ID();
16
+
17
+
18
+
19
+	/**
20
+	 * Returns an array where keys are field names and values are their values
21
+	 *
22
+	 * @return array
23
+	 */
24
+	public function model_field_array();
25
+
26
+
27
+
28
+	/**
29
+	 * Saves the thing to the database and returns success (or an ID)
30
+	 *
31
+	 * @return boolean success on insert; or int on update (ID of newly inserted thing)
32
+	 */
33
+	public function save();
34
+
35
+
36
+
37
+	/**
38
+	 * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
39
+	 * A $previous_value can be specified in case there are many meta rows with the same key
40
+	 *
41
+	 * @param string $meta_key
42
+	 * @param string $meta_value
43
+	 * @param string $previous_value
44
+	 * @return int records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
45
+	 * NOTE: if the values haven't changed, returns 0
46
+	 */
47
+	public function update_extra_meta($meta_key, $meta_value, $previous_value = null);
48
+
49
+
50
+
51
+	/**
52
+	 * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
53
+	 * no other extra meta for this model object have the same key. Returns TRUE if the
54
+	 * extra meta row was entered, false if not
55
+	 *
56
+	 * @param string  $meta_key
57
+	 * @param string  $meta_value
58
+	 * @param boolean $unique
59
+	 * @return boolean
60
+	 */
61
+	public function add_extra_meta($meta_key, $meta_value, $unique = false);
62
+
63
+
64
+
65
+	/**
66
+	 * Deletes all the extra meta rows for this record as specified by key. If $meta_value
67
+	 * is specified, only deletes extra meta records with that value.
68
+	 *
69
+	 * @param string $meta_key
70
+	 * @param string $meta_value
71
+	 * @return int number of extra meta rows deleted
72
+	 */
73
+	public function delete_extra_meta($meta_key, $meta_value = null);
74
+
75
+
76
+
77
+	/**
78
+	 * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
79
+	 * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
80
+	 * You can specify $default is case you haven't found the extra meta
81
+	 *
82
+	 * @param string  $meta_key
83
+	 * @param boolean $single
84
+	 * @param mixed   $default if we don't find anything, what should we return?
85
+	 * @return mixed single value if $single; array if ! $single
86
+	 */
87
+	public function get_extra_meta($meta_key, $single = false, $default = NULL);
88
+
89
+
90
+
91
+	/**
92
+	 * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
93
+	 * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
94
+	 * to see what options are available.
95
+	 *
96
+	 * @param string $field_name
97
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
98
+	 *                                (in cases where the same property may be used for different outputs
99
+	 *                                - i.e. datetime, money etc.)
100
+	 * @return mixed
101
+	 * @throws \EE_Error
102
+	 */
103
+	public function get_pretty($field_name, $extra_cache_ref);
104 104
 }
105 105
 // End of file EEI_Base.interface.php
106 106
 // Location: core/interfaces/EEI_Base.interface.php
107 107
\ No newline at end of file
Please login to merge, or discard this patch.
core/services/currency/MoneyFactory.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -186,7 +186,7 @@
 block discarded – undo
186 186
             )
187 187
         );
188 188
         foreach ($calculators as $calculator) {
189
-            if (! class_exists($calculator)) {
189
+            if ( ! class_exists($calculator)) {
190 190
                 continue;
191 191
             }
192 192
             $calculator = new $calculator();
Please login to merge, or discard this patch.
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -24,163 +24,163 @@
 block discarded – undo
24 24
 class MoneyFactory
25 25
 {
26 26
 
27
-    /**
28
-     * @var CurrencyFactory $currency_factory
29
-     */
30
-    protected $currency_factory;
31
-
32
-    /**
33
-     * @var Calculator $calculator
34
-     */
35
-    protected $calculator;
36
-
37
-
38
-    /**
39
-     * CreateMoney constructor.
40
-     *
41
-     * @param CurrencyFactory  $currency_factory
42
-     * @param Calculator       $calculator
43
-     */
44
-    public function __construct(
45
-        CurrencyFactory $currency_factory,
46
-        Calculator $calculator = null
47
-    ) {
48
-        $this->calculator = $calculator;
49
-        $this->currency_factory = $currency_factory;
50
-    }
51
-
52
-
53
-    /**
54
-     * factory method that returns a Money object using amount specified in the currency's subunits
55
-     * example: for $12.50 USD use CreateMoney::fromSubUnits(1250, 'USD')
56
-     *
57
-     * @param int    $subunits_amount money amount IN THE SUBUNITS FOR THE CURRENCY ie: cents
58
-     *                                example: $12.50 USD would equate to a subunits amount of 1250
59
-     * @param string $currency_code
60
-     * @return Money
61
-     * @throws EE_Error
62
-     * @throws InvalidArgumentException
63
-     * @throws InvalidDataTypeException
64
-     */
65
-    public function createFromSubUnits($subunits_amount, $currency_code = '')
66
-    {
67
-        $currency = $this->currency_factory->createFromCode($currency_code);
68
-        return new Money(
69
-            // shift decimal BACK by number of places for currency
70
-            $subunits_amount * pow(10, $currency->decimalPlaces() * -1),
71
-            $currency,
72
-            $this->calculator()
73
-        );
74
-    }
75
-
76
-
77
-
78
-    /**
79
-     * factory method that returns a Money object using the currency corresponding to the site's country
80
-     * example: CreateMoney::forSite(12.5)
81
-     *
82
-     * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
83
-     *                                 example: $12.5 USD would equate to a standard amount of 12.50
84
-     * @return Money
85
-     * @throws EE_Error
86
-     * @throws InvalidArgumentException
87
-     * @throws InvalidDataTypeException
88
-     */
89
-    public function createForSite($amount)
90
-    {
91
-        return new Money(
92
-            $amount,
93
-            $this->currency_factory->createFromCountryCode(\EE_Config::instance()->organization->CNT_ISO),
94
-            $this->calculator()
95
-        );
96
-    }
97
-
98
-
99
-
100
-    /**
101
-     * factory method that returns a Money object using the currency as specified by the supplied ISO country code
102
-     * example: CreateMoney::forCountry(12.5,'US')
103
-     *
104
-     * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
105
-     *                                 example: $12.5 USD would equate to a value amount of 12.50
106
-     * @param string           $CNT_ISO
107
-     * @return Money
108
-     * @throws EE_Error
109
-     * @throws InvalidArgumentException
110
-     * @throws InvalidDataTypeException
111
-     */
112
-    public function createForCountry($amount, $CNT_ISO)
113
-    {
114
-        return new Money(
115
-            $amount,
116
-            $this->currency_factory->createFromCountryCode($CNT_ISO),
117
-            $this->calculator()
118
-        );
119
-    }
120
-
121
-
122
-
123
-    /**
124
-     * factory method that returns a Money object using the currency as specified by the supplied currency code
125
-     * example: CreateMoney::forCurrency(12.5, 'USD')
126
-     *
127
-     * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
128
-     *                                 example: $12.5 USD would equate to a value amount of 12.50
129
-     * @param string           $currency_code
130
-     * @return Money
131
-     * @throws EE_Error
132
-     * @throws InvalidArgumentException
133
-     * @throws InvalidDataTypeException
134
-     */
135
-    public function createForCurrency($amount, $currency_code)
136
-    {
137
-        return new Money(
138
-            $amount,
139
-            $this->currency_factory->createFromCode($currency_code),
140
-            $this->calculator()
141
-        );
142
-    }
143
-
144
-
145
-
146
-
147
-    /**
148
-     * @return Calculator
149
-     */
150
-    public function calculator()
151
-    {
152
-        $this->initializeCalculators();
153
-        return $this->calculator;
154
-    }
155
-
156
-
157
-
158
-    /**
159
-     * loops through a filterable array of Calculator services
160
-     * and selects the first one that is supported by the current server
161
-     */
162
-    protected function initializeCalculators()
163
-    {
164
-        if ($this->calculator instanceof Calculator) {
165
-            return;
166
-        }
167
-        $calculators = apply_filters(
168
-            'FHEE__EventEspresso_core_services_currency_MoneyFactory__initializeCalculators__Calculators_array',
169
-            array(
170
-                'EventEspresso\core\services\currency\DefaultCalculator',
171
-            )
172
-        );
173
-        foreach ($calculators as $calculator) {
174
-            if (! class_exists($calculator)) {
175
-                continue;
176
-            }
177
-            $calculator = new $calculator();
178
-            if ($calculator instanceof Calculator && $calculator->isSupported()) {
179
-                $this->calculator = $calculator;
180
-                break;
181
-            }
182
-        }
183
-    }
27
+	/**
28
+	 * @var CurrencyFactory $currency_factory
29
+	 */
30
+	protected $currency_factory;
31
+
32
+	/**
33
+	 * @var Calculator $calculator
34
+	 */
35
+	protected $calculator;
36
+
37
+
38
+	/**
39
+	 * CreateMoney constructor.
40
+	 *
41
+	 * @param CurrencyFactory  $currency_factory
42
+	 * @param Calculator       $calculator
43
+	 */
44
+	public function __construct(
45
+		CurrencyFactory $currency_factory,
46
+		Calculator $calculator = null
47
+	) {
48
+		$this->calculator = $calculator;
49
+		$this->currency_factory = $currency_factory;
50
+	}
51
+
52
+
53
+	/**
54
+	 * factory method that returns a Money object using amount specified in the currency's subunits
55
+	 * example: for $12.50 USD use CreateMoney::fromSubUnits(1250, 'USD')
56
+	 *
57
+	 * @param int    $subunits_amount money amount IN THE SUBUNITS FOR THE CURRENCY ie: cents
58
+	 *                                example: $12.50 USD would equate to a subunits amount of 1250
59
+	 * @param string $currency_code
60
+	 * @return Money
61
+	 * @throws EE_Error
62
+	 * @throws InvalidArgumentException
63
+	 * @throws InvalidDataTypeException
64
+	 */
65
+	public function createFromSubUnits($subunits_amount, $currency_code = '')
66
+	{
67
+		$currency = $this->currency_factory->createFromCode($currency_code);
68
+		return new Money(
69
+			// shift decimal BACK by number of places for currency
70
+			$subunits_amount * pow(10, $currency->decimalPlaces() * -1),
71
+			$currency,
72
+			$this->calculator()
73
+		);
74
+	}
75
+
76
+
77
+
78
+	/**
79
+	 * factory method that returns a Money object using the currency corresponding to the site's country
80
+	 * example: CreateMoney::forSite(12.5)
81
+	 *
82
+	 * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
83
+	 *                                 example: $12.5 USD would equate to a standard amount of 12.50
84
+	 * @return Money
85
+	 * @throws EE_Error
86
+	 * @throws InvalidArgumentException
87
+	 * @throws InvalidDataTypeException
88
+	 */
89
+	public function createForSite($amount)
90
+	{
91
+		return new Money(
92
+			$amount,
93
+			$this->currency_factory->createFromCountryCode(\EE_Config::instance()->organization->CNT_ISO),
94
+			$this->calculator()
95
+		);
96
+	}
97
+
98
+
99
+
100
+	/**
101
+	 * factory method that returns a Money object using the currency as specified by the supplied ISO country code
102
+	 * example: CreateMoney::forCountry(12.5,'US')
103
+	 *
104
+	 * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
105
+	 *                                 example: $12.5 USD would equate to a value amount of 12.50
106
+	 * @param string           $CNT_ISO
107
+	 * @return Money
108
+	 * @throws EE_Error
109
+	 * @throws InvalidArgumentException
110
+	 * @throws InvalidDataTypeException
111
+	 */
112
+	public function createForCountry($amount, $CNT_ISO)
113
+	{
114
+		return new Money(
115
+			$amount,
116
+			$this->currency_factory->createFromCountryCode($CNT_ISO),
117
+			$this->calculator()
118
+		);
119
+	}
120
+
121
+
122
+
123
+	/**
124
+	 * factory method that returns a Money object using the currency as specified by the supplied currency code
125
+	 * example: CreateMoney::forCurrency(12.5, 'USD')
126
+	 *
127
+	 * @param float|int|string $amount money amount IN THE STANDARD UNIT FOR THE CURRENCY ie: dollars, Euros, etc
128
+	 *                                 example: $12.5 USD would equate to a value amount of 12.50
129
+	 * @param string           $currency_code
130
+	 * @return Money
131
+	 * @throws EE_Error
132
+	 * @throws InvalidArgumentException
133
+	 * @throws InvalidDataTypeException
134
+	 */
135
+	public function createForCurrency($amount, $currency_code)
136
+	{
137
+		return new Money(
138
+			$amount,
139
+			$this->currency_factory->createFromCode($currency_code),
140
+			$this->calculator()
141
+		);
142
+	}
143
+
144
+
145
+
146
+
147
+	/**
148
+	 * @return Calculator
149
+	 */
150
+	public function calculator()
151
+	{
152
+		$this->initializeCalculators();
153
+		return $this->calculator;
154
+	}
155
+
156
+
157
+
158
+	/**
159
+	 * loops through a filterable array of Calculator services
160
+	 * and selects the first one that is supported by the current server
161
+	 */
162
+	protected function initializeCalculators()
163
+	{
164
+		if ($this->calculator instanceof Calculator) {
165
+			return;
166
+		}
167
+		$calculators = apply_filters(
168
+			'FHEE__EventEspresso_core_services_currency_MoneyFactory__initializeCalculators__Calculators_array',
169
+			array(
170
+				'EventEspresso\core\services\currency\DefaultCalculator',
171
+			)
172
+		);
173
+		foreach ($calculators as $calculator) {
174
+			if (! class_exists($calculator)) {
175
+				continue;
176
+			}
177
+			$calculator = new $calculator();
178
+			if ($calculator instanceof Calculator && $calculator->isSupported()) {
179
+				$this->calculator = $calculator;
180
+				break;
181
+			}
182
+		}
183
+	}
184 184
 
185 185
 
186 186
 }
Please login to merge, or discard this patch.
core/libraries/payment_methods/EE_PMT_Base.lib.php 2 patches
Spacing   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -118,10 +118,10 @@  discard block
 block discarded – undo
118 118
         MoneyFactory $money_factory = null,
119 119
         CurrencyFactory $currency_factory = null
120 120
     ) {
121
-        if (! $money_factory instanceof  MoneyFactory) {
121
+        if ( ! $money_factory instanceof  MoneyFactory) {
122 122
             $money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
123 123
         }
124
-        if (! $currency_factory instanceof  CurrencyFactory) {
124
+        if ( ! $currency_factory instanceof  CurrencyFactory) {
125 125
             $currency_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\CurrencyFactory');
126 126
         }
127 127
         $this->currency_factory = $currency_factory;
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
             $this->_gateway->set_unsupported_character_remover(new AsciiOnly());
140 140
             do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway);
141 141
         }
142
-        if (!isset($this->_has_billing_form)) {
142
+        if ( ! isset($this->_has_billing_form)) {
143 143
             // by default, On Site gateways have a billing form
144 144
             if ($this->payment_occurs() == EE_PMT_Base::onsite) {
145 145
                 $this->set_has_billing_form(true);
@@ -148,12 +148,12 @@  discard block
 block discarded – undo
148 148
             }
149 149
         }
150 150
 
151
-        if (!$this->_pretty_name) {
151
+        if ( ! $this->_pretty_name) {
152 152
             throw new EE_Error(sprintf(__("You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized", "event_espresso")));
153 153
         }
154 154
         //if the child didn't specify a default button, use the credit card one
155 155
         if ($this->_default_button_url === NULL) {
156
-            $this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods' . DS . 'pay-by-credit-card.png';
156
+            $this->_default_button_url = EE_PLUGIN_DIR_URL.'payment_methods'.DS.'pay-by-credit-card.png';
157 157
         }
158 158
     }
159 159
 
@@ -174,7 +174,7 @@  discard block
 block discarded – undo
174 174
     {
175 175
         $reflector = new ReflectionClass(get_class($this));
176 176
         $fn = $reflector->getFileName();
177
-        $this->_file_folder = dirname($fn) . DS;
177
+        $this->_file_folder = dirname($fn).DS;
178 178
     }
179 179
 
180 180
 
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
      */
206 206
     public function file_folder()
207 207
     {
208
-        if (!$this->_file_folder) {
208
+        if ( ! $this->_file_folder) {
209 209
             $this->_set_file_folder();
210 210
         }
211 211
         return $this->_file_folder;
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
      */
218 218
     public function file_url()
219 219
     {
220
-        if (!$this->_file_url) {
220
+        if ( ! $this->_file_url) {
221 221
             $this->_set_file_url();
222 222
         }
223 223
         return $this->_file_url;
@@ -249,7 +249,7 @@  discard block
 block discarded – undo
249 249
      */
250 250
     function settings_form()
251 251
     {
252
-        if (!$this->_settings_form) {
252
+        if ( ! $this->_settings_form) {
253 253
             $this->_settings_form = $this->generate_new_settings_form();
254 254
             $this->_settings_form->set_payment_method_type($this);
255 255
             //if we have already assigned a model object to this pmt, make
@@ -301,7 +301,7 @@  discard block
 block discarded – undo
301 301
     public function billing_form(EE_Transaction $transaction = NULL, $extra_args = array())
302 302
     {
303 303
         // has billing form already been regenerated ? or overwrite cache?
304
-        if (!$this->_billing_form instanceof EE_Billing_Info_Form || !$this->_cache_billing_form) {
304
+        if ( ! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form) {
305 305
             $this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args);
306 306
         }
307 307
         //if we know who the attendee is, and this is a billing form
@@ -396,7 +396,7 @@  discard block
 block discarded – undo
396 396
             $payment = EEM_Payment::instance()->get_one(array($duplicate_properties));
397 397
             //if we didn't already have a payment in progress for the same thing,
398 398
             //then we actually want to make a new payment
399
-            if (!$payment instanceof EE_Payment) {
399
+            if ( ! $payment instanceof EE_Payment) {
400 400
                 $payment = EE_Payment::new_instance(
401 401
                     array_merge(
402 402
                         $duplicate_properties,
@@ -497,7 +497,7 @@  discard block
 block discarded – undo
497 497
     public function handle_ipn($req_data, $transaction)
498 498
     {
499 499
         $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
500
-        if (!$this->_gateway instanceof EE_Offsite_Gateway) {
500
+        if ( ! $this->_gateway instanceof EE_Offsite_Gateway) {
501 501
             throw new EE_Error(sprintf(__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), print_r($this->_gateway, TRUE)));
502 502
 
503 503
         }
@@ -515,17 +515,17 @@  discard block
 block discarded – undo
515 515
      */
516 516
     protected function _save_billing_info_to_attendee($billing_form, $transaction)
517 517
     {
518
-        if (!$transaction || !$transaction instanceof EE_Transaction) {
518
+        if ( ! $transaction || ! $transaction instanceof EE_Transaction) {
519 519
             EE_Error::add_error(__("Cannot save billing info because no transaction was specified", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
520 520
             return false;
521 521
         }
522 522
         $primary_reg = $transaction->primary_registration();
523
-        if (!$primary_reg) {
523
+        if ( ! $primary_reg) {
524 524
             EE_Error::add_error(__("Cannot save billing info because the transaction has no primary registration", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
525 525
             return false;
526 526
         }
527 527
         $attendee = $primary_reg->attendee();
528
-        if (!$attendee) {
528
+        if ( ! $attendee) {
529 529
             EE_Error::add_error(__("Cannot save billing info because the transaction's primary registration has no attendee!", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
530 530
             return false;
531 531
         }
@@ -625,7 +625,7 @@  discard block
 block discarded – undo
625 625
      */
626 626
     public function payment_occurs()
627 627
     {
628
-        if (!$this->_gateway) {
628
+        if ( ! $this->_gateway) {
629 629
             return EE_PMT_Base::offline;
630 630
         } elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
631 631
             return EE_PMT_Base::onsite;
@@ -646,7 +646,7 @@  discard block
 block discarded – undo
646 646
      */
647 647
     public function payment_overview_content(EE_Payment $payment)
648 648
     {
649
-        return EEH_Template::display_template(EE_LIBRARIES . 'payment_methods' . DS . 'templates' . DS . 'payment_details_content.template.php', array('payment_method' => $this->_pm_instance, 'payment' => $payment), true);
649
+        return EEH_Template::display_template(EE_LIBRARIES.'payment_methods'.DS.'templates'.DS.'payment_details_content.template.php', array('payment_method' => $this->_pm_instance, 'payment' => $payment), true);
650 650
     }
651 651
 
652 652
 
@@ -721,7 +721,7 @@  discard block
 block discarded – undo
721 721
      */
722 722
     public function get_help_tab_name()
723 723
     {
724
-        return 'ee_' . strtolower($this->system_name()) . '_help_tab';
724
+        return 'ee_'.strtolower($this->system_name()).'_help_tab';
725 725
     }
726 726
 
727 727
     /**
@@ -731,7 +731,7 @@  discard block
 block discarded – undo
731 731
      */
732 732
     public function cap_name()
733 733
     {
734
-        return 'ee_payment_method_' . strtolower($this->system_name());
734
+        return 'ee_payment_method_'.strtolower($this->system_name());
735 735
     }
736 736
 
737 737
     /**
@@ -762,7 +762,7 @@  discard block
 block discarded – undo
762 762
      */
763 763
     public function introductory_html()
764 764
     {
765
-        return EEH_Template::locate_template($this->file_folder() . 'templates' . DS . strtolower($this->system_name()) . '_intro.template.php', array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance));
765
+        return EEH_Template::locate_template($this->file_folder().'templates'.DS.strtolower($this->system_name()).'_intro.template.php', array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance));
766 766
     }
767 767
 
768 768
 
Please login to merge, or discard this patch.
Indentation   +757 added lines, -757 removed lines patch added patch discarded remove patch
@@ -29,763 +29,763 @@
 block discarded – undo
29 29
 abstract class EE_PMT_Base
30 30
 {
31 31
 
32
-    const onsite = 'on-site';
33
-    const offsite = 'off-site';
34
-    const offline = 'off-line';
35
-
36
-    /**
37
-     * @var EE_Payment_Method
38
-     */
39
-    protected $_pm_instance = NULL;
40
-
41
-    /**
42
-     * @var boolean
43
-     */
44
-    protected $_requires_https = FALSE;
45
-
46
-    /**
47
-     * @var boolean
48
-     */
49
-    protected $_has_billing_form;
50
-
51
-    /**
52
-     * @var EE_Gateway
53
-     */
54
-    protected $_gateway = NULL;
55
-
56
-    /**
57
-     * @var EE_Payment_Method_Form
58
-     */
59
-    protected $_settings_form = NULL;
60
-
61
-    /**
62
-     * @var EE_Form_Section_Proper
63
-     */
64
-    protected $_billing_form = NULL;
65
-
66
-    /**
67
-     * @var boolean
68
-     */
69
-    protected $_cache_billing_form = TRUE;
70
-
71
-    /**
72
-     * String of the absolute path to the folder containing this file, with a trailing slash.
73
-     * eg '/public_html/wp-site/wp-content/plugins/event-espresso/payment_methods/Invoice/'
74
-     * @var string
75
-     */
76
-    protected $_file_folder = NULL;
77
-
78
-    /**
79
-     * String to the absolute URL to this file (useful for getting its web-accessible resources
80
-     * like images, js, or css)
81
-     * @var string
82
-     */
83
-    protected $_file_url = NULL;
84
-
85
-    /**
86
-     * Pretty name for the payment method
87
-     * @var string
88
-     */
89
-    protected $_pretty_name = NULL;
90
-
91
-    /**
92
-     *
93
-     * @var string
94
-     */
95
-    protected $_default_button_url = NULL;
96
-
97
-    /**
98
-     *
99
-     * @var string
100
-     */
101
-    protected $_default_description = NULL;
102
-
103
-    /**
104
-     * @var MoneyFactory
105
-     */
106
-    protected $money_factory;
107
-
108
-    /**
109
-     * @var CurrencyFactory
110
-     */
111
-    protected $currency_factory;
112
-
113
-
114
-    /**
115
-     *
116
-     * @param EE_Payment_Method $pm_instance
117
-     * @param MoneyFactory|null $money_factory
118
-     * @param CurrencyFactory $currency_factory
119
-     * @throws InvalidArgumentException
120
-     * @throws InvalidInterfaceException
121
-     * @throws InvalidDataTypeException
122
-     * @throws InvalidEntityException
123
-     * @throws EE_Error
124
-     */
125
-    public function __construct(
126
-        $pm_instance = NULL,
127
-        MoneyFactory $money_factory = null,
128
-        CurrencyFactory $currency_factory = null
129
-    ) {
130
-        if (! $money_factory instanceof  MoneyFactory) {
131
-            $money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
132
-        }
133
-        if (! $currency_factory instanceof  CurrencyFactory) {
134
-            $currency_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\CurrencyFactory');
135
-        }
136
-        $this->currency_factory = $currency_factory;
137
-        $this->money_factory = $money_factory;
138
-        if ($pm_instance instanceof EE_Payment_Method) {
139
-            $this->set_instance($pm_instance);
140
-        }
141
-        if ($this->_gateway) {
142
-            $this->_gateway->set_payment_model(EEM_Payment::instance());
143
-            $this->_gateway->set_payment_log(EEM_Change_Log::instance());
144
-            $this->_gateway->set_template_helper(new EEH_Template());
145
-            $this->_gateway->set_line_item_helper(new EEH_Line_Item());
146
-            $this->_gateway->set_money_helper(new EEH_Money());
147
-            $this->_gateway->set_gateway_data_formatter(new GatewayDataFormatter());
148
-            $this->_gateway->set_unsupported_character_remover(new AsciiOnly());
149
-            do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway);
150
-        }
151
-        if (!isset($this->_has_billing_form)) {
152
-            // by default, On Site gateways have a billing form
153
-            if ($this->payment_occurs() == EE_PMT_Base::onsite) {
154
-                $this->set_has_billing_form(true);
155
-            } else {
156
-                $this->set_has_billing_form(false);
157
-            }
158
-        }
159
-
160
-        if (!$this->_pretty_name) {
161
-            throw new EE_Error(sprintf(__("You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized", "event_espresso")));
162
-        }
163
-        //if the child didn't specify a default button, use the credit card one
164
-        if ($this->_default_button_url === NULL) {
165
-            $this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods' . DS . 'pay-by-credit-card.png';
166
-        }
167
-    }
168
-
169
-
170
-    /**
171
-     * @param boolean $has_billing_form
172
-     */
173
-    public function set_has_billing_form($has_billing_form)
174
-    {
175
-        $this->_has_billing_form = filter_var($has_billing_form, FILTER_VALIDATE_BOOLEAN);
176
-    }
177
-
178
-
179
-    /**
180
-     * sets the file_folder property
181
-     * @throws ReflectionException
182
-     */
183
-    protected function _set_file_folder()
184
-    {
185
-        $reflector = new ReflectionClass(get_class($this));
186
-        $fn = $reflector->getFileName();
187
-        $this->_file_folder = dirname($fn) . DS;
188
-    }
189
-
190
-
191
-    /**
192
-     * sets the file URL with a trailing slash for this PMT
193
-     */
194
-    protected function _set_file_url()
195
-    {
196
-        $plugins_dir_fixed = str_replace('\\', DS, WP_PLUGIN_DIR);
197
-        $file_folder_fixed = str_replace('\\', DS, $this->file_folder());
198
-        $file_path = str_replace($plugins_dir_fixed, WP_PLUGIN_URL, $file_folder_fixed);
199
-        $this->_file_url = $file_path;
200
-    }
201
-
202
-    /**
203
-     * Gets the default description on all payment methods of this type
204
-     * @return string
205
-     */
206
-    public function default_description()
207
-    {
208
-        return $this->_default_description;
209
-    }
210
-
211
-
212
-    /**
213
-     * Returns the folder containing the PMT child class, with a trailing slash
214
-     * @return string
215
-     */
216
-    public function file_folder()
217
-    {
218
-        if (!$this->_file_folder) {
219
-            $this->_set_file_folder();
220
-        }
221
-        return $this->_file_folder;
222
-    }
223
-
224
-
225
-    /**
226
-     * @return string
227
-     */
228
-    public function file_url()
229
-    {
230
-        if (!$this->_file_url) {
231
-            $this->_set_file_url();
232
-        }
233
-        return $this->_file_url;
234
-    }
235
-
236
-
237
-    /**
238
-     * Sets the payment method instance this payment method type is for.
239
-     * Its important teh payment method instance is set before
240
-     * @param EE_Payment_Method $payment_method_instance
241
-     */
242
-    function set_instance($payment_method_instance)
243
-    {
244
-        $this->_pm_instance = $payment_method_instance;
245
-        //if they have already requested the settings form, make sure its
246
-        //data matches this model object
247
-        if ($this->_settings_form) {
248
-            $this->settings_form()->populate_model_obj($payment_method_instance);
249
-        }
250
-        if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
251
-            $this->_gateway->set_settings($payment_method_instance->settings_array());
252
-        }
253
-    }
254
-
255
-
256
-    /**
257
-     * Gets teh form for displaying to admins where they setup the payment method
258
-     * @return EE_Payment_Method_Form
259
-     * @throws EE_Error
260
-     */
261
-    function settings_form()
262
-    {
263
-        if (!$this->_settings_form) {
264
-            $this->_settings_form = $this->generate_new_settings_form();
265
-            $this->_settings_form->set_payment_method_type($this);
266
-            //if we have already assigned a model object to this pmt, make
267
-            //sure its reflected in teh form we just generated
268
-            if ($this->_pm_instance) {
269
-                $this->_settings_form->populate_model_obj($this->_pm_instance);
270
-            }
271
-        }
272
-        return $this->_settings_form;
273
-    }
274
-
275
-
276
-    /**
277
-     * Gets the form for all the settings related to this payment method type
278
-     * @return EE_Payment_Method_Form
279
-     */
280
-    abstract function generate_new_settings_form();
281
-
282
-
283
-    /**
284
-     * Sets the form for settings. This may be useful if we have already received
285
-     * a form submission and have form data it in, and want to use it anytime we're showing
286
-     * this payment method type's settings form later in the request
287
-     * @param EE_Payment_Method_Form $form
288
-     */
289
-    public function set_settings_form($form)
290
-    {
291
-        $this->_settings_form = $form;
292
-    }
293
-
294
-
295
-    /**
296
-     * @return boolean
297
-     */
298
-    public function has_billing_form()
299
-    {
300
-        return $this->_has_billing_form;
301
-    }
302
-
303
-
304
-    /**
305
-     * Gets the form for displaying to attendees where they can enter their billing info
306
-     * which will be sent to teh gateway (can be null)
307
-     *
308
-     * @param EE_Transaction $transaction
309
-     * @param array $extra_args
310
-     * @return EE_Billing_Attendee_Info_Form|EE_Billing_Info_Form|null
311
-     * @throws EE_Error
312
-     */
313
-    public function billing_form(EE_Transaction $transaction = NULL, $extra_args = array())
314
-    {
315
-        // has billing form already been regenerated ? or overwrite cache?
316
-        if (!$this->_billing_form instanceof EE_Billing_Info_Form || !$this->_cache_billing_form) {
317
-            $this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args);
318
-        }
319
-        //if we know who the attendee is, and this is a billing form
320
-        //that uses attendee info, populate it
321
-        if (
322
-        apply_filters(
323
-            'FHEE__populate_billing_form_fields_from_attendee',
324
-            (
325
-                $this->_billing_form instanceof EE_Billing_Attendee_Info_Form
326
-                && $transaction instanceof EE_Transaction
327
-                && $transaction->primary_registration() instanceof EE_Registration
328
-                && $transaction->primary_registration()->attendee() instanceof EE_Attendee
329
-            ),
330
-            $this->_billing_form,
331
-            $transaction
332
-        )
333
-        ) {
334
-            $this->_billing_form->populate_from_attendee($transaction->primary_registration()->attendee());
335
-        }
336
-        return $this->_billing_form;
337
-    }
338
-
339
-
340
-    /**
341
-     * Creates the billing form for this payment method type
342
-     * @param EE_Transaction $transaction
343
-     * @return EE_Billing_Info_Form
344
-     */
345
-    abstract function generate_new_billing_form(EE_Transaction $transaction = NULL);
346
-
347
-
348
-    /**
349
-     * apply_billing_form_debug_settings
350
-     * applies debug data to the form
351
-     *
352
-     * @param EE_Billing_Info_Form $billing_form
353
-     * @return EE_Billing_Info_Form
354
-     */
355
-    public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form)
356
-    {
357
-        return $billing_form;
358
-    }
359
-
360
-
361
-    /**
362
-     * Sets the billing form for this payment method type. You may want to use this
363
-     * if you have form
364
-     * @param EE_Payment_Method $form
365
-     */
366
-    public function set_billing_form($form)
367
-    {
368
-        $this->_billing_form = $form;
369
-    }
370
-
371
-
372
-    /**
373
-     * Returns whether or not this payment method requires HTTPS to be used
374
-     * @return boolean
375
-     */
376
-    function requires_https()
377
-    {
378
-        return $this->_requires_https;
379
-    }
380
-
381
-
382
-    /**
383
-     *
384
-     * @param EE_Transaction $transaction
385
-     * @param float $amount
386
-     * @param EE_Billing_Info_Form $billing_info
387
-     * @param string $return_url
388
-     * @param string $fail_url
389
-     * @param string $method
390
-     * @param bool $by_admin
391
-     * @return EE_Payment
392
-     * @throws InvalidArgumentException
393
-     * @throws InvalidInterfaceException
394
-     * @throws InvalidDataTypeException
395
-     * @throws EE_Error
396
-     */
397
-    function process_payment(EE_Transaction $transaction, $amount = null, $billing_info = null, $return_url = null, $fail_url = '', $method = 'CART', $by_admin = false)
398
-    {
399
-        // @todo: add surcharge for the payment method, if any
400
-        if ($this->_gateway) {
401
-            //there is a gateway, so we're going to make a payment object
402
-            //but wait! do they already have a payment in progress that we thought was failed?
403
-            $duplicate_properties = array(
404
-                'STS_ID' => EEM_Payment::status_id_failed,
405
-                'TXN_ID' => $transaction->ID(),
406
-                'PMD_ID' => $this->_pm_instance->ID(),
407
-                'PAY_source' => $method,
408
-                'PAY_amount' => $amount !== null ? $amount : $transaction->remaining(),
409
-                'PAY_gateway_response' => null,
410
-            );
411
-            $payment = EEM_Payment::instance()->get_one(array($duplicate_properties));
412
-            //if we didn't already have a payment in progress for the same thing,
413
-            //then we actually want to make a new payment
414
-            if (!$payment instanceof EE_Payment) {
415
-                $payment = EE_Payment::new_instance(
416
-                    array_merge(
417
-                        $duplicate_properties,
418
-                        array(
419
-                            'PAY_timestamp' => time(),
420
-                            'PAY_txn_id_chq_nmbr' => null,
421
-                            'PAY_po_number' => null,
422
-                            'PAY_extra_accntng' => null,
423
-                            'PAY_details' => null,
424
-                        )
425
-                    )
426
-                );
427
-            }
428
-            //make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it
429
-            $payment->save();
430
-            $billing_values = $this->_get_billing_values_from_form($billing_info);
431
-
432
-            //  Offsite Gateway
433
-            if ($this->_gateway instanceof EE_Offsite_Gateway) {
434
-
435
-                $payment = $this->_gateway->set_redirection_info(
436
-                    $payment,
437
-                    $billing_values,
438
-                    $return_url,
439
-                    EE_Config::instance()->core->txn_page_url(
440
-                        array(
441
-                            'e_reg_url_link' => $transaction->primary_registration()->reg_url_link(),
442
-                            'ee_payment_method' => $this->_pm_instance->slug()
443
-                        )
444
-                    ),
445
-                    $fail_url
446
-                );
447
-                $payment->save();
448
-                //  Onsite Gateway
449
-            } elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
450
-
451
-                $payment = $this->_gateway->do_direct_payment($payment, $billing_values);
452
-                $payment->save();
453
-
454
-            } else {
455
-                throw new EE_Error(
456
-                    sprintf(
457
-                        __('Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)', 'event_espresso'),
458
-                        get_class($this),
459
-                        gettype($this->_gateway)
460
-                    )
461
-                );
462
-            }
463
-
464
-        } else {
465
-            // no gateway provided
466
-            // there is no payment. Must be an offline gateway
467
-            // create a payment object anyways, but dont save it
468
-            $payment = EE_Payment::new_instance(
469
-                array(
470
-                    'STS_ID' => EEM_Payment::status_id_pending,
471
-                    'TXN_ID' => $transaction->ID(),
472
-                    'PMD_ID' => $transaction->payment_method_ID(),
473
-                    'PAY_amount' => 0.00,
474
-                    'PAY_timestamp' => time(),
475
-                )
476
-            );
477
-
478
-        }
479
-
480
-        // if there is billing info, clean it and save it now
481
-        if ($billing_info instanceof EE_Billing_Attendee_Info_Form) {
482
-            $this->_save_billing_info_to_attendee($billing_info, $transaction);
483
-        }
484
-
485
-        return $payment;
486
-    }
487
-
488
-    /**
489
-     * Gets the values we want to pass onto the gateway. Normally these
490
-     * are just the 'pretty' values, but there may be times the data may need
491
-     * a  little massaging. Proper subsections will become arrays of inputs
492
-     * @param EE_Billing_Info_Form $billing_form
493
-     * @return array
494
-     */
495
-    protected function _get_billing_values_from_form($billing_form)
496
-    {
497
-        if ($billing_form instanceof EE_Form_Section_Proper) {
498
-            return $billing_form->input_pretty_values(true);
499
-        } else {
500
-            return NULL;
501
-        }
502
-    }
503
-
504
-
505
-    /**
506
-     * Handles an instant payment notification when the transaction is known (by default).
507
-     * @param array $req_data
508
-     * @param EE_Transaction $transaction
509
-     * @return EE_Payment
510
-     * @throws InvalidArgumentException
511
-     * @throws InvalidInterfaceException
512
-     * @throws InvalidDataTypeException
513
-     * @throws EE_Error
514
-     */
515
-    public function handle_ipn($req_data, $transaction)
516
-    {
517
-        $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
518
-        if (!$this->_gateway instanceof EE_Offsite_Gateway) {
519
-            throw new EE_Error(sprintf(__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), print_r($this->_gateway, TRUE)));
520
-
521
-        }
522
-        $payment = $this->_gateway->handle_payment_update($req_data, $transaction);
523
-        return $payment;
524
-    }
525
-
526
-
527
-    /**
528
-     * Saves the billing info onto the attendee of the primary registrant on this transaction, and
529
-     * cleans it first.
530
-     * @param EE_Billing_Attendee_Info_Form $billing_form
531
-     * @param EE_Transaction $transaction
532
-     * @return boolean success
533
-     * @throws EE_Error
534
-     */
535
-    protected function _save_billing_info_to_attendee($billing_form, $transaction)
536
-    {
537
-        if (!$transaction || !$transaction instanceof EE_Transaction) {
538
-            EE_Error::add_error(__("Cannot save billing info because no transaction was specified", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
539
-            return false;
540
-        }
541
-        $primary_reg = $transaction->primary_registration();
542
-        if (!$primary_reg) {
543
-            EE_Error::add_error(__("Cannot save billing info because the transaction has no primary registration", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
544
-            return false;
545
-        }
546
-        $attendee = $primary_reg->attendee();
547
-        if (!$attendee) {
548
-            EE_Error::add_error(__("Cannot save billing info because the transaction's primary registration has no attendee!", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
549
-            return false;
550
-        }
551
-        return $attendee->save_and_clean_billing_info_for_payment_method($billing_form, $transaction->payment_method());
552
-
553
-    }
554
-
555
-
556
-    /**
557
-     * Gets the payment this IPN is for. Children may often want to
558
-     * override this to inspect the request
559
-     * @param EE_Transaction $transaction
560
-     * @param array $req_data
561
-     * @return EE_Payment
562
-     * @throws EE_Error
563
-     */
564
-    protected function find_payment_for_ipn(EE_Transaction $transaction, $req_data = array())
565
-    {
566
-        return $transaction->last_payment();
567
-    }
568
-
569
-
570
-    /**
571
-     * In case generic code cannot provide the payment processor with a specific payment method
572
-     * and transaction, it will try calling this method on each activate payment method.
573
-     * If the payment method is able to identify the request as being for it, it should fetch
574
-     * the payment its for and return it. If not, it should throw an EE_Error to indicate it cannot
575
-     * handle the IPN
576
-     * @param array $req_data
577
-     * @return EE_Payment only if this payment method can find the info its needs from $req_data
578
-     * and identifies the IPN as being for this payment method (not just fo ra payment method of this type)
579
-     * @throws EE_Error
580
-     */
581
-    public function handle_unclaimed_ipn($req_data = array())
582
-    {
583
-        throw new EE_Error(sprintf(__("Payment Method '%s' cannot handle unclaimed IPNs", "event_espresso"), get_class($this)));
584
-    }
585
-
586
-
587
-    /**
588
-     * Logic to be accomplished when the payment attempt is complete.
589
-     * Most payment methods don't need to do anything at this point; but some, like Mijireh, do.
590
-     * (Mijireh is an offsite gateway which doesn't send an IPN. So when the user returns to EE from
591
-     * mijireh, this method needs to be called so the Mijireh PM can ping Mijireh to know the status
592
-     * of the payment). Fed a transaction because it's always assumed to be the last payment that
593
-     * we're dealing with. Returns that last payment (if there is one)
594
-     *
595
-     * @param EE_Transaction $transaction
596
-     * @return EE_Payment
597
-     * @throws EE_Error
598
-     */
599
-    public function finalize_payment_for($transaction)
600
-    {
601
-        return $transaction->last_payment();
602
-    }
603
-
604
-
605
-    /**
606
-     * Whether or not this payment method's gateway supports sending refund requests
607
-     * @return boolean
608
-     */
609
-    public function supports_sending_refunds()
610
-    {
611
-        if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
612
-            return $this->_gateway->supports_sending_refunds();
613
-        } else {
614
-            return false;
615
-        }
616
-    }
617
-
618
-
619
-    /**
620
-     *
621
-     * @param EE_Payment $payment
622
-     * @param array $refund_info
623
-     * @throws EE_Error
624
-     * @return EE_Payment
625
-     */
626
-    public function process_refund(EE_Payment $payment, $refund_info = array())
627
-    {
628
-        if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
629
-            return $this->_gateway->do_direct_refund($payment, $refund_info);
630
-        } else {
631
-            throw new EE_Error(
632
-                sprintf(
633
-                    __('Payment Method Type "%s" does not support sending refund requests', 'event_espresso'),
634
-                    get_class($this)
635
-                )
636
-            );
637
-        }
638
-    }
639
-
640
-
641
-    /**
642
-     * Returns one the class's constants onsite,offsite, or offline, depending on this
643
-     * payment method's gateway.
644
-     * @return string
645
-     * @throws EE_Error
646
-     */
647
-    public function payment_occurs()
648
-    {
649
-        if (!$this->_gateway) {
650
-            return EE_PMT_Base::offline;
651
-        } elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
652
-            return EE_PMT_Base::onsite;
653
-        } elseif ($this->_gateway instanceof EE_Offsite_Gateway) {
654
-            return EE_PMT_Base::offsite;
655
-        } else {
656
-            throw new EE_Error(sprintf(__("Payment method type '%s's gateway isn't an instance of EE_Onsite_Gateway, EE_Offsite_Gateway, or null. It must be one of those", "event_espresso"), get_class($this)));
657
-        }
658
-    }
659
-
660
-
661
-    /**
662
-     * For adding any html output ab ove the payment overview.
663
-     * Many gateways won't want ot display anything, so this function just returns an empty string.
664
-     * Other gateways may want to override this, such as offline gateways.
665
-     * @param EE_Payment $payment
666
-     * @return string
667
-     * @throws \DomainException
668
-     */
669
-    public function payment_overview_content(EE_Payment $payment)
670
-    {
671
-        return EEH_Template::display_template(EE_LIBRARIES . 'payment_methods' . DS . 'templates' . DS . 'payment_details_content.template.php', array('payment_method' => $this->_pm_instance, 'payment' => $payment), true);
672
-    }
673
-
674
-
675
-    /**
676
-     * @return array where keys are the help tab name,
677
-     * values are: array {
678
-     * @type string $title i18n name for the help tab
679
-     * @type string $filename name of the file located in ./help_tabs/ (ie, in a folder next to this file)
680
-     * @type array $template_args any arguments you want passed to the template file while rendering.
681
-     *                Keys will be variable names and values with be their values.
682
-     */
683
-    public function help_tabs_config()
684
-    {
685
-        return array();
686
-    }
687
-
688
-
689
-    /**
690
-     * The system name for this PMT (eg AIM, Paypal_Pro, Invoice... what gets put into
691
-     * the payment method's table's PMT_type column)
692
-     * @return string
693
-     */
694
-    public function system_name()
695
-    {
696
-        $classname = get_class($this);
697
-        return str_replace("EE_PMT_", '', $classname);
698
-    }
699
-
700
-
701
-    /**
702
-     * A pretty i18n version of the PMT name
703
-     * @return string
704
-     */
705
-    public function pretty_name()
706
-    {
707
-        return $this->_pretty_name;
708
-    }
709
-
710
-
711
-    /**
712
-     * Gets the default absolute URL to the payment method type's button
713
-     * @return string
714
-     */
715
-    public function default_button_url()
716
-    {
717
-        return $this->_default_button_url;
718
-    }
719
-
720
-
721
-    /**
722
-     * Gets the gateway used by this payment method (if any)
723
-     * @return EE_Gateway
724
-     */
725
-    public function get_gateway()
726
-    {
727
-        return $this->_gateway;
728
-    }
729
-
730
-
731
-    /**
732
-     * @return string html for the link to a help tab
733
-     */
734
-    public function get_help_tab_link()
735
-    {
736
-        return EEH_Template::get_help_tab_link($this->get_help_tab_name());
737
-    }
738
-
739
-
740
-    /**
741
-     * Returns the name of the help tab for this PMT
742
-     * @return string
743
-     */
744
-    public function get_help_tab_name()
745
-    {
746
-        return 'ee_' . strtolower($this->system_name()) . '_help_tab';
747
-    }
748
-
749
-    /**
750
-     * The name of the wp capability that should be associated with the usage of
751
-     * this PMT by an admin
752
-     * @return string
753
-     */
754
-    public function cap_name()
755
-    {
756
-        return 'ee_payment_method_' . strtolower($this->system_name());
757
-    }
758
-
759
-    /**
760
-     * Called by client code to tell the gateway that if it wants to change
761
-     * the transaction or line items or registrations related to teh payment it already
762
-     * processed (we think, but possibly not) that now's the time to do it.
763
-     * It is expected that gateways will store any info they need for this on the PAY_details,
764
-     * or maybe an extra meta value
765
-     * @param EE_Payment $payment
766
-     * @return void
767
-     */
768
-    public function update_txn_based_on_payment($payment)
769
-    {
770
-        if ($this->_gateway instanceof EE_Gateway) {
771
-            $this->_gateway->update_txn_based_on_payment($payment);
772
-        }
773
-    }
774
-
775
-    /**
776
-     * Returns a string of HTML describing this payment method type for an admin,
777
-     * primarily intended for them to read before activating it.
778
-     * The easiest way to set this is to create a folder 'templates' alongside
779
-     * your EE_PMT_{System_Name} file, and in it create a file named "{system_name}_intro.template.php".
780
-     * Eg, if your payment method file is named "EE_PMT_Foo_Bar.pm.php",
781
-     * then you'd create a file named "templates" in the same folder as it, and name the file
782
-     * "foo_bar_intro.template.php", and its content will be returned by this method
783
-     * @return string
784
-     */
785
-    public function introductory_html()
786
-    {
787
-        return EEH_Template::locate_template($this->file_folder() . 'templates' . DS . strtolower($this->system_name()) . '_intro.template.php', array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance));
788
-    }
32
+	const onsite = 'on-site';
33
+	const offsite = 'off-site';
34
+	const offline = 'off-line';
35
+
36
+	/**
37
+	 * @var EE_Payment_Method
38
+	 */
39
+	protected $_pm_instance = NULL;
40
+
41
+	/**
42
+	 * @var boolean
43
+	 */
44
+	protected $_requires_https = FALSE;
45
+
46
+	/**
47
+	 * @var boolean
48
+	 */
49
+	protected $_has_billing_form;
50
+
51
+	/**
52
+	 * @var EE_Gateway
53
+	 */
54
+	protected $_gateway = NULL;
55
+
56
+	/**
57
+	 * @var EE_Payment_Method_Form
58
+	 */
59
+	protected $_settings_form = NULL;
60
+
61
+	/**
62
+	 * @var EE_Form_Section_Proper
63
+	 */
64
+	protected $_billing_form = NULL;
65
+
66
+	/**
67
+	 * @var boolean
68
+	 */
69
+	protected $_cache_billing_form = TRUE;
70
+
71
+	/**
72
+	 * String of the absolute path to the folder containing this file, with a trailing slash.
73
+	 * eg '/public_html/wp-site/wp-content/plugins/event-espresso/payment_methods/Invoice/'
74
+	 * @var string
75
+	 */
76
+	protected $_file_folder = NULL;
77
+
78
+	/**
79
+	 * String to the absolute URL to this file (useful for getting its web-accessible resources
80
+	 * like images, js, or css)
81
+	 * @var string
82
+	 */
83
+	protected $_file_url = NULL;
84
+
85
+	/**
86
+	 * Pretty name for the payment method
87
+	 * @var string
88
+	 */
89
+	protected $_pretty_name = NULL;
90
+
91
+	/**
92
+	 *
93
+	 * @var string
94
+	 */
95
+	protected $_default_button_url = NULL;
96
+
97
+	/**
98
+	 *
99
+	 * @var string
100
+	 */
101
+	protected $_default_description = NULL;
102
+
103
+	/**
104
+	 * @var MoneyFactory
105
+	 */
106
+	protected $money_factory;
107
+
108
+	/**
109
+	 * @var CurrencyFactory
110
+	 */
111
+	protected $currency_factory;
112
+
113
+
114
+	/**
115
+	 *
116
+	 * @param EE_Payment_Method $pm_instance
117
+	 * @param MoneyFactory|null $money_factory
118
+	 * @param CurrencyFactory $currency_factory
119
+	 * @throws InvalidArgumentException
120
+	 * @throws InvalidInterfaceException
121
+	 * @throws InvalidDataTypeException
122
+	 * @throws InvalidEntityException
123
+	 * @throws EE_Error
124
+	 */
125
+	public function __construct(
126
+		$pm_instance = NULL,
127
+		MoneyFactory $money_factory = null,
128
+		CurrencyFactory $currency_factory = null
129
+	) {
130
+		if (! $money_factory instanceof  MoneyFactory) {
131
+			$money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
132
+		}
133
+		if (! $currency_factory instanceof  CurrencyFactory) {
134
+			$currency_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\CurrencyFactory');
135
+		}
136
+		$this->currency_factory = $currency_factory;
137
+		$this->money_factory = $money_factory;
138
+		if ($pm_instance instanceof EE_Payment_Method) {
139
+			$this->set_instance($pm_instance);
140
+		}
141
+		if ($this->_gateway) {
142
+			$this->_gateway->set_payment_model(EEM_Payment::instance());
143
+			$this->_gateway->set_payment_log(EEM_Change_Log::instance());
144
+			$this->_gateway->set_template_helper(new EEH_Template());
145
+			$this->_gateway->set_line_item_helper(new EEH_Line_Item());
146
+			$this->_gateway->set_money_helper(new EEH_Money());
147
+			$this->_gateway->set_gateway_data_formatter(new GatewayDataFormatter());
148
+			$this->_gateway->set_unsupported_character_remover(new AsciiOnly());
149
+			do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway);
150
+		}
151
+		if (!isset($this->_has_billing_form)) {
152
+			// by default, On Site gateways have a billing form
153
+			if ($this->payment_occurs() == EE_PMT_Base::onsite) {
154
+				$this->set_has_billing_form(true);
155
+			} else {
156
+				$this->set_has_billing_form(false);
157
+			}
158
+		}
159
+
160
+		if (!$this->_pretty_name) {
161
+			throw new EE_Error(sprintf(__("You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized", "event_espresso")));
162
+		}
163
+		//if the child didn't specify a default button, use the credit card one
164
+		if ($this->_default_button_url === NULL) {
165
+			$this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods' . DS . 'pay-by-credit-card.png';
166
+		}
167
+	}
168
+
169
+
170
+	/**
171
+	 * @param boolean $has_billing_form
172
+	 */
173
+	public function set_has_billing_form($has_billing_form)
174
+	{
175
+		$this->_has_billing_form = filter_var($has_billing_form, FILTER_VALIDATE_BOOLEAN);
176
+	}
177
+
178
+
179
+	/**
180
+	 * sets the file_folder property
181
+	 * @throws ReflectionException
182
+	 */
183
+	protected function _set_file_folder()
184
+	{
185
+		$reflector = new ReflectionClass(get_class($this));
186
+		$fn = $reflector->getFileName();
187
+		$this->_file_folder = dirname($fn) . DS;
188
+	}
189
+
190
+
191
+	/**
192
+	 * sets the file URL with a trailing slash for this PMT
193
+	 */
194
+	protected function _set_file_url()
195
+	{
196
+		$plugins_dir_fixed = str_replace('\\', DS, WP_PLUGIN_DIR);
197
+		$file_folder_fixed = str_replace('\\', DS, $this->file_folder());
198
+		$file_path = str_replace($plugins_dir_fixed, WP_PLUGIN_URL, $file_folder_fixed);
199
+		$this->_file_url = $file_path;
200
+	}
201
+
202
+	/**
203
+	 * Gets the default description on all payment methods of this type
204
+	 * @return string
205
+	 */
206
+	public function default_description()
207
+	{
208
+		return $this->_default_description;
209
+	}
210
+
211
+
212
+	/**
213
+	 * Returns the folder containing the PMT child class, with a trailing slash
214
+	 * @return string
215
+	 */
216
+	public function file_folder()
217
+	{
218
+		if (!$this->_file_folder) {
219
+			$this->_set_file_folder();
220
+		}
221
+		return $this->_file_folder;
222
+	}
223
+
224
+
225
+	/**
226
+	 * @return string
227
+	 */
228
+	public function file_url()
229
+	{
230
+		if (!$this->_file_url) {
231
+			$this->_set_file_url();
232
+		}
233
+		return $this->_file_url;
234
+	}
235
+
236
+
237
+	/**
238
+	 * Sets the payment method instance this payment method type is for.
239
+	 * Its important teh payment method instance is set before
240
+	 * @param EE_Payment_Method $payment_method_instance
241
+	 */
242
+	function set_instance($payment_method_instance)
243
+	{
244
+		$this->_pm_instance = $payment_method_instance;
245
+		//if they have already requested the settings form, make sure its
246
+		//data matches this model object
247
+		if ($this->_settings_form) {
248
+			$this->settings_form()->populate_model_obj($payment_method_instance);
249
+		}
250
+		if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
251
+			$this->_gateway->set_settings($payment_method_instance->settings_array());
252
+		}
253
+	}
254
+
255
+
256
+	/**
257
+	 * Gets teh form for displaying to admins where they setup the payment method
258
+	 * @return EE_Payment_Method_Form
259
+	 * @throws EE_Error
260
+	 */
261
+	function settings_form()
262
+	{
263
+		if (!$this->_settings_form) {
264
+			$this->_settings_form = $this->generate_new_settings_form();
265
+			$this->_settings_form->set_payment_method_type($this);
266
+			//if we have already assigned a model object to this pmt, make
267
+			//sure its reflected in teh form we just generated
268
+			if ($this->_pm_instance) {
269
+				$this->_settings_form->populate_model_obj($this->_pm_instance);
270
+			}
271
+		}
272
+		return $this->_settings_form;
273
+	}
274
+
275
+
276
+	/**
277
+	 * Gets the form for all the settings related to this payment method type
278
+	 * @return EE_Payment_Method_Form
279
+	 */
280
+	abstract function generate_new_settings_form();
281
+
282
+
283
+	/**
284
+	 * Sets the form for settings. This may be useful if we have already received
285
+	 * a form submission and have form data it in, and want to use it anytime we're showing
286
+	 * this payment method type's settings form later in the request
287
+	 * @param EE_Payment_Method_Form $form
288
+	 */
289
+	public function set_settings_form($form)
290
+	{
291
+		$this->_settings_form = $form;
292
+	}
293
+
294
+
295
+	/**
296
+	 * @return boolean
297
+	 */
298
+	public function has_billing_form()
299
+	{
300
+		return $this->_has_billing_form;
301
+	}
302
+
303
+
304
+	/**
305
+	 * Gets the form for displaying to attendees where they can enter their billing info
306
+	 * which will be sent to teh gateway (can be null)
307
+	 *
308
+	 * @param EE_Transaction $transaction
309
+	 * @param array $extra_args
310
+	 * @return EE_Billing_Attendee_Info_Form|EE_Billing_Info_Form|null
311
+	 * @throws EE_Error
312
+	 */
313
+	public function billing_form(EE_Transaction $transaction = NULL, $extra_args = array())
314
+	{
315
+		// has billing form already been regenerated ? or overwrite cache?
316
+		if (!$this->_billing_form instanceof EE_Billing_Info_Form || !$this->_cache_billing_form) {
317
+			$this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args);
318
+		}
319
+		//if we know who the attendee is, and this is a billing form
320
+		//that uses attendee info, populate it
321
+		if (
322
+		apply_filters(
323
+			'FHEE__populate_billing_form_fields_from_attendee',
324
+			(
325
+				$this->_billing_form instanceof EE_Billing_Attendee_Info_Form
326
+				&& $transaction instanceof EE_Transaction
327
+				&& $transaction->primary_registration() instanceof EE_Registration
328
+				&& $transaction->primary_registration()->attendee() instanceof EE_Attendee
329
+			),
330
+			$this->_billing_form,
331
+			$transaction
332
+		)
333
+		) {
334
+			$this->_billing_form->populate_from_attendee($transaction->primary_registration()->attendee());
335
+		}
336
+		return $this->_billing_form;
337
+	}
338
+
339
+
340
+	/**
341
+	 * Creates the billing form for this payment method type
342
+	 * @param EE_Transaction $transaction
343
+	 * @return EE_Billing_Info_Form
344
+	 */
345
+	abstract function generate_new_billing_form(EE_Transaction $transaction = NULL);
346
+
347
+
348
+	/**
349
+	 * apply_billing_form_debug_settings
350
+	 * applies debug data to the form
351
+	 *
352
+	 * @param EE_Billing_Info_Form $billing_form
353
+	 * @return EE_Billing_Info_Form
354
+	 */
355
+	public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form)
356
+	{
357
+		return $billing_form;
358
+	}
359
+
360
+
361
+	/**
362
+	 * Sets the billing form for this payment method type. You may want to use this
363
+	 * if you have form
364
+	 * @param EE_Payment_Method $form
365
+	 */
366
+	public function set_billing_form($form)
367
+	{
368
+		$this->_billing_form = $form;
369
+	}
370
+
371
+
372
+	/**
373
+	 * Returns whether or not this payment method requires HTTPS to be used
374
+	 * @return boolean
375
+	 */
376
+	function requires_https()
377
+	{
378
+		return $this->_requires_https;
379
+	}
380
+
381
+
382
+	/**
383
+	 *
384
+	 * @param EE_Transaction $transaction
385
+	 * @param float $amount
386
+	 * @param EE_Billing_Info_Form $billing_info
387
+	 * @param string $return_url
388
+	 * @param string $fail_url
389
+	 * @param string $method
390
+	 * @param bool $by_admin
391
+	 * @return EE_Payment
392
+	 * @throws InvalidArgumentException
393
+	 * @throws InvalidInterfaceException
394
+	 * @throws InvalidDataTypeException
395
+	 * @throws EE_Error
396
+	 */
397
+	function process_payment(EE_Transaction $transaction, $amount = null, $billing_info = null, $return_url = null, $fail_url = '', $method = 'CART', $by_admin = false)
398
+	{
399
+		// @todo: add surcharge for the payment method, if any
400
+		if ($this->_gateway) {
401
+			//there is a gateway, so we're going to make a payment object
402
+			//but wait! do they already have a payment in progress that we thought was failed?
403
+			$duplicate_properties = array(
404
+				'STS_ID' => EEM_Payment::status_id_failed,
405
+				'TXN_ID' => $transaction->ID(),
406
+				'PMD_ID' => $this->_pm_instance->ID(),
407
+				'PAY_source' => $method,
408
+				'PAY_amount' => $amount !== null ? $amount : $transaction->remaining(),
409
+				'PAY_gateway_response' => null,
410
+			);
411
+			$payment = EEM_Payment::instance()->get_one(array($duplicate_properties));
412
+			//if we didn't already have a payment in progress for the same thing,
413
+			//then we actually want to make a new payment
414
+			if (!$payment instanceof EE_Payment) {
415
+				$payment = EE_Payment::new_instance(
416
+					array_merge(
417
+						$duplicate_properties,
418
+						array(
419
+							'PAY_timestamp' => time(),
420
+							'PAY_txn_id_chq_nmbr' => null,
421
+							'PAY_po_number' => null,
422
+							'PAY_extra_accntng' => null,
423
+							'PAY_details' => null,
424
+						)
425
+					)
426
+				);
427
+			}
428
+			//make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it
429
+			$payment->save();
430
+			$billing_values = $this->_get_billing_values_from_form($billing_info);
431
+
432
+			//  Offsite Gateway
433
+			if ($this->_gateway instanceof EE_Offsite_Gateway) {
434
+
435
+				$payment = $this->_gateway->set_redirection_info(
436
+					$payment,
437
+					$billing_values,
438
+					$return_url,
439
+					EE_Config::instance()->core->txn_page_url(
440
+						array(
441
+							'e_reg_url_link' => $transaction->primary_registration()->reg_url_link(),
442
+							'ee_payment_method' => $this->_pm_instance->slug()
443
+						)
444
+					),
445
+					$fail_url
446
+				);
447
+				$payment->save();
448
+				//  Onsite Gateway
449
+			} elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
450
+
451
+				$payment = $this->_gateway->do_direct_payment($payment, $billing_values);
452
+				$payment->save();
453
+
454
+			} else {
455
+				throw new EE_Error(
456
+					sprintf(
457
+						__('Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)', 'event_espresso'),
458
+						get_class($this),
459
+						gettype($this->_gateway)
460
+					)
461
+				);
462
+			}
463
+
464
+		} else {
465
+			// no gateway provided
466
+			// there is no payment. Must be an offline gateway
467
+			// create a payment object anyways, but dont save it
468
+			$payment = EE_Payment::new_instance(
469
+				array(
470
+					'STS_ID' => EEM_Payment::status_id_pending,
471
+					'TXN_ID' => $transaction->ID(),
472
+					'PMD_ID' => $transaction->payment_method_ID(),
473
+					'PAY_amount' => 0.00,
474
+					'PAY_timestamp' => time(),
475
+				)
476
+			);
477
+
478
+		}
479
+
480
+		// if there is billing info, clean it and save it now
481
+		if ($billing_info instanceof EE_Billing_Attendee_Info_Form) {
482
+			$this->_save_billing_info_to_attendee($billing_info, $transaction);
483
+		}
484
+
485
+		return $payment;
486
+	}
487
+
488
+	/**
489
+	 * Gets the values we want to pass onto the gateway. Normally these
490
+	 * are just the 'pretty' values, but there may be times the data may need
491
+	 * a  little massaging. Proper subsections will become arrays of inputs
492
+	 * @param EE_Billing_Info_Form $billing_form
493
+	 * @return array
494
+	 */
495
+	protected function _get_billing_values_from_form($billing_form)
496
+	{
497
+		if ($billing_form instanceof EE_Form_Section_Proper) {
498
+			return $billing_form->input_pretty_values(true);
499
+		} else {
500
+			return NULL;
501
+		}
502
+	}
503
+
504
+
505
+	/**
506
+	 * Handles an instant payment notification when the transaction is known (by default).
507
+	 * @param array $req_data
508
+	 * @param EE_Transaction $transaction
509
+	 * @return EE_Payment
510
+	 * @throws InvalidArgumentException
511
+	 * @throws InvalidInterfaceException
512
+	 * @throws InvalidDataTypeException
513
+	 * @throws EE_Error
514
+	 */
515
+	public function handle_ipn($req_data, $transaction)
516
+	{
517
+		$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
518
+		if (!$this->_gateway instanceof EE_Offsite_Gateway) {
519
+			throw new EE_Error(sprintf(__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), print_r($this->_gateway, TRUE)));
520
+
521
+		}
522
+		$payment = $this->_gateway->handle_payment_update($req_data, $transaction);
523
+		return $payment;
524
+	}
525
+
526
+
527
+	/**
528
+	 * Saves the billing info onto the attendee of the primary registrant on this transaction, and
529
+	 * cleans it first.
530
+	 * @param EE_Billing_Attendee_Info_Form $billing_form
531
+	 * @param EE_Transaction $transaction
532
+	 * @return boolean success
533
+	 * @throws EE_Error
534
+	 */
535
+	protected function _save_billing_info_to_attendee($billing_form, $transaction)
536
+	{
537
+		if (!$transaction || !$transaction instanceof EE_Transaction) {
538
+			EE_Error::add_error(__("Cannot save billing info because no transaction was specified", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
539
+			return false;
540
+		}
541
+		$primary_reg = $transaction->primary_registration();
542
+		if (!$primary_reg) {
543
+			EE_Error::add_error(__("Cannot save billing info because the transaction has no primary registration", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
544
+			return false;
545
+		}
546
+		$attendee = $primary_reg->attendee();
547
+		if (!$attendee) {
548
+			EE_Error::add_error(__("Cannot save billing info because the transaction's primary registration has no attendee!", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
549
+			return false;
550
+		}
551
+		return $attendee->save_and_clean_billing_info_for_payment_method($billing_form, $transaction->payment_method());
552
+
553
+	}
554
+
555
+
556
+	/**
557
+	 * Gets the payment this IPN is for. Children may often want to
558
+	 * override this to inspect the request
559
+	 * @param EE_Transaction $transaction
560
+	 * @param array $req_data
561
+	 * @return EE_Payment
562
+	 * @throws EE_Error
563
+	 */
564
+	protected function find_payment_for_ipn(EE_Transaction $transaction, $req_data = array())
565
+	{
566
+		return $transaction->last_payment();
567
+	}
568
+
569
+
570
+	/**
571
+	 * In case generic code cannot provide the payment processor with a specific payment method
572
+	 * and transaction, it will try calling this method on each activate payment method.
573
+	 * If the payment method is able to identify the request as being for it, it should fetch
574
+	 * the payment its for and return it. If not, it should throw an EE_Error to indicate it cannot
575
+	 * handle the IPN
576
+	 * @param array $req_data
577
+	 * @return EE_Payment only if this payment method can find the info its needs from $req_data
578
+	 * and identifies the IPN as being for this payment method (not just fo ra payment method of this type)
579
+	 * @throws EE_Error
580
+	 */
581
+	public function handle_unclaimed_ipn($req_data = array())
582
+	{
583
+		throw new EE_Error(sprintf(__("Payment Method '%s' cannot handle unclaimed IPNs", "event_espresso"), get_class($this)));
584
+	}
585
+
586
+
587
+	/**
588
+	 * Logic to be accomplished when the payment attempt is complete.
589
+	 * Most payment methods don't need to do anything at this point; but some, like Mijireh, do.
590
+	 * (Mijireh is an offsite gateway which doesn't send an IPN. So when the user returns to EE from
591
+	 * mijireh, this method needs to be called so the Mijireh PM can ping Mijireh to know the status
592
+	 * of the payment). Fed a transaction because it's always assumed to be the last payment that
593
+	 * we're dealing with. Returns that last payment (if there is one)
594
+	 *
595
+	 * @param EE_Transaction $transaction
596
+	 * @return EE_Payment
597
+	 * @throws EE_Error
598
+	 */
599
+	public function finalize_payment_for($transaction)
600
+	{
601
+		return $transaction->last_payment();
602
+	}
603
+
604
+
605
+	/**
606
+	 * Whether or not this payment method's gateway supports sending refund requests
607
+	 * @return boolean
608
+	 */
609
+	public function supports_sending_refunds()
610
+	{
611
+		if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
612
+			return $this->_gateway->supports_sending_refunds();
613
+		} else {
614
+			return false;
615
+		}
616
+	}
617
+
618
+
619
+	/**
620
+	 *
621
+	 * @param EE_Payment $payment
622
+	 * @param array $refund_info
623
+	 * @throws EE_Error
624
+	 * @return EE_Payment
625
+	 */
626
+	public function process_refund(EE_Payment $payment, $refund_info = array())
627
+	{
628
+		if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
629
+			return $this->_gateway->do_direct_refund($payment, $refund_info);
630
+		} else {
631
+			throw new EE_Error(
632
+				sprintf(
633
+					__('Payment Method Type "%s" does not support sending refund requests', 'event_espresso'),
634
+					get_class($this)
635
+				)
636
+			);
637
+		}
638
+	}
639
+
640
+
641
+	/**
642
+	 * Returns one the class's constants onsite,offsite, or offline, depending on this
643
+	 * payment method's gateway.
644
+	 * @return string
645
+	 * @throws EE_Error
646
+	 */
647
+	public function payment_occurs()
648
+	{
649
+		if (!$this->_gateway) {
650
+			return EE_PMT_Base::offline;
651
+		} elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
652
+			return EE_PMT_Base::onsite;
653
+		} elseif ($this->_gateway instanceof EE_Offsite_Gateway) {
654
+			return EE_PMT_Base::offsite;
655
+		} else {
656
+			throw new EE_Error(sprintf(__("Payment method type '%s's gateway isn't an instance of EE_Onsite_Gateway, EE_Offsite_Gateway, or null. It must be one of those", "event_espresso"), get_class($this)));
657
+		}
658
+	}
659
+
660
+
661
+	/**
662
+	 * For adding any html output ab ove the payment overview.
663
+	 * Many gateways won't want ot display anything, so this function just returns an empty string.
664
+	 * Other gateways may want to override this, such as offline gateways.
665
+	 * @param EE_Payment $payment
666
+	 * @return string
667
+	 * @throws \DomainException
668
+	 */
669
+	public function payment_overview_content(EE_Payment $payment)
670
+	{
671
+		return EEH_Template::display_template(EE_LIBRARIES . 'payment_methods' . DS . 'templates' . DS . 'payment_details_content.template.php', array('payment_method' => $this->_pm_instance, 'payment' => $payment), true);
672
+	}
673
+
674
+
675
+	/**
676
+	 * @return array where keys are the help tab name,
677
+	 * values are: array {
678
+	 * @type string $title i18n name for the help tab
679
+	 * @type string $filename name of the file located in ./help_tabs/ (ie, in a folder next to this file)
680
+	 * @type array $template_args any arguments you want passed to the template file while rendering.
681
+	 *                Keys will be variable names and values with be their values.
682
+	 */
683
+	public function help_tabs_config()
684
+	{
685
+		return array();
686
+	}
687
+
688
+
689
+	/**
690
+	 * The system name for this PMT (eg AIM, Paypal_Pro, Invoice... what gets put into
691
+	 * the payment method's table's PMT_type column)
692
+	 * @return string
693
+	 */
694
+	public function system_name()
695
+	{
696
+		$classname = get_class($this);
697
+		return str_replace("EE_PMT_", '', $classname);
698
+	}
699
+
700
+
701
+	/**
702
+	 * A pretty i18n version of the PMT name
703
+	 * @return string
704
+	 */
705
+	public function pretty_name()
706
+	{
707
+		return $this->_pretty_name;
708
+	}
709
+
710
+
711
+	/**
712
+	 * Gets the default absolute URL to the payment method type's button
713
+	 * @return string
714
+	 */
715
+	public function default_button_url()
716
+	{
717
+		return $this->_default_button_url;
718
+	}
719
+
720
+
721
+	/**
722
+	 * Gets the gateway used by this payment method (if any)
723
+	 * @return EE_Gateway
724
+	 */
725
+	public function get_gateway()
726
+	{
727
+		return $this->_gateway;
728
+	}
729
+
730
+
731
+	/**
732
+	 * @return string html for the link to a help tab
733
+	 */
734
+	public function get_help_tab_link()
735
+	{
736
+		return EEH_Template::get_help_tab_link($this->get_help_tab_name());
737
+	}
738
+
739
+
740
+	/**
741
+	 * Returns the name of the help tab for this PMT
742
+	 * @return string
743
+	 */
744
+	public function get_help_tab_name()
745
+	{
746
+		return 'ee_' . strtolower($this->system_name()) . '_help_tab';
747
+	}
748
+
749
+	/**
750
+	 * The name of the wp capability that should be associated with the usage of
751
+	 * this PMT by an admin
752
+	 * @return string
753
+	 */
754
+	public function cap_name()
755
+	{
756
+		return 'ee_payment_method_' . strtolower($this->system_name());
757
+	}
758
+
759
+	/**
760
+	 * Called by client code to tell the gateway that if it wants to change
761
+	 * the transaction or line items or registrations related to teh payment it already
762
+	 * processed (we think, but possibly not) that now's the time to do it.
763
+	 * It is expected that gateways will store any info they need for this on the PAY_details,
764
+	 * or maybe an extra meta value
765
+	 * @param EE_Payment $payment
766
+	 * @return void
767
+	 */
768
+	public function update_txn_based_on_payment($payment)
769
+	{
770
+		if ($this->_gateway instanceof EE_Gateway) {
771
+			$this->_gateway->update_txn_based_on_payment($payment);
772
+		}
773
+	}
774
+
775
+	/**
776
+	 * Returns a string of HTML describing this payment method type for an admin,
777
+	 * primarily intended for them to read before activating it.
778
+	 * The easiest way to set this is to create a folder 'templates' alongside
779
+	 * your EE_PMT_{System_Name} file, and in it create a file named "{system_name}_intro.template.php".
780
+	 * Eg, if your payment method file is named "EE_PMT_Foo_Bar.pm.php",
781
+	 * then you'd create a file named "templates" in the same folder as it, and name the file
782
+	 * "foo_bar_intro.template.php", and its content will be returned by this method
783
+	 * @return string
784
+	 */
785
+	public function introductory_html()
786
+	{
787
+		return EEH_Template::locate_template($this->file_folder() . 'templates' . DS . strtolower($this->system_name()) . '_intro.template.php', array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance));
788
+	}
789 789
 
790 790
 
791 791
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Base_Class.class.php 3 patches
Doc Comments   +11 added lines, -10 removed lines patch added patch discarded remove patch
@@ -659,7 +659,7 @@  discard block
 block discarded – undo
659 659
      *
660 660
      * @param \EE_Datetime_Field $datetime_field
661 661
      * @param bool $pretty
662
-     * @param null $date_or_time
662
+     * @param string|null $date_or_time
663 663
      * @return void
664 664
      * @throws InvalidArgumentException
665 665
      * @throws InvalidInterfaceException
@@ -1004,7 +1004,7 @@  discard block
 block discarded – undo
1004 1004
      *
1005 1005
      * @param null  $field_to_order_by  What field is being used as the reference point.
1006 1006
      * @param array $query_params       Any additional conditions on the query.
1007
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1007
+     * @param string  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1008 1008
      *                                  you can indicate just the columns you want returned
1009 1009
      * @return array|EE_Base_Class
1010 1010
      * @throws EE_Error
@@ -1030,7 +1030,7 @@  discard block
 block discarded – undo
1030 1030
      *
1031 1031
      * @param null  $field_to_order_by  What field is being used as the reference point.
1032 1032
      * @param array $query_params       Any additional conditions on the query.
1033
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1033
+     * @param string  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1034 1034
      *                                  you can indicate just the column you want returned
1035 1035
      * @return array|EE_Base_Class
1036 1036
      * @throws EE_Error
@@ -1104,7 +1104,7 @@  discard block
 block discarded – undo
1104 1104
      * This method simply returns the RAW unprocessed value for the given property in this class
1105 1105
      *
1106 1106
      * @param  string $field_name A valid fieldname
1107
-     * @return mixed              Whatever the raw value stored on the property is.
1107
+     * @return integer|null              Whatever the raw value stored on the property is.
1108 1108
      * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1109 1109
      */
1110 1110
     public function get_raw($field_name)
@@ -1165,7 +1165,7 @@  discard block
 block discarded – undo
1165 1165
      * used for fields corresponding to EE_Money_Fields, and it will always return a money object,
1166 1166
      * or else it will throw an exception.
1167 1167
      *
1168
-     * @param $field_name
1168
+     * @param string $field_name
1169 1169
      * @return Money
1170 1170
      * @throws InvalidEntityException
1171 1171
      * @throws EE_Error
@@ -1439,7 +1439,7 @@  discard block
 block discarded – undo
1439 1439
      * sets the time on a datetime property
1440 1440
      *
1441 1441
      * @access protected
1442
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1442
+     * @param string $time      a valid time string for php datetime functions (or DateTime object)
1443 1443
      * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1444 1444
      * @throws EE_Error
1445 1445
      */
@@ -1454,7 +1454,7 @@  discard block
 block discarded – undo
1454 1454
      * sets the date on a datetime property
1455 1455
      *
1456 1456
      * @access protected
1457
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1457
+     * @param string $date      a valid date string for php datetime functions ( or DateTime object)
1458 1458
      * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1459 1459
      * @throws EE_Error
1460 1460
      */
@@ -1518,6 +1518,7 @@  discard block
 block discarded – undo
1518 1518
      * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1519 1519
      * @param string $prepend You can include something to prepend on the timestamp
1520 1520
      * @param string $append You can include something to append on the timestamp
1521
+     * @param string $args
1521 1522
      * @throws InvalidArgumentException
1522 1523
      * @throws InvalidInterfaceException
1523 1524
      * @throws InvalidDataTypeException
@@ -1922,7 +1923,7 @@  discard block
 block discarded – undo
1922 1923
      *
1923 1924
      * @param  array  $props_n_values   incoming array of properties and their values
1924 1925
      * @param  string $classname        the classname of the child class
1925
-     * @param null    $timezone
1926
+     * @param string|null    $timezone
1926 1927
      * @param array   $date_formats     incoming date_formats in an array where the first value is the
1927 1928
      *                                  date_format and the second value is the time format
1928 1929
      * @return mixed (EE_Base_Class|bool)
@@ -2000,7 +2001,7 @@  discard block
 block discarded – undo
2000 2001
      * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2001 2002
      *
2002 2003
      * @param string $model_classname
2003
-     * @param null $timezone
2004
+     * @param string|null $timezone
2004 2005
      * @return EEM_Base
2005 2006
      * @throws \ReflectionException
2006 2007
      * @throws InvalidArgumentException
@@ -2506,7 +2507,7 @@  discard block
 block discarded – undo
2506 2507
      *
2507 2508
      * @param string $meta_key
2508 2509
      * @param mixed $meta_value
2509
-     * @param mixed $previous_value
2510
+     * @param boolean $previous_value
2510 2511
      * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2511 2512
      * @throws InvalidArgumentException
2512 2513
      * @throws InvalidInterfaceException
Please login to merge, or discard this patch.
Indentation   +2884 added lines, -2884 removed lines patch added patch discarded remove patch
@@ -11,7 +11,7 @@  discard block
 block discarded – undo
11 11
 use EventEspresso\core\services\loaders\LoaderFactory;
12 12
 
13 13
 if ( ! defined('EVENT_ESPRESSO_VERSION')) {
14
-    exit('No direct script access allowed');
14
+	exit('No direct script access allowed');
15 15
 }
16 16
 do_action('AHEE_log', __FILE__, ' FILE LOADED', '');
17 17
 
@@ -27,2889 +27,2889 @@  discard block
 block discarded – undo
27 27
 abstract class EE_Base_Class
28 28
 {
29 29
 
30
-    /**
31
-     * This is an array of the original properties and values provided during construction
32
-     * of this model object. (keys are model field names, values are their values).
33
-     * This list is important to remember so that when we are merging data from the db, we know
34
-     * which values to override and which to not override.
35
-     *
36
-     * @var array
37
-     */
38
-    protected $_props_n_values_provided_in_constructor;
39
-
40
-    /**
41
-     * Timezone
42
-     * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
43
-     * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
44
-     * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
45
-     * access to it.
46
-     *
47
-     * @var string
48
-     */
49
-    protected $_timezone;
50
-
51
-
52
-
53
-    /**
54
-     * date format
55
-     * pattern or format for displaying dates
56
-     *
57
-     * @var string $_dt_frmt
58
-     */
59
-    protected $_dt_frmt;
60
-
61
-
62
-
63
-    /**
64
-     * time format
65
-     * pattern or format for displaying time
66
-     *
67
-     * @var string $_tm_frmt
68
-     */
69
-    protected $_tm_frmt;
70
-
71
-
72
-
73
-    /**
74
-     * This property is for holding a cached array of object properties indexed by property name as the key.
75
-     * The purpose of this is for setting a cache on properties that may have calculated values after a
76
-     * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
77
-     * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
78
-     *
79
-     * @var array
80
-     */
81
-    protected $_cached_properties = array();
82
-
83
-    /**
84
-     * An array containing keys of the related model, and values are either an array of related mode objects or a
85
-     * single
86
-     * related model object. see the model's _model_relations. The keys should match those specified. And if the
87
-     * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
88
-     * all others have an array)
89
-     *
90
-     * @var array
91
-     */
92
-    protected $_model_relations = array();
93
-
94
-    /**
95
-     * Array where keys are field names (see the model's _fields property) and values are their values. To see what
96
-     * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
97
-     *
98
-     * @var array
99
-     */
100
-    protected $_fields = array();
101
-
102
-    /**
103
-     * @var boolean indicating whether or not this model object is intended to ever be saved
104
-     * For example, we might create model objects intended to only be used for the duration
105
-     * of this request and to be thrown away, and if they were accidentally saved
106
-     * it would be a bug.
107
-     */
108
-    protected $_allow_persist = true;
109
-
110
-    /**
111
-     * @var boolean indicating whether or not this model object's properties have changed since construction
112
-     */
113
-    protected $_has_changes = false;
114
-
115
-    /**
116
-     * @var EEM_Base
117
-     */
118
-    protected $_model;
119
-
120
-    /**
121
-     * @var MoneyFactory
122
-     */
123
-    protected $money_factory;
124
-
125
-
126
-    /**
127
-     * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
128
-     * play nice
129
-     *
130
-     * @param array $fieldValues where each key is a field (ie, array key in the 2nd
131
-     *                                                         layer of the model's _fields array, (eg, EVT_ID,
132
-     *                                                         TXN_amount, QST_name, etc) and values are their values
133
-     * @param boolean $bydb a flag for setting if the class is instantiated by the
134
-     *                                                         corresponding db model or not.
135
-     * @param string $timezone indicate what timezone you want any datetime fields to
136
-     *                                                         be in when instantiating a EE_Base_Class object.
137
-     * @param array $date_formats An array of date formats to set on construct where first
138
-     *                                                         value is the date_format and second value is the time
139
-     *                                                         format.
140
-     * @throws InvalidArgumentException
141
-     * @throws InvalidInterfaceException
142
-     * @throws InvalidDataTypeException
143
-     * @throws EE_Error
144
-     */
145
-    protected function __construct(
146
-        $fieldValues = array(),
147
-        $bydb = false,
148
-        $timezone = '',
149
-        $date_formats = array()
150
-    ) {
151
-        $className = get_class($this);
152
-        do_action("AHEE__{$className}__construct", $this, $fieldValues);
153
-        $model = $this->get_model();
154
-        $model_fields = $model->field_settings(false);
155
-        // ensure $fieldValues is an array
156
-        $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
157
-        // EEH_Debug_Tools::printr( $fieldValues, '$fieldValues  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
158
-        // verify client code has not passed any invalid field names
159
-        foreach ($fieldValues as $field_name => $field_value) {
160
-            if ( ! isset($model_fields[$field_name])) {
161
-                throw new EE_Error(sprintf(__("Invalid field (%s) passed to constructor of %s. Allowed fields are :%s",
162
-                    "event_espresso"), $field_name, get_class($this), implode(", ", array_keys($model_fields))));
163
-            }
164
-        }
165
-        // EEH_Debug_Tools::printr( $model_fields, '$model_fields  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
166
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
167
-        if ( ! empty($date_formats) && is_array($date_formats)) {
168
-            list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
169
-        } else {
170
-            //set default formats for date and time
171
-            $this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
172
-            $this->_tm_frmt = (string)get_option('time_format', 'g:i a');
173
-        }
174
-        //if db model is instantiating
175
-        if ($bydb) {
176
-            //client code has indicated these field values are from the database
177
-            foreach ($model_fields as $fieldName => $field) {
178
-                $this->set_from_db($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null);
179
-            }
180
-        } else {
181
-            //we're constructing a brand
182
-            //new instance of the model object. Generally, this means we'll need to do more field validation
183
-            foreach ($model_fields as $fieldName => $field) {
184
-                $this->set($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true);
185
-            }
186
-        }
187
-        //remember what values were passed to this constructor
188
-        $this->_props_n_values_provided_in_constructor = $fieldValues;
189
-        //remember in entity mapper
190
-        if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
191
-            $model->add_to_entity_map($this);
192
-        }
193
-        //setup all the relations
194
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
195
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
196
-                $this->_model_relations[$relation_name] = null;
197
-            } else {
198
-                $this->_model_relations[$relation_name] = array();
199
-            }
200
-        }
201
-        /**
202
-         * Action done at the end of each model object construction
203
-         *
204
-         * @param EE_Base_Class $this the model object just created
205
-         */
206
-        do_action('AHEE__EE_Base_Class__construct__finished', $this);
207
-    }
208
-
209
-
210
-
211
-    /**
212
-     * Gets whether or not this model object is allowed to persist/be saved to the database.
213
-     *
214
-     * @return boolean
215
-     */
216
-    public function allow_persist()
217
-    {
218
-        return $this->_allow_persist;
219
-    }
220
-
221
-
222
-
223
-    /**
224
-     * Sets whether or not this model object should be allowed to be saved to the DB.
225
-     * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
226
-     * you got new information that somehow made you change your mind.
227
-     *
228
-     * @param boolean $allow_persist
229
-     * @return boolean
230
-     */
231
-    public function set_allow_persist($allow_persist)
232
-    {
233
-        return $this->_allow_persist = $allow_persist;
234
-    }
235
-
236
-
237
-
238
-    /**
239
-     * Gets the field's original value when this object was constructed during this request.
240
-     * This can be helpful when determining if a model object has changed or not
241
-     *
242
-     * @param string $field_name
243
-     * @return mixed|null
244
-     * @throws EE_Error
245
-     */
246
-    public function get_original($field_name)
247
-    {
248
-        if (isset($this->_props_n_values_provided_in_constructor[$field_name])
249
-            && $field_settings = $this->get_model()->field_settings_for($field_name)
250
-        ) {
251
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
252
-        } else {
253
-            return null;
254
-        }
255
-    }
256
-
257
-
258
-
259
-    /**
260
-     * @param EE_Base_Class $obj
261
-     * @return string
262
-     */
263
-    public function get_class($obj)
264
-    {
265
-        return get_class($obj);
266
-    }
267
-
268
-
269
-    /**
270
-     * Overrides parent because parent expects old models.
271
-     * This also doesn't do any validation, and won't work for serialized arrays
272
-     *
273
-     * @param    string $field_name
274
-     * @param    mixed $field_value
275
-     * @param bool $use_default
276
-     * @throws InvalidArgumentException
277
-     * @throws InvalidInterfaceException
278
-     * @throws InvalidDataTypeException
279
-     * @throws EE_Error
280
-     */
281
-    public function set($field_name, $field_value, $use_default = false)
282
-    {
283
-        // if not using default and nothing has changed, and object has already been setup (has ID),
284
-        // then don't do anything
285
-        if (
286
-            ! $use_default
287
-            && $this->_fields[$field_name] === $field_value
288
-            && $this->ID()
289
-        ) {
290
-            return;
291
-        }
292
-        $model = $this->get_model();
293
-        $this->_has_changes = true;
294
-        $field_obj = $model->field_settings_for($field_name);
295
-        if ($field_obj instanceof EE_Model_Field_Base) {
296
-            //			if ( method_exists( $field_obj, 'set_timezone' )) {
297
-            if ($field_obj instanceof EE_Datetime_Field) {
298
-                $field_obj->set_timezone($this->_timezone);
299
-                $field_obj->set_date_format($this->_dt_frmt);
300
-                $field_obj->set_time_format($this->_tm_frmt);
301
-            }
302
-            $holder_of_value = $field_obj->prepare_for_set($field_value);
303
-            //should the value be null?
304
-            if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
305
-                $this->_fields[$field_name] = $field_obj->get_default_value();
306
-                /**
307
-                 * To save having to refactor all the models, if a default value is used for a
308
-                 * EE_Datetime_Field, and that value is not null nor is it a DateTime
309
-                 * object.  Then let's do a set again to ensure that it becomes a DateTime
310
-                 * object.
311
-                 *
312
-                 * @since 4.6.10+
313
-                 */
314
-                if (
315
-                    $field_obj instanceof EE_Datetime_Field
316
-                    && $this->_fields[$field_name] !== null
317
-                    && ! $this->_fields[$field_name] instanceof DateTime
318
-                ) {
319
-                    empty($this->_fields[$field_name])
320
-                        ? $this->set($field_name, time())
321
-                        : $this->set($field_name, $this->_fields[$field_name]);
322
-                }
323
-            } else {
324
-                $this->_fields[$field_name] = $holder_of_value;
325
-            }
326
-            //if we're not in the constructor...
327
-            //now check if what we set was a primary key
328
-            if (
329
-                //note: props_n_values_provided_in_constructor is only set at the END of the constructor
330
-                $this->_props_n_values_provided_in_constructor
331
-                && $field_value
332
-                && $field_name === $model->primary_key_name()
333
-            ) {
334
-                //if so, we want all this object's fields to be filled either with
335
-                //what we've explicitly set on this model
336
-                //or what we have in the db
337
-                // echo "setting primary key!";
338
-                $fields_on_model = self::_get_model(get_class($this))->field_settings();
339
-                $obj_in_db = self::_get_model(get_class($this))->get_one_by_ID($field_value);
340
-                foreach ($fields_on_model as $field_obj) {
341
-                    if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
342
-                         && $field_obj->get_name() !== $field_name
343
-                    ) {
344
-                        $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
345
-                    }
346
-                }
347
-                //oh this model object has an ID? well make sure its in the entity mapper
348
-                $model->add_to_entity_map($this);
349
-            }
350
-            //let's unset any cache for this field_name from the $_cached_properties property.
351
-            $this->_clear_cached_property($field_name);
352
-        } else {
353
-            throw new EE_Error(sprintf(__("A valid EE_Model_Field_Base could not be found for the given field name: %s",
354
-                "event_espresso"), $field_name));
355
-        }
356
-    }
357
-
358
-
359
-
360
-    /**
361
-     * This sets the field value on the db column if it exists for the given $column_name or
362
-     * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
363
-     *
364
-     * @see EE_message::get_column_value for related documentation on the necessity of this method.
365
-     * @param string $field_name  Must be the exact column name.
366
-     * @param mixed  $field_value The value to set.
367
-     * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
368
-     * @throws EE_Error
369
-     */
370
-    public function set_field_or_extra_meta($field_name, $field_value)
371
-    {
372
-        if ($this->get_model()->has_field($field_name)) {
373
-            $this->set($field_name, $field_value);
374
-            return true;
375
-        } else {
376
-            //ensure this object is saved first so that extra meta can be properly related.
377
-            $this->save();
378
-            return $this->update_extra_meta($field_name, $field_value);
379
-        }
380
-    }
381
-
382
-
383
-
384
-    /**
385
-     * This retrieves the value of the db column set on this class or if that's not present
386
-     * it will attempt to retrieve from extra_meta if found.
387
-     * Example Usage:
388
-     * Via EE_Message child class:
389
-     * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
390
-     * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
391
-     * also have additional main fields specific to the messenger.  The system accommodates those extra
392
-     * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
393
-     * value for those extra fields dynamically via the EE_message object.
394
-     *
395
-     * @param  string $field_name expecting the fully qualified field name.
396
-     * @return mixed|null  value for the field if found.  null if not found.
397
-     * @throws EE_Error
398
-     */
399
-    public function get_field_or_extra_meta($field_name)
400
-    {
401
-        if ($this->get_model()->has_field($field_name)) {
402
-            $column_value = $this->get($field_name);
403
-        } else {
404
-            //This isn't a column in the main table, let's see if it is in the extra meta.
405
-            $column_value = $this->get_extra_meta($field_name, true, null);
406
-        }
407
-        return $column_value;
408
-    }
409
-
410
-
411
-    /**
412
-     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
413
-     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
414
-     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
415
-     * available to all child classes that may be using the EE_Datetime_Field for a field data type.
416
-     *
417
-     * @access public
418
-     * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
419
-     * @return void
420
-     * @throws InvalidArgumentException
421
-     * @throws InvalidInterfaceException
422
-     * @throws InvalidDataTypeException
423
-     * @throws EE_Error
424
-     */
425
-    public function set_timezone($timezone = '')
426
-    {
427
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
428
-        //make sure we clear all cached properties because they won't be relevant now
429
-        $this->_clear_cached_properties();
430
-        //make sure we update field settings and the date for all EE_Datetime_Fields
431
-        $model_fields = $this->get_model()->field_settings(false);
432
-        foreach ($model_fields as $field_name => $field_obj) {
433
-            if ($field_obj instanceof EE_Datetime_Field) {
434
-                $field_obj->set_timezone($this->_timezone);
435
-                if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
436
-                    $this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
437
-                }
438
-            }
439
-        }
440
-    }
441
-
442
-
443
-
444
-    /**
445
-     * This just returns whatever is set for the current timezone.
446
-     *
447
-     * @access public
448
-     * @return string timezone string
449
-     */
450
-    public function get_timezone()
451
-    {
452
-        return $this->_timezone;
453
-    }
454
-
455
-
456
-
457
-    /**
458
-     * This sets the internal date format to what is sent in to be used as the new default for the class
459
-     * internally instead of wp set date format options
460
-     *
461
-     * @since 4.6
462
-     * @param string $format should be a format recognizable by PHP date() functions.
463
-     */
464
-    public function set_date_format($format)
465
-    {
466
-        $this->_dt_frmt = $format;
467
-        //clear cached_properties because they won't be relevant now.
468
-        $this->_clear_cached_properties();
469
-    }
470
-
471
-
472
-
473
-    /**
474
-     * This sets the internal time format string to what is sent in to be used as the new default for the
475
-     * class internally instead of wp set time format options.
476
-     *
477
-     * @since 4.6
478
-     * @param string $format should be a format recognizable by PHP date() functions.
479
-     */
480
-    public function set_time_format($format)
481
-    {
482
-        $this->_tm_frmt = $format;
483
-        //clear cached_properties because they won't be relevant now.
484
-        $this->_clear_cached_properties();
485
-    }
486
-
487
-
488
-
489
-    /**
490
-     * This returns the current internal set format for the date and time formats.
491
-     *
492
-     * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
493
-     *                             where the first value is the date format and the second value is the time format.
494
-     * @return mixed string|array
495
-     */
496
-    public function get_format($full = true)
497
-    {
498
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
499
-    }
500
-
501
-
502
-
503
-    /**
504
-     * cache
505
-     * stores the passed model object on the current model object.
506
-     * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
507
-     *
508
-     * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
509
-     *                                       'Registration' associated with this model object
510
-     * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
511
-     *                                       that could be a payment or a registration)
512
-     * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
513
-     *                                       items which will be stored in an array on this object
514
-     * @throws EE_Error
515
-     * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
516
-     *                  related thing, no array)
517
-     */
518
-    public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
519
-    {
520
-        // its entirely possible that there IS no related object yet in which case there is nothing to cache.
521
-        if ( ! $object_to_cache instanceof EE_Base_Class) {
522
-            return false;
523
-        }
524
-        // also get "how" the object is related, or throw an error
525
-        if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
526
-            throw new EE_Error(sprintf(__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
527
-                $relationName, get_class($this)));
528
-        }
529
-        // how many things are related ?
530
-        if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
531
-            // if it's a "belongs to" relationship, then there's only one related model object  eg, if this is a registration, there's only 1 attendee for it
532
-            // so for these model objects just set it to be cached
533
-            $this->_model_relations[$relationName] = $object_to_cache;
534
-            $return = true;
535
-        } else {
536
-            // otherwise, this is the "many" side of a one to many relationship, so we'll add the object to the array of related objects for that type.
537
-            // eg: if this is an event, there are many registrations for that event, so we cache the registrations in an array
538
-            if ( ! is_array($this->_model_relations[$relationName])) {
539
-                // if for some reason, the cached item is a model object, then stick that in the array, otherwise start with an empty array
540
-                $this->_model_relations[$relationName] = $this->_model_relations[$relationName] instanceof EE_Base_Class
541
-                    ? array($this->_model_relations[$relationName]) : array();
542
-            }
543
-            // first check for a cache_id which is normally empty
544
-            if ( ! empty($cache_id)) {
545
-                // if the cache_id exists, then it means we are purposely trying to cache this with a known key that can then be used to retrieve the object later on
546
-                $this->_model_relations[$relationName][$cache_id] = $object_to_cache;
547
-                $return = $cache_id;
548
-            } elseif ($object_to_cache->ID()) {
549
-                // OR the cached object originally came from the db, so let's just use it's PK for an ID
550
-                $this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
551
-                $return = $object_to_cache->ID();
552
-            } else {
553
-                // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
554
-                $this->_model_relations[$relationName][] = $object_to_cache;
555
-                // move the internal pointer to the end of the array
556
-                end($this->_model_relations[$relationName]);
557
-                // and grab the key so that we can return it
558
-                $return = key($this->_model_relations[$relationName]);
559
-            }
560
-        }
561
-        return $return;
562
-    }
563
-
564
-
565
-
566
-    /**
567
-     * For adding an item to the cached_properties property.
568
-     *
569
-     * @access protected
570
-     * @param string      $fieldname the property item the corresponding value is for.
571
-     * @param mixed       $value     The value we are caching.
572
-     * @param string|null $cache_type
573
-     * @return void
574
-     * @throws EE_Error
575
-     */
576
-    protected function _set_cached_property($fieldname, $value, $cache_type = null)
577
-    {
578
-        //first make sure this property exists
579
-        $this->get_model()->field_settings_for($fieldname);
580
-        $cache_type = empty($cache_type) ? 'standard' : $cache_type;
581
-        $this->_cached_properties[$fieldname][$cache_type] = $value;
582
-    }
583
-
584
-
585
-
586
-    /**
587
-     * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
588
-     * This also SETS the cache if we return the actual property!
589
-     *
590
-     * @param string $fieldname        the name of the property we're trying to retrieve
591
-     * @param bool   $pretty
592
-     * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
593
-     *                                 (in cases where the same property may be used for different outputs
594
-     *                                 - i.e. datetime, money etc.)
595
-     *                                 It can also accept certain pre-defined "schema" strings
596
-     *                                 to define how to output the property.
597
-     *                                 see the field's prepare_for_pretty_echoing for what strings can be used
598
-     * @return mixed                   whatever the value for the property is we're retrieving
599
-     * @throws EE_Error
600
-     */
601
-    protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
602
-    {
603
-        //verify the field exists
604
-        $model = $this->get_model();
605
-        $model->field_settings_for($fieldname);
606
-        $cache_type = $pretty ? 'pretty' : 'standard';
607
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
608
-        if (isset($this->_cached_properties[$fieldname][$cache_type])) {
609
-            return $this->_cached_properties[$fieldname][$cache_type];
610
-        }
611
-        $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
612
-        $this->_set_cached_property($fieldname, $value, $cache_type);
613
-        return $value;
614
-    }
615
-
616
-
617
-    /**
618
-     * If the cache didn't fetch the needed item, this fetches it.
619
-     * @param string $fieldname
620
-     * @param bool $pretty
621
-     * @param string $extra_cache_ref
622
-     * @return mixed
623
-     * @throws EE_Error
624
-     */
625
-    protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
626
-    {
627
-        $field_obj = $this->get_model()->field_settings_for($fieldname);
628
-        // If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
629
-        if ($field_obj instanceof EE_Datetime_Field) {
630
-            $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
631
-        }
632
-        if ( ! isset($this->_fields[$fieldname])) {
633
-            $this->_fields[$fieldname] = null;
634
-        }
635
-        $value = $pretty
636
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
637
-            : $field_obj->prepare_for_get($this->_fields[$fieldname]);
638
-        return $value;
639
-    }
640
-
641
-
642
-    /**
643
-     * set timezone, formats, and output for EE_Datetime_Field objects
644
-     *
645
-     * @param \EE_Datetime_Field $datetime_field
646
-     * @param bool $pretty
647
-     * @param null $date_or_time
648
-     * @return void
649
-     * @throws InvalidArgumentException
650
-     * @throws InvalidInterfaceException
651
-     * @throws InvalidDataTypeException
652
-     * @throws EE_Error
653
-     */
654
-    protected function _prepare_datetime_field(
655
-        EE_Datetime_Field $datetime_field,
656
-        $pretty = false,
657
-        $date_or_time = null
658
-    ) {
659
-        $datetime_field->set_timezone($this->_timezone);
660
-        $datetime_field->set_date_format($this->_dt_frmt, $pretty);
661
-        $datetime_field->set_time_format($this->_tm_frmt, $pretty);
662
-        //set the output returned
663
-        switch ($date_or_time) {
664
-            case 'D' :
665
-                $datetime_field->set_date_time_output('date');
666
-                break;
667
-            case 'T' :
668
-                $datetime_field->set_date_time_output('time');
669
-                break;
670
-            default :
671
-                $datetime_field->set_date_time_output();
672
-        }
673
-    }
674
-
675
-
676
-
677
-    /**
678
-     * This just takes care of clearing out the cached_properties
679
-     *
680
-     * @return void
681
-     */
682
-    protected function _clear_cached_properties()
683
-    {
684
-        $this->_cached_properties = array();
685
-    }
686
-
687
-
688
-
689
-    /**
690
-     * This just clears out ONE property if it exists in the cache
691
-     *
692
-     * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
693
-     * @return void
694
-     */
695
-    protected function _clear_cached_property($property_name)
696
-    {
697
-        if (isset($this->_cached_properties[$property_name])) {
698
-            unset($this->_cached_properties[$property_name]);
699
-        }
700
-    }
701
-
702
-
703
-
704
-    /**
705
-     * Ensures that this related thing is a model object.
706
-     *
707
-     * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
708
-     * @param string $model_name   name of the related thing, eg 'Attendee',
709
-     * @return EE_Base_Class
710
-     * @throws EE_Error
711
-     */
712
-    protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
713
-    {
714
-        $other_model_instance = self::_get_model_instance_with_name(
715
-            self::_get_model_classname($model_name),
716
-            $this->_timezone
717
-        );
718
-        return $other_model_instance->ensure_is_obj($object_or_id);
719
-    }
720
-
721
-
722
-
723
-    /**
724
-     * Forgets the cached model of the given relation Name. So the next time we request it,
725
-     * we will fetch it again from the database. (Handy if you know it's changed somehow).
726
-     * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
727
-     * then only remove that one object from our cached array. Otherwise, clear the entire list
728
-     *
729
-     * @param string $relationName                         one of the keys in the _model_relations array on the model.
730
-     *                                                     Eg 'Registration'
731
-     * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
732
-     *                                                     if you intend to use $clear_all = TRUE, or the relation only
733
-     *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
734
-     * @param bool   $clear_all                            This flags clearing the entire cache relation property if
735
-     *                                                     this is HasMany or HABTM.
736
-     * @throws EE_Error
737
-     * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
738
-     *                       relation from all
739
-     */
740
-    public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
741
-    {
742
-        $relationship_to_model = $this->get_model()->related_settings_for($relationName);
743
-        $index_in_cache = '';
744
-        if ( ! $relationship_to_model) {
745
-            throw new EE_Error(
746
-                sprintf(
747
-                    __("There is no relationship to %s on a %s. Cannot clear that cache", 'event_espresso'),
748
-                    $relationName,
749
-                    get_class($this)
750
-                )
751
-            );
752
-        }
753
-        if ($clear_all) {
754
-            $obj_removed = true;
755
-            $this->_model_relations[$relationName] = null;
756
-        } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
757
-            $obj_removed = $this->_model_relations[$relationName];
758
-            $this->_model_relations[$relationName] = null;
759
-        } else {
760
-            if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
761
-                && $object_to_remove_or_index_into_array->ID()
762
-            ) {
763
-                $index_in_cache = $object_to_remove_or_index_into_array->ID();
764
-                if (is_array($this->_model_relations[$relationName])
765
-                    && ! isset($this->_model_relations[$relationName][$index_in_cache])
766
-                ) {
767
-                    $index_found_at = null;
768
-                    //find this object in the array even though it has a different key
769
-                    foreach ($this->_model_relations[$relationName] as $index => $obj) {
770
-                        if (
771
-                            $obj instanceof EE_Base_Class
772
-                            && (
773
-                                $obj == $object_to_remove_or_index_into_array
774
-                                || $obj->ID() === $object_to_remove_or_index_into_array->ID()
775
-                            )
776
-                        ) {
777
-                            $index_found_at = $index;
778
-                            break;
779
-                        }
780
-                    }
781
-                    if ($index_found_at) {
782
-                        $index_in_cache = $index_found_at;
783
-                    } else {
784
-                        //it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
785
-                        //if it wasn't in it to begin with. So we're done
786
-                        return $object_to_remove_or_index_into_array;
787
-                    }
788
-                }
789
-            } elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
790
-                //so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
791
-                foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
792
-                    if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
793
-                        $index_in_cache = $index;
794
-                    }
795
-                }
796
-            } else {
797
-                $index_in_cache = $object_to_remove_or_index_into_array;
798
-            }
799
-            //supposedly we've found it. But it could just be that the client code
800
-            //provided a bad index/object
801
-            if (
802
-            isset(
803
-                $this->_model_relations[$relationName],
804
-                $this->_model_relations[$relationName][$index_in_cache]
805
-            )
806
-            ) {
807
-                $obj_removed = $this->_model_relations[$relationName][$index_in_cache];
808
-                unset($this->_model_relations[$relationName][$index_in_cache]);
809
-            } else {
810
-                //that thing was never cached anyways.
811
-                $obj_removed = null;
812
-            }
813
-        }
814
-        return $obj_removed;
815
-    }
816
-
817
-
818
-
819
-    /**
820
-     * update_cache_after_object_save
821
-     * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
822
-     * obtained after being saved to the db
823
-     *
824
-     * @param string         $relationName       - the type of object that is cached
825
-     * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
826
-     * @param string         $current_cache_id   - the ID that was used when originally caching the object
827
-     * @return boolean TRUE on success, FALSE on fail
828
-     * @throws EE_Error
829
-     */
830
-    public function update_cache_after_object_save(
831
-        $relationName,
832
-        EE_Base_Class $newly_saved_object,
833
-        $current_cache_id = ''
834
-    ) {
835
-        // verify that incoming object is of the correct type
836
-        $obj_class = 'EE_' . $relationName;
837
-        if ($newly_saved_object instanceof $obj_class) {
838
-            /* @type EE_Base_Class $newly_saved_object */
839
-            // now get the type of relation
840
-            $relationship_to_model = $this->get_model()->related_settings_for($relationName);
841
-            // if this is a 1:1 relationship
842
-            if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
843
-                // then just replace the cached object with the newly saved object
844
-                $this->_model_relations[$relationName] = $newly_saved_object;
845
-                return true;
846
-                // or if it's some kind of sordid feral polyamorous relationship...
847
-            } elseif (is_array($this->_model_relations[$relationName])
848
-                      && isset($this->_model_relations[$relationName][$current_cache_id])
849
-            ) {
850
-                // then remove the current cached item
851
-                unset($this->_model_relations[$relationName][$current_cache_id]);
852
-                // and cache the newly saved object using it's new ID
853
-                $this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
854
-                return true;
855
-            }
856
-        }
857
-        return false;
858
-    }
859
-
860
-
861
-
862
-    /**
863
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
864
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
865
-     *
866
-     * @param string $relationName
867
-     * @return EE_Base_Class
868
-     */
869
-    public function get_one_from_cache($relationName)
870
-    {
871
-        $cached_array_or_object = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName]
872
-            : null;
873
-        if (is_array($cached_array_or_object)) {
874
-            return array_shift($cached_array_or_object);
875
-        } else {
876
-            return $cached_array_or_object;
877
-        }
878
-    }
879
-
880
-
881
-    /**
882
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
883
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
884
-     *
885
-     * @param string $relationName
886
-     * @throws \ReflectionException
887
-     * @throws InvalidArgumentException
888
-     * @throws InvalidInterfaceException
889
-     * @throws InvalidDataTypeException
890
-     * @throws EE_Error
891
-     * @return EE_Base_Class[] NOT necessarily indexed by primary keys
892
-     */
893
-    public function get_all_from_cache($relationName)
894
-    {
895
-        $objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
896
-        // if the result is not an array, but exists, make it an array
897
-        $objects = is_array($objects) ? $objects : array($objects);
898
-        //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
899
-        //basically, if this model object was stored in the session, and these cached model objects
900
-        //already have IDs, let's make sure they're in their model's entity mapper
901
-        //otherwise we will have duplicates next time we call
902
-        // EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
903
-        $model = EE_Registry::instance()->load_model($relationName);
904
-        foreach ($objects as $model_object) {
905
-            if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
906
-                //ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
907
-                if ($model_object->ID()) {
908
-                    $model->add_to_entity_map($model_object);
909
-                }
910
-            } else {
911
-                throw new EE_Error(
912
-                    sprintf(
913
-                        __(
914
-                            'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
915
-                            'event_espresso'
916
-                        ),
917
-                        $relationName,
918
-                        gettype($model_object)
919
-                    )
920
-                );
921
-            }
922
-        }
923
-        return $objects;
924
-    }
925
-
926
-
927
-
928
-    /**
929
-     * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
930
-     * matching the given query conditions.
931
-     *
932
-     * @param null  $field_to_order_by  What field is being used as the reference point.
933
-     * @param int   $limit              How many objects to return.
934
-     * @param array $query_params       Any additional conditions on the query.
935
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
936
-     *                                  you can indicate just the columns you want returned
937
-     * @return array|EE_Base_Class[]
938
-     * @throws EE_Error
939
-     */
940
-    public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
941
-    {
942
-        $model = $this->get_model();
943
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
944
-            ? $model->get_primary_key_field()->get_name()
945
-            : $field_to_order_by;
946
-        $current_value = ! empty($field) ? $this->get($field) : null;
947
-        if (empty($field) || empty($current_value)) {
948
-            return array();
949
-        }
950
-        return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
951
-    }
952
-
953
-
954
-
955
-    /**
956
-     * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
957
-     * matching the given query conditions.
958
-     *
959
-     * @param null  $field_to_order_by  What field is being used as the reference point.
960
-     * @param int   $limit              How many objects to return.
961
-     * @param array $query_params       Any additional conditions on the query.
962
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
963
-     *                                  you can indicate just the columns you want returned
964
-     * @return array|EE_Base_Class[]
965
-     * @throws EE_Error
966
-     */
967
-    public function previous_x(
968
-        $field_to_order_by = null,
969
-        $limit = 1,
970
-        $query_params = array(),
971
-        $columns_to_select = null
972
-    ) {
973
-        $model = $this->get_model();
974
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
975
-            ? $model->get_primary_key_field()->get_name()
976
-            : $field_to_order_by;
977
-        $current_value = ! empty($field) ? $this->get($field) : null;
978
-        if (empty($field) || empty($current_value)) {
979
-            return array();
980
-        }
981
-        return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
982
-    }
983
-
984
-
985
-
986
-    /**
987
-     * Returns the next EE_Base_Class object in sequence from this object as found in the database
988
-     * matching the given query conditions.
989
-     *
990
-     * @param null  $field_to_order_by  What field is being used as the reference point.
991
-     * @param array $query_params       Any additional conditions on the query.
992
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
993
-     *                                  you can indicate just the columns you want returned
994
-     * @return array|EE_Base_Class
995
-     * @throws EE_Error
996
-     */
997
-    public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
998
-    {
999
-        $model = $this->get_model();
1000
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
1001
-            ? $model->get_primary_key_field()->get_name()
1002
-            : $field_to_order_by;
1003
-        $current_value = ! empty($field) ? $this->get($field) : null;
1004
-        if (empty($field) || empty($current_value)) {
1005
-            return array();
1006
-        }
1007
-        return $model->next($current_value, $field, $query_params, $columns_to_select);
1008
-    }
1009
-
1010
-
1011
-
1012
-    /**
1013
-     * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1014
-     * matching the given query conditions.
1015
-     *
1016
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1017
-     * @param array $query_params       Any additional conditions on the query.
1018
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1019
-     *                                  you can indicate just the column you want returned
1020
-     * @return array|EE_Base_Class
1021
-     * @throws EE_Error
1022
-     */
1023
-    public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1024
-    {
1025
-        $model = $this->get_model();
1026
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
1027
-            ? $model->get_primary_key_field()->get_name()
1028
-            : $field_to_order_by;
1029
-        $current_value = ! empty($field) ? $this->get($field) : null;
1030
-        if (empty($field) || empty($current_value)) {
1031
-            return array();
1032
-        }
1033
-        return $model->previous($current_value, $field, $query_params, $columns_to_select);
1034
-    }
1035
-
1036
-
1037
-
1038
-    /**
1039
-     * Overrides parent because parent expects old models.
1040
-     * This also doesn't do any validation, and won't work for serialized arrays
1041
-     *
1042
-     * @param string $field_name
1043
-     * @param mixed  $field_value_from_db
1044
-     * @throws EE_Error
1045
-     */
1046
-    public function set_from_db($field_name, $field_value_from_db)
1047
-    {
1048
-        $field_obj = $this->get_model()->field_settings_for($field_name);
1049
-        if ($field_obj instanceof EE_Model_Field_Base) {
1050
-            //you would think the DB has no NULLs for non-null label fields right? wrong!
1051
-            //eg, a CPT model object could have an entry in the posts table, but no
1052
-            //entry in the meta table. Meaning that all its columns in the meta table
1053
-            //are null! yikes! so when we find one like that, use defaults for its meta columns
1054
-            if ($field_value_from_db === null) {
1055
-                if ($field_obj->is_nullable()) {
1056
-                    //if the field allows nulls, then let it be null
1057
-                    $field_value = null;
1058
-                } else {
1059
-                    $field_value = $field_obj->get_default_value();
1060
-                }
1061
-            } else {
1062
-                $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1063
-            }
1064
-            $this->_fields[$field_name] = $field_value;
1065
-            $this->_clear_cached_property($field_name);
1066
-        }
1067
-    }
1068
-
1069
-
1070
-
1071
-    /**
1072
-     * verifies that the specified field is of the correct type
1073
-     *
1074
-     * @param string $field_name
1075
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1076
-     *                                (in cases where the same property may be used for different outputs
1077
-     *                                - i.e. datetime, money etc.)
1078
-     * @return mixed
1079
-     * @throws EE_Error
1080
-     */
1081
-    public function get($field_name, $extra_cache_ref = null)
1082
-    {
1083
-        return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1084
-    }
1085
-
1086
-
1087
-
1088
-    /**
1089
-     * This method simply returns the RAW unprocessed value for the given property in this class
1090
-     *
1091
-     * @param  string $field_name A valid fieldname
1092
-     * @return mixed              Whatever the raw value stored on the property is.
1093
-     * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1094
-     */
1095
-    public function get_raw($field_name)
1096
-    {
1097
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1098
-        switch(true){
1099
-            case $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime:
1100
-                $value = $this->_fields[$field_name]->format('U');
1101
-                break;
1102
-            case $field_settings instanceof EE_Money_Field && $this->_fields[$field_name] instanceof Money:
1103
-                $value = $this->_fields[$field_name]->floatAmount();
1104
-                break;
1105
-            default:
1106
-                $value = $this->_fields[$field_name];
1107
-        }
1108
-        return $value;
1109
-    }
1110
-
1111
-
1112
-
1113
-    /**
1114
-     * This is used to return the internal DateTime object used for a field that is a
1115
-     * EE_Datetime_Field.
1116
-     *
1117
-     * @param string $field_name               The field name retrieving the DateTime object.
1118
-     * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1119
-     * @throws EE_Error
1120
-     *                                         an error is set and false returned.  If the field IS an
1121
-     *                                         EE_Datetime_Field and but the field value is null, then
1122
-     *                                         just null is returned (because that indicates that likely
1123
-     *                                         this field is nullable).
1124
-     */
1125
-    public function get_DateTime_object($field_name)
1126
-    {
1127
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1128
-        if ( ! $field_settings instanceof EE_Datetime_Field) {
1129
-            EE_Error::add_error(
1130
-                sprintf(
1131
-                    __(
1132
-                        'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1133
-                        'event_espresso'
1134
-                    ),
1135
-                    $field_name
1136
-                ),
1137
-                __FILE__,
1138
-                __FUNCTION__,
1139
-                __LINE__
1140
-            );
1141
-            return false;
1142
-        }
1143
-        return $this->_fields[$field_name];
1144
-    }
1145
-
1146
-
1147
-    /**
1148
-     * Gets a Money object for the specified field. Please note that this should only be
1149
-     * used for fields corresponding to EE_Money_Fields, and it will always return a money object,
1150
-     * or else it will throw an exception.
1151
-     *
1152
-     * @param $field_name
1153
-     * @return Money
1154
-     * @throws InvalidEntityException
1155
-     * @throws EE_Error
1156
-     * @throws DomainException
1157
-     * @since $VID:$
1158
-     */
1159
-    public function getMoneyObject($field_name)
1160
-    {
1161
-        $this->verifyUsesMoney(__FUNCTION__);
1162
-        $field = $this->get_model()->field_settings_for($field_name);
1163
-        $value = isset($this->_fields[$field_name]) ? $this->_fields[$field_name] : null;
1164
-        if (! $field instanceof EE_Money_Field
1165
-            || ! $value instanceof Money) {
1166
-            throw new InvalidEntityException(
1167
-                get_class($value),
1168
-                'Money',
1169
-                sprintf(
1170
-                    esc_html__(
1171
-                        // @codingStandardsIgnoreStart
1172
-                        'Tried to retrieve money value from %1$s with ID %2$s from field %3$s but no money object present.',
1173
-                        // @codingStandardsIgnoreEnd
1174
-                        'event_espresso'
1175
-                    ),
1176
-                    get_class($this),
1177
-                    $this->ID(),
1178
-                    $field_name
1179
-                )
1180
-            );
1181
-        }
1182
-        return $value;
1183
-    }
1184
-
1185
-
1186
-
1187
-    /**
1188
-     * To be used in template to immediately echo out the value, and format it for output.
1189
-     * Eg, should call stripslashes and whatnot before echoing
1190
-     *
1191
-     * @param string $field_name      the name of the field as it appears in the DB
1192
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1193
-     *                                (in cases where the same property may be used for different outputs
1194
-     *                                - i.e. datetime, money etc.)
1195
-     * @return void
1196
-     * @throws EE_Error
1197
-     */
1198
-    public function e($field_name, $extra_cache_ref = null)
1199
-    {
1200
-        echo $this->get_pretty($field_name, $extra_cache_ref);
1201
-    }
1202
-
1203
-
1204
-
1205
-    /**
1206
-     * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1207
-     * can be easily used as the value of form input.
1208
-     *
1209
-     * @param string $field_name
1210
-     * @return void
1211
-     * @throws EE_Error
1212
-     */
1213
-    public function f($field_name)
1214
-    {
1215
-        $this->e($field_name, 'form_input');
1216
-    }
1217
-
1218
-    /**
1219
-     * Same as `f()` but just returns the value instead of echoing it
1220
-     * @param string $field_name
1221
-     * @return string
1222
-     * @throws EE_Error
1223
-     */
1224
-    public function get_f($field_name)
1225
-    {
1226
-        return (string)$this->get_pretty($field_name,'form_input');
1227
-    }
1228
-
1229
-
1230
-
1231
-    /**
1232
-     * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1233
-     * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1234
-     * to see what options are available.
1235
-     * @param string $field_name
1236
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1237
-     *                                (in cases where the same property may be used for different outputs
1238
-     *                                - i.e. datetime, money etc.)
1239
-     * @return mixed
1240
-     * @throws EE_Error
1241
-     */
1242
-    public function get_pretty($field_name, $extra_cache_ref = null)
1243
-    {
1244
-        return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1245
-    }
1246
-
1247
-
1248
-
1249
-    /**
1250
-     * This simply returns the datetime for the given field name
1251
-     * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1252
-     * (and the equivalent e_date, e_time, e_datetime).
1253
-     *
1254
-     * @access   protected
1255
-     * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1256
-     * @param string   $dt_frmt      valid datetime format used for date
1257
-     *                               (if '' then we just use the default on the field,
1258
-     *                               if NULL we use the last-used format)
1259
-     * @param string   $tm_frmt      Same as above except this is for time format
1260
-     * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1261
-     * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1262
-     * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1263
-     *                               if field is not a valid dtt field, or void if echoing
1264
-     * @throws EE_Error
1265
-     */
1266
-    protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1267
-    {
1268
-        // clear cached property
1269
-        $this->_clear_cached_property($field_name);
1270
-        //reset format properties because they are used in get()
1271
-        $this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1272
-        $this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1273
-        if ($echo) {
1274
-            $this->e($field_name, $date_or_time);
1275
-            return '';
1276
-        }
1277
-        return $this->get($field_name, $date_or_time);
1278
-    }
1279
-
1280
-
1281
-
1282
-    /**
1283
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1284
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1285
-     * other echoes the pretty value for dtt)
1286
-     *
1287
-     * @param  string $field_name name of model object datetime field holding the value
1288
-     * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1289
-     * @return string            datetime value formatted
1290
-     * @throws EE_Error
1291
-     */
1292
-    public function get_date($field_name, $format = '')
1293
-    {
1294
-        return $this->_get_datetime($field_name, $format, null, 'D');
1295
-    }
1296
-
1297
-
1298
-
1299
-    /**
1300
-     * @param      $field_name
1301
-     * @param string $format
1302
-     * @throws EE_Error
1303
-     */
1304
-    public function e_date($field_name, $format = '')
1305
-    {
1306
-        $this->_get_datetime($field_name, $format, null, 'D', true);
1307
-    }
1308
-
1309
-
1310
-
1311
-    /**
1312
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1313
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1314
-     * other echoes the pretty value for dtt)
1315
-     *
1316
-     * @param  string $field_name name of model object datetime field holding the value
1317
-     * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1318
-     * @return string             datetime value formatted
1319
-     * @throws EE_Error
1320
-     */
1321
-    public function get_time($field_name, $format = '')
1322
-    {
1323
-        return $this->_get_datetime($field_name, null, $format, 'T');
1324
-    }
1325
-
1326
-
1327
-
1328
-    /**
1329
-     * @param      $field_name
1330
-     * @param string $format
1331
-     * @throws EE_Error
1332
-     */
1333
-    public function e_time($field_name, $format = '')
1334
-    {
1335
-        $this->_get_datetime($field_name, null, $format, 'T', true);
1336
-    }
1337
-
1338
-
1339
-
1340
-    /**
1341
-     * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1342
-     * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1343
-     * other echoes the pretty value for dtt)
1344
-     *
1345
-     * @param  string $field_name name of model object datetime field holding the value
1346
-     * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1347
-     * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1348
-     * @return string             datetime value formatted
1349
-     * @throws EE_Error
1350
-     */
1351
-    public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1352
-    {
1353
-        return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1354
-    }
1355
-
1356
-
1357
-
1358
-    /**
1359
-     * @param string $field_name
1360
-     * @param string $dt_frmt
1361
-     * @param string $tm_frmt
1362
-     * @throws EE_Error
1363
-     */
1364
-    public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1365
-    {
1366
-        $this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * Get the i8ln value for a date using the WordPress @see date_i18n function.
1372
-     *
1373
-     * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1374
-     * @param string $format PHP valid date/time string format.  If none is provided then the internal set format
1375
-     *                           on the object will be used.
1376
-     * @return string Date and time string in set locale or false if no field exists for the given
1377
-     * @throws InvalidArgumentException
1378
-     * @throws InvalidInterfaceException
1379
-     * @throws InvalidDataTypeException
1380
-     * @throws EE_Error
1381
-     *                           field name.
1382
-     */
1383
-    public function get_i18n_datetime($field_name, $format = '')
1384
-    {
1385
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1386
-        return date_i18n(
1387
-            $format,
1388
-            EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
1389
-        );
1390
-    }
1391
-
1392
-
1393
-
1394
-    /**
1395
-     * This method validates whether the given field name is a valid field on the model object as well as it is of a
1396
-     * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1397
-     * thrown.
1398
-     *
1399
-     * @param  string $field_name The field name being checked
1400
-     * @throws EE_Error
1401
-     * @return EE_Datetime_Field
1402
-     */
1403
-    protected function _get_dtt_field_settings($field_name)
1404
-    {
1405
-        $field = $this->get_model()->field_settings_for($field_name);
1406
-        //check if field is dtt
1407
-        if ($field instanceof EE_Datetime_Field) {
1408
-            return $field;
1409
-        } else {
1410
-            throw new EE_Error(sprintf(__('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',
1411
-                'event_espresso'), $field_name, self::_get_model_classname(get_class($this))));
1412
-        }
1413
-    }
1414
-
1415
-
1416
-
1417
-
1418
-    /**
1419
-     * NOTE ABOUT BELOW:
1420
-     * These convenience date and time setters are for setting date and time independently.  In other words you might
1421
-     * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1422
-     * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1423
-     * method and make sure you send the entire datetime value for setting.
1424
-     */
1425
-    /**
1426
-     * sets the time on a datetime property
1427
-     *
1428
-     * @access protected
1429
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1430
-     * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1431
-     * @throws EE_Error
1432
-     */
1433
-    protected function _set_time_for($time, $fieldname)
1434
-    {
1435
-        $this->_set_date_time('T', $time, $fieldname);
1436
-    }
1437
-
1438
-
1439
-
1440
-    /**
1441
-     * sets the date on a datetime property
1442
-     *
1443
-     * @access protected
1444
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1445
-     * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1446
-     * @throws EE_Error
1447
-     */
1448
-    protected function _set_date_for($date, $fieldname)
1449
-    {
1450
-        $this->_set_date_time('D', $date, $fieldname);
1451
-    }
1452
-
1453
-
1454
-    /**
1455
-     * This takes care of setting a date or time independently on a given model object property. This method also
1456
-     * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1457
-     *
1458
-     * @access protected
1459
-     * @param string $what "T" for time, 'B' for both, 'D' for Date.
1460
-     * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1461
-     * @param string $fieldname the name of the field the date OR time is being set on (must match a
1462
-     *                                        EE_Datetime_Field property)
1463
-     * @throws InvalidArgumentException
1464
-     * @throws InvalidInterfaceException
1465
-     * @throws InvalidDataTypeException
1466
-     * @throws EE_Error
1467
-     */
1468
-    protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1469
-    {
1470
-        $field = $this->_get_dtt_field_settings($fieldname);
1471
-        $field->set_timezone($this->_timezone);
1472
-        $field->set_date_format($this->_dt_frmt);
1473
-        $field->set_time_format($this->_tm_frmt);
1474
-        switch ($what) {
1475
-            case 'T' :
1476
-                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1477
-                    $datetime_value,
1478
-                    $this->_fields[$fieldname]
1479
-                );
1480
-                break;
1481
-            case 'D' :
1482
-                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1483
-                    $datetime_value,
1484
-                    $this->_fields[$fieldname]
1485
-                );
1486
-                break;
1487
-            case 'B' :
1488
-                $this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1489
-                break;
1490
-        }
1491
-        $this->_clear_cached_property($fieldname);
1492
-    }
1493
-
1494
-
1495
-    /**
1496
-     * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1497
-     * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1498
-     * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1499
-     * that could lead to some unexpected results!
1500
-     *
1501
-     * @access public
1502
-     * @param string $field_name This is the name of the field on the object that contains the date/time
1503
-     *                                         value being returned.
1504
-     * @param string $callback must match a valid method in this class (defaults to get_datetime)
1505
-     * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1506
-     * @param string $prepend You can include something to prepend on the timestamp
1507
-     * @param string $append You can include something to append on the timestamp
1508
-     * @throws InvalidArgumentException
1509
-     * @throws InvalidInterfaceException
1510
-     * @throws InvalidDataTypeException
1511
-     * @throws EE_Error
1512
-     * @return string timestamp
1513
-     */
1514
-    public function display_in_my_timezone(
1515
-        $field_name,
1516
-        $callback = 'get_datetime',
1517
-        $args = null,
1518
-        $prepend = '',
1519
-        $append = ''
1520
-    ) {
1521
-        $timezone = EEH_DTT_Helper::get_timezone();
1522
-        if ($timezone === $this->_timezone) {
1523
-            return '';
1524
-        }
1525
-        $original_timezone = $this->_timezone;
1526
-        $this->set_timezone($timezone);
1527
-        $fn = (array)$field_name;
1528
-        $args = array_merge($fn, (array)$args);
1529
-        if ( ! method_exists($this, $callback)) {
1530
-            throw new EE_Error(
1531
-                sprintf(
1532
-                    __(
1533
-                        'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1534
-                        'event_espresso'
1535
-                    ),
1536
-                    $callback
1537
-                )
1538
-            );
1539
-        }
1540
-        $args = (array)$args;
1541
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1542
-        $this->set_timezone($original_timezone);
1543
-        return $return;
1544
-    }
1545
-
1546
-
1547
-
1548
-    /**
1549
-     * Deletes this model object.
1550
-     * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1551
-     * override
1552
-     * `EE_Base_Class::_delete` NOT this class.
1553
-     *
1554
-     * @return boolean | int
1555
-     * @throws EE_Error
1556
-     */
1557
-    public function delete()
1558
-    {
1559
-        /**
1560
-         * Called just before the `EE_Base_Class::_delete` method call.
1561
-         * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1562
-         * should be aware that `_delete` may not always result in a permanent delete.  For example, `EE_Soft_Delete_Base_Class::_delete`
1563
-         * soft deletes (trash) the object and does not permanently delete it.
1564
-         *
1565
-         * @param EE_Base_Class $model_object about to be 'deleted'
1566
-         */
1567
-        do_action('AHEE__EE_Base_Class__delete__before', $this);
1568
-        $result = $this->_delete();
1569
-        /**
1570
-         * Called just after the `EE_Base_Class::_delete` method call.
1571
-         * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1572
-         * should be aware that `_delete` may not always result in a permanent delete.  For example `EE_Soft_Base_Class::_delete`
1573
-         * soft deletes (trash) the object and does not permanently delete it.
1574
-         *
1575
-         * @param EE_Base_Class $model_object that was just 'deleted'
1576
-         * @param boolean       $result
1577
-         */
1578
-        do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1579
-        return $result;
1580
-    }
1581
-
1582
-
1583
-
1584
-    /**
1585
-     * Calls the specific delete method for the instantiated class.
1586
-     * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1587
-     * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1588
-     * `EE_Base_Class::delete`
1589
-     *
1590
-     * @return bool|int
1591
-     * @throws EE_Error
1592
-     */
1593
-    protected function _delete()
1594
-    {
1595
-        return $this->delete_permanently();
1596
-    }
1597
-
1598
-
1599
-
1600
-    /**
1601
-     * Deletes this model object permanently from db (but keep in mind related models my block the delete and return an
1602
-     * error)
1603
-     *
1604
-     * @return bool | int
1605
-     * @throws EE_Error
1606
-     */
1607
-    public function delete_permanently()
1608
-    {
1609
-        /**
1610
-         * Called just before HARD deleting a model object
1611
-         *
1612
-         * @param EE_Base_Class $model_object about to be 'deleted'
1613
-         */
1614
-        do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1615
-        $model = $this->get_model();
1616
-        $result = $model->delete_permanently_by_ID($this->ID());
1617
-        $this->refresh_cache_of_related_objects();
1618
-        /**
1619
-         * Called just after HARD deleting a model object
1620
-         *
1621
-         * @param EE_Base_Class $model_object that was just 'deleted'
1622
-         * @param boolean       $result
1623
-         */
1624
-        do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1625
-        return $result;
1626
-    }
1627
-
1628
-
1629
-
1630
-    /**
1631
-     * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1632
-     * related model objects
1633
-     *
1634
-     * @throws EE_Error
1635
-     */
1636
-    public function refresh_cache_of_related_objects()
1637
-    {
1638
-        $model = $this->get_model();
1639
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1640
-            if ( ! empty($this->_model_relations[$relation_name])) {
1641
-                $related_objects = $this->_model_relations[$relation_name];
1642
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
1643
-                    //this relation only stores a single model object, not an array
1644
-                    //but let's make it consistent
1645
-                    $related_objects = array($related_objects);
1646
-                }
1647
-                foreach ($related_objects as $related_object) {
1648
-                    //only refresh their cache if they're in memory
1649
-                    if ($related_object instanceof EE_Base_Class) {
1650
-                        $related_object->clear_cache($model->get_this_model_name(), $this);
1651
-                    }
1652
-                }
1653
-            }
1654
-        }
1655
-    }
1656
-
1657
-
1658
-
1659
-    /**
1660
-     *        Saves this object to the database. An array may be supplied to set some values on this
1661
-     * object just before saving.
1662
-     *
1663
-     * @access public
1664
-     * @param array $set_cols_n_values keys are field names, values are their new values,
1665
-     *                                 if provided during the save() method (often client code will change the fields'
1666
-     *                                 values before calling save)
1667
-     * @throws EE_Error
1668
-     * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1669
-     *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1670
-     */
1671
-    public function save($set_cols_n_values = array())
1672
-    {
1673
-        $model = $this->get_model();
1674
-        /**
1675
-         * Filters the fields we're about to save on the model object
1676
-         *
1677
-         * @param array         $set_cols_n_values
1678
-         * @param EE_Base_Class $model_object
1679
-         */
1680
-        $set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1681
-            $this);
1682
-        //set attributes as provided in $set_cols_n_values
1683
-        foreach ($set_cols_n_values as $column => $value) {
1684
-            $this->set($column, $value);
1685
-        }
1686
-        // no changes ? then don't do anything
1687
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1688
-            return 0;
1689
-        }
1690
-        /**
1691
-         * Saving a model object.
1692
-         * Before we perform a save, this action is fired.
1693
-         *
1694
-         * @param EE_Base_Class $model_object the model object about to be saved.
1695
-         */
1696
-        do_action('AHEE__EE_Base_Class__save__begin', $this);
1697
-        if ( ! $this->allow_persist()) {
1698
-            return 0;
1699
-        }
1700
-        //now get current attribute values
1701
-        $save_cols_n_values = $this->_fields;
1702
-        //if the object already has an ID, update it. Otherwise, insert it
1703
-        //also: change the assumption about values passed to the model NOT being prepare dby the model object. They have been
1704
-        $old_assumption_concerning_value_preparation = $model
1705
-                                                            ->get_assumption_concerning_values_already_prepared_by_model_object();
1706
-        $model->assume_values_already_prepared_by_model_object(true);
1707
-        //does this model have an autoincrement PK?
1708
-        if ($model->has_primary_key_field()) {
1709
-            if ($model->get_primary_key_field()->is_auto_increment()) {
1710
-                //ok check if it's set, if so: update; if not, insert
1711
-                if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1712
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1713
-                } else {
1714
-                    unset($save_cols_n_values[$model->primary_key_name()]);
1715
-                    $results = $model->insert($save_cols_n_values);
1716
-                    if ($results) {
1717
-                        //if successful, set the primary key
1718
-                        //but don't use the normal SET method, because it will check if
1719
-                        //an item with the same ID exists in the mapper & db, then
1720
-                        //will find it in the db (because we just added it) and THAT object
1721
-                        //will get added to the mapper before we can add this one!
1722
-                        //but if we just avoid using the SET method, all that headache can be avoided
1723
-                        $pk_field_name = $model->primary_key_name();
1724
-                        $this->_fields[$pk_field_name] = $results;
1725
-                        $this->_clear_cached_property($pk_field_name);
1726
-                        $model->add_to_entity_map($this);
1727
-                        $this->_update_cached_related_model_objs_fks();
1728
-                    }
1729
-                }
1730
-            } else {//PK is NOT auto-increment
1731
-                //so check if one like it already exists in the db
1732
-                if ($model->exists_by_ID($this->ID())) {
1733
-                    if (WP_DEBUG && ! $this->in_entity_map()) {
1734
-                        throw new EE_Error(
1735
-                            sprintf(
1736
-                                __('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',
1737
-                                    'event_espresso'),
1738
-                                get_class($this),
1739
-                                get_class($model) . '::instance()->add_to_entity_map()',
1740
-                                get_class($model) . '::instance()->get_one_by_ID()',
1741
-                                '<br />'
1742
-                            )
1743
-                        );
1744
-                    }
1745
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1746
-                } else {
1747
-                    $results = $model->insert($save_cols_n_values);
1748
-                    $this->_update_cached_related_model_objs_fks();
1749
-                }
1750
-            }
1751
-        } else {//there is NO primary key
1752
-            $already_in_db = false;
1753
-            foreach ($model->unique_indexes() as $index) {
1754
-                $uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1755
-                if ($model->exists(array($uniqueness_where_params))) {
1756
-                    $already_in_db = true;
1757
-                }
1758
-            }
1759
-            if ($already_in_db) {
1760
-                $combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1761
-                    $model->get_combined_primary_key_fields());
1762
-                $results = $model->update($save_cols_n_values, $combined_pk_fields_n_values);
1763
-            } else {
1764
-                $results = $model->insert($save_cols_n_values);
1765
-            }
1766
-        }
1767
-        //restore the old assumption about values being prepared by the model object
1768
-        $model
1769
-             ->assume_values_already_prepared_by_model_object($old_assumption_concerning_value_preparation);
1770
-        /**
1771
-         * After saving the model object this action is called
1772
-         *
1773
-         * @param EE_Base_Class $model_object which was just saved
1774
-         * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1775
-         *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1776
-         */
1777
-        do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1778
-        $this->_has_changes = false;
1779
-        return $results;
1780
-    }
1781
-
1782
-
1783
-
1784
-    /**
1785
-     * Updates the foreign key on related models objects pointing to this to have this model object's ID
1786
-     * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1787
-     * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1788
-     * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1789
-     * 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
1790
-     * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1791
-     * or not they exist in the DB (if they do, their DB records will be automatically updated)
1792
-     *
1793
-     * @return void
1794
-     * @throws EE_Error
1795
-     */
1796
-    protected function _update_cached_related_model_objs_fks()
1797
-    {
1798
-        $model = $this->get_model();
1799
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1800
-            if ($relation_obj instanceof EE_Has_Many_Relation) {
1801
-                foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1802
-                    $fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1803
-                        $model->get_this_model_name()
1804
-                    );
1805
-                    $related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1806
-                    if ($related_model_obj_in_cache->ID()) {
1807
-                        $related_model_obj_in_cache->save();
1808
-                    }
1809
-                }
1810
-            }
1811
-        }
1812
-    }
1813
-
1814
-
1815
-
1816
-    /**
1817
-     * Saves this model object and its NEW cached relations to the database.
1818
-     * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1819
-     * In order for that to work, we would need to mark model objects as dirty/clean...
1820
-     * because otherwise, there's a potential for infinite looping of saving
1821
-     * Saves the cached related model objects, and ensures the relation between them
1822
-     * and this object and properly setup
1823
-     *
1824
-     * @return int ID of new model object on save; 0 on failure+
1825
-     * @throws EE_Error
1826
-     */
1827
-    public function save_new_cached_related_model_objs()
1828
-    {
1829
-        //make sure this has been saved
1830
-        if ( ! $this->ID()) {
1831
-            $id = $this->save();
1832
-        } else {
1833
-            $id = $this->ID();
1834
-        }
1835
-        //now save all the NEW cached model objects  (ie they don't exist in the DB)
1836
-        foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1837
-            if ($this->_model_relations[$relationName]) {
1838
-                //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1839
-                //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1840
-                if ($relationObj instanceof EE_Belongs_To_Relation) {
1841
-                    //add a relation to that relation type (which saves the appropriate thing in the process)
1842
-                    //but ONLY if it DOES NOT exist in the DB
1843
-                    /* @var $related_model_obj EE_Base_Class */
1844
-                    $related_model_obj = $this->_model_relations[$relationName];
1845
-                    //					if( ! $related_model_obj->ID()){
1846
-                    $this->_add_relation_to($related_model_obj, $relationName);
1847
-                    $related_model_obj->save_new_cached_related_model_objs();
1848
-                    //					}
1849
-                } else {
1850
-                    foreach ($this->_model_relations[$relationName] as $related_model_obj) {
1851
-                        //add a relation to that relation type (which saves the appropriate thing in the process)
1852
-                        //but ONLY if it DOES NOT exist in the DB
1853
-                        //						if( ! $related_model_obj->ID()){
1854
-                        $this->_add_relation_to($related_model_obj, $relationName);
1855
-                        $related_model_obj->save_new_cached_related_model_objs();
1856
-                        //						}
1857
-                    }
1858
-                }
1859
-            }
1860
-        }
1861
-        return $id;
1862
-    }
1863
-
1864
-
1865
-
1866
-    /**
1867
-     * for getting a model while instantiated.
1868
-     *
1869
-     * @return EEM_Base | EEM_CPT_Base
1870
-     */
1871
-    public function get_model()
1872
-    {
1873
-        if( ! $this->_model){
1874
-            $modelName = self::_get_model_classname(get_class($this));
1875
-            $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1876
-        } else {
1877
-            $this->_model->set_timezone($this->_timezone);
1878
-        }
1879
-
1880
-        return $this->_model;
1881
-    }
1882
-
1883
-
1884
-
1885
-    /**
1886
-     * @param $props_n_values
1887
-     * @param $classname
1888
-     * @return mixed bool|EE_Base_Class|EEM_CPT_Base
1889
-     * @throws EE_Error
1890
-     */
1891
-    protected static function _get_object_from_entity_mapper($props_n_values, $classname)
1892
-    {
1893
-        //TODO: will not work for Term_Relationships because they have no PK!
1894
-        $primary_id_ref = self::_get_primary_key_name($classname);
1895
-        if (array_key_exists($primary_id_ref, $props_n_values) && ! empty($props_n_values[$primary_id_ref])) {
1896
-            $id = $props_n_values[$primary_id_ref];
1897
-            return self::_get_model($classname)->get_from_entity_map($id);
1898
-        }
1899
-        return false;
1900
-    }
1901
-
1902
-
1903
-
1904
-    /**
1905
-     * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
1906
-     * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
1907
-     * 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
1908
-     * we return false.
1909
-     *
1910
-     * @param  array  $props_n_values   incoming array of properties and their values
1911
-     * @param  string $classname        the classname of the child class
1912
-     * @param null    $timezone
1913
-     * @param array   $date_formats     incoming date_formats in an array where the first value is the
1914
-     *                                  date_format and the second value is the time format
1915
-     * @return mixed (EE_Base_Class|bool)
1916
-     * @throws EE_Error
1917
-     */
1918
-    protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
1919
-    {
1920
-        $existing = null;
1921
-        $model = self::_get_model($classname, $timezone);
1922
-        if ($model->has_primary_key_field()) {
1923
-            $primary_id_ref = self::_get_primary_key_name($classname);
1924
-            if (array_key_exists($primary_id_ref, $props_n_values)
1925
-                && ! empty($props_n_values[$primary_id_ref])
1926
-            ) {
1927
-                $existing = $model->get_one_by_ID(
1928
-                    $props_n_values[$primary_id_ref]
1929
-                );
1930
-            }
1931
-        } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
1932
-            //no primary key on this model, but there's still a matching item in the DB
1933
-            $existing = self::_get_model($classname, $timezone)->get_one_by_ID(
1934
-                self::_get_model($classname, $timezone)->get_index_primary_key_string($props_n_values)
1935
-            );
1936
-        }
1937
-        if ($existing) {
1938
-            //set date formats if present before setting values
1939
-            if ( ! empty($date_formats) && is_array($date_formats)) {
1940
-                $existing->set_date_format($date_formats[0]);
1941
-                $existing->set_time_format($date_formats[1]);
1942
-            } else {
1943
-                //set default formats for date and time
1944
-                $existing->set_date_format(get_option('date_format'));
1945
-                $existing->set_time_format(get_option('time_format'));
1946
-            }
1947
-            foreach ($props_n_values as $property => $field_value) {
1948
-                $existing->set($property, $field_value);
1949
-            }
1950
-            return $existing;
1951
-        } else {
1952
-            return false;
1953
-        }
1954
-    }
1955
-
1956
-
1957
-
1958
-    /**
1959
-     * Gets the EEM_*_Model for this class
1960
-     *
1961
-     * @access public now, as this is more convenient
1962
-     * @param      $classname
1963
-     * @param null $timezone
1964
-     * @throws EE_Error
1965
-     * @return EEM_Base
1966
-     */
1967
-    protected static function _get_model($classname, $timezone = null)
1968
-    {
1969
-        //find model for this class
1970
-        if ( ! $classname) {
1971
-            throw new EE_Error(
1972
-                sprintf(
1973
-                    __(
1974
-                        "What were you thinking calling _get_model(%s)?? You need to specify the class name",
1975
-                        "event_espresso"
1976
-                    ),
1977
-                    $classname
1978
-                )
1979
-            );
1980
-        }
1981
-        $modelName = self::_get_model_classname($classname);
1982
-        return self::_get_model_instance_with_name($modelName, $timezone);
1983
-    }
1984
-
1985
-
1986
-    /**
1987
-     * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
1988
-     *
1989
-     * @param string $model_classname
1990
-     * @param null $timezone
1991
-     * @return EEM_Base
1992
-     * @throws \ReflectionException
1993
-     * @throws InvalidArgumentException
1994
-     * @throws InvalidInterfaceException
1995
-     * @throws InvalidDataTypeException
1996
-     * @throws EE_Error
1997
-     */
1998
-    protected static function _get_model_instance_with_name($model_classname, $timezone = null)
1999
-    {
2000
-        $model_classname = str_replace('EEM_', '', $model_classname);
2001
-        $model = EE_Registry::instance()->load_model($model_classname);
2002
-        $model->set_timezone($timezone);
2003
-        return $model;
2004
-    }
2005
-
2006
-
2007
-
2008
-    /**
2009
-     * If a model name is provided (eg Registration), gets the model classname for that model.
2010
-     * Also works if a model class's classname is provided (eg EE_Registration).
2011
-     *
2012
-     * @param null $model_name
2013
-     * @return string like EEM_Attendee
2014
-     */
2015
-    private static function _get_model_classname($model_name = null)
2016
-    {
2017
-        if (strpos($model_name, "EE_") === 0) {
2018
-            $model_classname = str_replace("EE_", "EEM_", $model_name);
2019
-        } else {
2020
-            $model_classname = "EEM_" . $model_name;
2021
-        }
2022
-        return $model_classname;
2023
-    }
2024
-
2025
-
2026
-
2027
-    /**
2028
-     * returns the name of the primary key attribute
2029
-     *
2030
-     * @param null $classname
2031
-     * @throws EE_Error
2032
-     * @return string
2033
-     */
2034
-    protected static function _get_primary_key_name($classname = null)
2035
-    {
2036
-        if ( ! $classname) {
2037
-            throw new EE_Error(
2038
-                sprintf(
2039
-                    __("What were you thinking calling _get_primary_key_name(%s)", "event_espresso"),
2040
-                    $classname
2041
-                )
2042
-            );
2043
-        }
2044
-        return self::_get_model($classname)->get_primary_key_field()->get_name();
2045
-    }
2046
-
2047
-
2048
-
2049
-    /**
2050
-     * Gets the value of the primary key.
2051
-     * If the object hasn't yet been saved, it should be whatever the model field's default was
2052
-     * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2053
-     * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2054
-     *
2055
-     * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2056
-     * @throws EE_Error
2057
-     */
2058
-    public function ID()
2059
-    {
2060
-        $model = $this->get_model();
2061
-        //now that we know the name of the variable, use a variable variable to get its value and return its
2062
-        if ($model->has_primary_key_field()) {
2063
-            return $this->_fields[$model->primary_key_name()];
2064
-        } else {
2065
-            return $model->get_index_primary_key_string($this->_fields);
2066
-        }
2067
-    }
2068
-
2069
-
2070
-
2071
-    /**
2072
-     * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2073
-     * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2074
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2075
-     *
2076
-     * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2077
-     * @param string $relationName                     eg 'Events','Question',etc.
2078
-     *                                                 an attendee to a group, you also want to specify which role they
2079
-     *                                                 will have in that group. So you would use this parameter to
2080
-     *                                                 specify array('role-column-name'=>'role-id')
2081
-     * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2082
-     *                                                 allow you to further constrict the relation to being added.
2083
-     *                                                 However, keep in mind that the columns (keys) given must match a
2084
-     *                                                 column on the JOIN table and currently only the HABTM models
2085
-     *                                                 accept these additional conditions.  Also remember that if an
2086
-     *                                                 exact match isn't found for these extra cols/val pairs, then a
2087
-     *                                                 NEW row is created in the join table.
2088
-     * @param null   $cache_id
2089
-     * @throws EE_Error
2090
-     * @return EE_Base_Class the object the relation was added to
2091
-     */
2092
-    public function _add_relation_to(
2093
-        $otherObjectModelObjectOrID,
2094
-        $relationName,
2095
-        $extra_join_model_fields_n_values = array(),
2096
-        $cache_id = null
2097
-    ) {
2098
-        $model = $this->get_model();
2099
-        //if this thing exists in the DB, save the relation to the DB
2100
-        if ($this->ID()) {
2101
-            $otherObject = $model
2102
-                                ->add_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2103
-                                    $extra_join_model_fields_n_values);
2104
-            //clear cache so future get_many_related and get_first_related() return new results.
2105
-            $this->clear_cache($relationName, $otherObject, true);
2106
-            if ($otherObject instanceof EE_Base_Class) {
2107
-                $otherObject->clear_cache($model->get_this_model_name(), $this);
2108
-            }
2109
-        } else {
2110
-            //this thing doesn't exist in the DB,  so just cache it
2111
-            if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2112
-                throw new EE_Error(sprintf(
2113
-                    __('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',
2114
-                        'event_espresso'),
2115
-                    $otherObjectModelObjectOrID,
2116
-                    get_class($this)
2117
-                ));
2118
-            } else {
2119
-                $otherObject = $otherObjectModelObjectOrID;
2120
-            }
2121
-            $this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2122
-        }
2123
-        if ($otherObject instanceof EE_Base_Class) {
2124
-            //fix the reciprocal relation too
2125
-            if ($otherObject->ID()) {
2126
-                //its saved so assumed relations exist in the DB, so we can just
2127
-                //clear the cache so future queries use the updated info in the DB
2128
-                $otherObject->clear_cache($model->get_this_model_name(), null, true);
2129
-            } else {
2130
-                //it's not saved, so it caches relations like this
2131
-                $otherObject->cache($model->get_this_model_name(), $this);
2132
-            }
2133
-        }
2134
-        return $otherObject;
2135
-    }
2136
-
2137
-
2138
-
2139
-    /**
2140
-     * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2141
-     * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2142
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2143
-     * from the cache
2144
-     *
2145
-     * @param mixed  $otherObjectModelObjectOrID
2146
-     *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2147
-     *                to the DB yet
2148
-     * @param string $relationName
2149
-     * @param array  $where_query
2150
-     *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2151
-     *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2152
-     *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2153
-     *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2154
-     *                created in the join table.
2155
-     * @return EE_Base_Class the relation was removed from
2156
-     * @throws EE_Error
2157
-     */
2158
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2159
-    {
2160
-        if ($this->ID()) {
2161
-            //if this exists in the DB, save the relation change to the DB too
2162
-            $otherObject = $this->get_model()
2163
-                                ->remove_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2164
-                                    $where_query);
2165
-            $this->clear_cache($relationName, $otherObject);
2166
-        } else {
2167
-            //this doesn't exist in the DB, just remove it from the cache
2168
-            $otherObject = $this->clear_cache($relationName, $otherObjectModelObjectOrID);
2169
-        }
2170
-        if ($otherObject instanceof EE_Base_Class) {
2171
-            $otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2172
-        }
2173
-        return $otherObject;
2174
-    }
2175
-
2176
-
2177
-
2178
-    /**
2179
-     * Removes ALL the related things for the $relationName.
2180
-     *
2181
-     * @param string $relationName
2182
-     * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2183
-     * @return EE_Base_Class
2184
-     * @throws EE_Error
2185
-     */
2186
-    public function _remove_relations($relationName, $where_query_params = array())
2187
-    {
2188
-        if ($this->ID()) {
2189
-            //if this exists in the DB, save the relation change to the DB too
2190
-            $otherObjects = $this->get_model()->remove_relations($this, $relationName, $where_query_params);
2191
-            $this->clear_cache($relationName, null, true);
2192
-        } else {
2193
-            //this doesn't exist in the DB, just remove it from the cache
2194
-            $otherObjects = $this->clear_cache($relationName, null, true);
2195
-        }
2196
-        if (is_array($otherObjects)) {
2197
-            foreach ($otherObjects as $otherObject) {
2198
-                $otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2199
-            }
2200
-        }
2201
-        return $otherObjects;
2202
-    }
2203
-
2204
-
2205
-
2206
-    /**
2207
-     * Gets all the related model objects of the specified type. Eg, if the current class if
2208
-     * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2209
-     * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2210
-     * because we want to get even deleted items etc.
2211
-     *
2212
-     * @param string $relationName key in the model's _model_relations array
2213
-     * @param array  $query_params like EEM_Base::get_all
2214
-     * @return EE_Base_Class[] Results not necessarily indexed by IDs, because some results might not have primary keys
2215
-     * @throws EE_Error
2216
-     *                             or might not be saved yet. Consider using EEM_Base::get_IDs() on these results if
2217
-     *                             you want IDs
2218
-     */
2219
-    public function get_many_related($relationName, $query_params = array())
2220
-    {
2221
-        if ($this->ID()) {
2222
-            //this exists in the DB, so get the related things from either the cache or the DB
2223
-            //if there are query parameters, forget about caching the related model objects.
2224
-            if ($query_params) {
2225
-                $related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2226
-            } else {
2227
-                //did we already cache the result of this query?
2228
-                $cached_results = $this->get_all_from_cache($relationName);
2229
-                if ( ! $cached_results) {
2230
-                    $related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2231
-                    //if no query parameters were passed, then we got all the related model objects
2232
-                    //for that relation. We can cache them then.
2233
-                    foreach ($related_model_objects as $related_model_object) {
2234
-                        $this->cache($relationName, $related_model_object);
2235
-                    }
2236
-                } else {
2237
-                    $related_model_objects = $cached_results;
2238
-                }
2239
-            }
2240
-        } else {
2241
-            //this doesn't exist in the DB, so just get the related things from the cache
2242
-            $related_model_objects = $this->get_all_from_cache($relationName);
2243
-        }
2244
-        return $related_model_objects;
2245
-    }
2246
-
2247
-
2248
-    /**
2249
-     * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2250
-     * unless otherwise specified in the $query_params
2251
-     *
2252
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2253
-     * @param array $query_params like EEM_Base::get_all's
2254
-     * @param string $field_to_count name of field to count by. By default, uses primary key
2255
-     * @param bool $distinct if we want to only count the distinct values for the column then you can trigger
2256
-     *                               that by the setting $distinct to TRUE;
2257
-     * @return int
2258
-     * @throws EE_Error
2259
-     */
2260
-    public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2261
-    {
2262
-        return $this->get_model()->count_related($this, $relation_name, $query_params, $field_to_count, $distinct);
2263
-    }
2264
-
2265
-
2266
-    /**
2267
-     * Instead of getting the related model objects, simply sums up the values of the specified field.
2268
-     * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2269
-     *
2270
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2271
-     * @param array $query_params like EEM_Base::get_all's
2272
-     * @param string $field_to_sum name of field to count by.
2273
-     *                              By default, uses primary key (which doesn't make much sense, so you should probably
2274
-     *                              change it)
2275
-     * @return int
2276
-     * @throws EE_Error
2277
-     */
2278
-    public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2279
-    {
2280
-        return $this->get_model()->sum_related($this, $relation_name, $query_params, $field_to_sum);
2281
-    }
2282
-
2283
-
2284
-
2285
-    /**
2286
-     * Gets the first (ie, one) related model object of the specified type.
2287
-     *
2288
-     * @param string $relationName key in the model's _model_relations array
2289
-     * @param array  $query_params like EEM_Base::get_all
2290
-     * @return EE_Base_Class (not an array, a single object)
2291
-     * @throws EE_Error
2292
-     */
2293
-    public function get_first_related($relationName, $query_params = array())
2294
-    {
2295
-        $model = $this->get_model();
2296
-        if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2297
-            //if they've provided some query parameters, don't bother trying to cache the result
2298
-            //also make sure we're not caching the result of get_first_related
2299
-            //on a relation which should have an array of objects (because the cache might have an array of objects)
2300
-            if ($query_params
2301
-                || ! $model->related_settings_for($relationName)
2302
-                     instanceof
2303
-                     EE_Belongs_To_Relation
2304
-            ) {
2305
-                $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2306
-            } else {
2307
-                //first, check if we've already cached the result of this query
2308
-                $cached_result = $this->get_one_from_cache($relationName);
2309
-                if ( ! $cached_result) {
2310
-                    $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2311
-                    $this->cache($relationName, $related_model_object);
2312
-                } else {
2313
-                    $related_model_object = $cached_result;
2314
-                }
2315
-            }
2316
-        } else {
2317
-            $related_model_object = null;
2318
-            //this doesn't exist in the Db, but maybe the relation is of type belongs to, and so the related thing might
2319
-            if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2320
-                $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2321
-            }
2322
-            //this doesn't exist in the DB and apparently the thing it belongs to doesn't either, just get what's cached on this object
2323
-            if ( ! $related_model_object) {
2324
-                $related_model_object = $this->get_one_from_cache($relationName);
2325
-            }
2326
-        }
2327
-        return $related_model_object;
2328
-    }
2329
-
2330
-
2331
-
2332
-    /**
2333
-     * Does a delete on all related objects of type $relationName and removes
2334
-     * the current model object's relation to them. If they can't be deleted (because
2335
-     * of blocking related model objects) does nothing. If the related model objects are
2336
-     * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2337
-     * If this model object doesn't exist yet in the DB, just removes its related things
2338
-     *
2339
-     * @param string $relationName
2340
-     * @param array  $query_params like EEM_Base::get_all's
2341
-     * @return int how many deleted
2342
-     * @throws EE_Error
2343
-     */
2344
-    public function delete_related($relationName, $query_params = array())
2345
-    {
2346
-        if ($this->ID()) {
2347
-            $count = $this->get_model()->delete_related($this, $relationName, $query_params);
2348
-        } else {
2349
-            $count = count($this->get_all_from_cache($relationName));
2350
-            $this->clear_cache($relationName, null, true);
2351
-        }
2352
-        return $count;
2353
-    }
2354
-
2355
-
2356
-
2357
-    /**
2358
-     * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2359
-     * the current model object's relation to them. If they can't be deleted (because
2360
-     * of blocking related model objects) just does a soft delete on it instead, if possible.
2361
-     * If the related thing isn't a soft-deletable model object, this function is identical
2362
-     * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2363
-     *
2364
-     * @param string $relationName
2365
-     * @param array  $query_params like EEM_Base::get_all's
2366
-     * @return int how many deleted (including those soft deleted)
2367
-     * @throws EE_Error
2368
-     */
2369
-    public function delete_related_permanently($relationName, $query_params = array())
2370
-    {
2371
-        if ($this->ID()) {
2372
-            $count = $this->get_model()->delete_related_permanently($this, $relationName, $query_params);
2373
-        } else {
2374
-            $count = count($this->get_all_from_cache($relationName));
2375
-        }
2376
-        $this->clear_cache($relationName, null, true);
2377
-        return $count;
2378
-    }
2379
-
2380
-
2381
-
2382
-    /**
2383
-     * is_set
2384
-     * Just a simple utility function children can use for checking if property exists
2385
-     *
2386
-     * @access  public
2387
-     * @param  string $field_name property to check
2388
-     * @return bool                              TRUE if existing,FALSE if not.
2389
-     */
2390
-    public function is_set($field_name)
2391
-    {
2392
-        return isset($this->_fields[$field_name]);
2393
-    }
2394
-
2395
-
2396
-
2397
-    /**
2398
-     * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2399
-     * EE_Error exception if they don't
2400
-     *
2401
-     * @param  mixed (string|array) $properties properties to check
2402
-     * @throws EE_Error
2403
-     * @return bool                              TRUE if existing, throw EE_Error if not.
2404
-     */
2405
-    protected function _property_exists($properties)
2406
-    {
2407
-        foreach ((array)$properties as $property_name) {
2408
-            //first make sure this property exists
2409
-            if ( ! $this->_fields[$property_name]) {
2410
-                throw new EE_Error(
2411
-                    sprintf(
2412
-                        __(
2413
-                            'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2414
-                            'event_espresso'
2415
-                        ),
2416
-                        $property_name
2417
-                    )
2418
-                );
2419
-            }
2420
-        }
2421
-        return true;
2422
-    }
2423
-
2424
-
2425
-
2426
-    /**
2427
-     * This simply returns an array of model fields for this object
2428
-     *
2429
-     * @return array
2430
-     * @throws EE_Error
2431
-     */
2432
-    public function model_field_array()
2433
-    {
2434
-        $fields = $this->get_model()->field_settings(false);
2435
-        $properties = array();
2436
-        //remove prepended underscore
2437
-        foreach ($fields as $field_name => $settings) {
2438
-            $properties[$field_name] = $this->get($field_name);
2439
-        }
2440
-        return $properties;
2441
-    }
2442
-
2443
-
2444
-
2445
-    /**
2446
-     * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2447
-     * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2448
-     * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
2449
-     * requiring a plugin to extend the EE_Base_Class (which works fine is there's only 1 plugin, but when will that
2450
-     * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
2451
-     * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
2452
-     * was called, and an array of the original arguments passed to the function. Whatever their callback function
2453
-     * returns will be returned by this function. Example: in functions.php (or in a plugin):
2454
-     * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
2455
-     * my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2456
-     * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2457
-     *        return $previousReturnValue.$returnString;
2458
-     * }
2459
-     * require('EE_Answer.class.php');
2460
-     * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2461
-     * echo $answer->my_callback('monkeys',100);
2462
-     * //will output "you called my_callback! and passed args:monkeys,100"
2463
-     *
2464
-     * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2465
-     * @param array  $args       array of original arguments passed to the function
2466
-     * @throws EE_Error
2467
-     * @return mixed whatever the plugin which calls add_filter decides
2468
-     */
2469
-    public function __call($methodName, $args)
2470
-    {
2471
-        $className = get_class($this);
2472
-        $tagName = "FHEE__{$className}__{$methodName}";
2473
-        if ( ! has_filter($tagName)) {
2474
-            throw new EE_Error(
2475
-                sprintf(
2476
-                    __(
2477
-                        "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;}",
2478
-                        "event_espresso"
2479
-                    ),
2480
-                    $methodName,
2481
-                    $className,
2482
-                    $tagName
2483
-                )
2484
-            );
2485
-        }
2486
-        return apply_filters($tagName, null, $this, $args);
2487
-    }
2488
-
2489
-
2490
-    /**
2491
-     * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2492
-     * A $previous_value can be specified in case there are many meta rows with the same key
2493
-     *
2494
-     * @param string $meta_key
2495
-     * @param mixed $meta_value
2496
-     * @param mixed $previous_value
2497
-     * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2498
-     * @throws InvalidArgumentException
2499
-     * @throws InvalidInterfaceException
2500
-     * @throws InvalidDataTypeException
2501
-     * @throws EE_Error
2502
-     * NOTE: if the values haven't changed, returns 0
2503
-     */
2504
-    public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2505
-    {
2506
-        $query_params = array(
2507
-            array(
2508
-                'EXM_key'  => $meta_key,
2509
-                'OBJ_ID'   => $this->ID(),
2510
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2511
-            ),
2512
-        );
2513
-        if ($previous_value !== null) {
2514
-            $query_params[0]['EXM_value'] = $meta_value;
2515
-        }
2516
-        $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2517
-        if ( ! $existing_rows_like_that) {
2518
-            return $this->add_extra_meta($meta_key, $meta_value);
2519
-        }
2520
-        foreach ($existing_rows_like_that as $existing_row) {
2521
-            $existing_row->save(array('EXM_value' => $meta_value));
2522
-        }
2523
-        return count($existing_rows_like_that);
2524
-    }
2525
-
2526
-
2527
-    /**
2528
-     * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2529
-     * no other extra meta for this model object have the same key. Returns TRUE if the
2530
-     * extra meta row was entered, false if not
2531
-     *
2532
-     * @param string $meta_key
2533
-     * @param mixed $meta_value
2534
-     * @param boolean $unique
2535
-     * @return boolean
2536
-     * @throws InvalidArgumentException
2537
-     * @throws InvalidInterfaceException
2538
-     * @throws InvalidDataTypeException
2539
-     * @throws EE_Error
2540
-     */
2541
-    public function add_extra_meta($meta_key, $meta_value, $unique = false)
2542
-    {
2543
-        if ($unique) {
2544
-            $existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2545
-                array(
2546
-                    array(
2547
-                        'EXM_key'  => $meta_key,
2548
-                        'OBJ_ID'   => $this->ID(),
2549
-                        'EXM_type' => $this->get_model()->get_this_model_name(),
2550
-                    ),
2551
-                )
2552
-            );
2553
-            if ($existing_extra_meta) {
2554
-                return false;
2555
-            }
2556
-        }
2557
-        $new_extra_meta = EE_Extra_Meta::new_instance(
2558
-            array(
2559
-                'EXM_key'   => $meta_key,
2560
-                'EXM_value' => $meta_value,
2561
-                'OBJ_ID'    => $this->ID(),
2562
-                'EXM_type'  => $this->get_model()->get_this_model_name(),
2563
-            )
2564
-        );
2565
-        $new_extra_meta->save();
2566
-        return true;
2567
-    }
2568
-
2569
-
2570
-    /**
2571
-     * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2572
-     * is specified, only deletes extra meta records with that value.
2573
-     *
2574
-     * @param string $meta_key
2575
-     * @param mixed $meta_value
2576
-     * @return int number of extra meta rows deleted
2577
-     * @throws InvalidArgumentException
2578
-     * @throws InvalidInterfaceException
2579
-     * @throws InvalidDataTypeException
2580
-     * @throws EE_Error
2581
-     */
2582
-    public function delete_extra_meta($meta_key, $meta_value = null)
2583
-    {
2584
-        $query_params = array(
2585
-            array(
2586
-                'EXM_key'  => $meta_key,
2587
-                'OBJ_ID'   => $this->ID(),
2588
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2589
-            ),
2590
-        );
2591
-        if ($meta_value !== null) {
2592
-            $query_params[0]['EXM_value'] = $meta_value;
2593
-        }
2594
-        return EEM_Extra_Meta::instance()->delete($query_params);
2595
-    }
2596
-
2597
-
2598
-
2599
-    /**
2600
-     * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2601
-     * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2602
-     * You can specify $default is case you haven't found the extra meta
2603
-     *
2604
-     * @param string  $meta_key
2605
-     * @param boolean $single
2606
-     * @param mixed   $default if we don't find anything, what should we return?
2607
-     * @return mixed single value if $single; array if ! $single
2608
-     * @throws EE_Error
2609
-     */
2610
-    public function get_extra_meta($meta_key, $single = false, $default = null)
2611
-    {
2612
-        if ($single) {
2613
-            $result = $this->get_first_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2614
-            if ($result instanceof EE_Extra_Meta) {
2615
-                return $result->value();
2616
-            }
2617
-        } else {
2618
-            $results = $this->get_many_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2619
-            if ($results) {
2620
-                $values = array();
2621
-                foreach ($results as $result) {
2622
-                    if ($result instanceof EE_Extra_Meta) {
2623
-                        $values[$result->ID()] = $result->value();
2624
-                    }
2625
-                }
2626
-                return $values;
2627
-            }
2628
-        }
2629
-        //if nothing discovered yet return default.
2630
-        return apply_filters(
2631
-            'FHEE__EE_Base_Class__get_extra_meta__default_value',
2632
-            $default,
2633
-            $meta_key,
2634
-            $single,
2635
-            $this
2636
-            );
2637
-    }
2638
-
2639
-
2640
-
2641
-    /**
2642
-     * Returns a simple array of all the extra meta associated with this model object.
2643
-     * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2644
-     * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2645
-     * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2646
-     * If $one_of_each_key is false, it will return an array with the top-level keys being
2647
-     * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2648
-     * finally the extra meta's value as each sub-value. (eg
2649
-     * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2650
-     *
2651
-     * @param boolean $one_of_each_key
2652
-     * @return array
2653
-     * @throws EE_Error
2654
-     */
2655
-    public function all_extra_meta_array($one_of_each_key = true)
2656
-    {
2657
-        $return_array = array();
2658
-        if ($one_of_each_key) {
2659
-            $extra_meta_objs = $this->get_many_related('Extra_Meta', array('group_by' => 'EXM_key'));
2660
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2661
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2662
-                    $return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2663
-                }
2664
-            }
2665
-        } else {
2666
-            $extra_meta_objs = $this->get_many_related('Extra_Meta');
2667
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2668
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2669
-                    if ( ! isset($return_array[$extra_meta_obj->key()])) {
2670
-                        $return_array[$extra_meta_obj->key()] = array();
2671
-                    }
2672
-                    $return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2673
-                }
2674
-            }
2675
-        }
2676
-        return $return_array;
2677
-    }
2678
-
2679
-
2680
-
2681
-    /**
2682
-     * Gets a pretty nice displayable nice for this model object. Often overridden
2683
-     *
2684
-     * @return string
2685
-     * @throws EE_Error
2686
-     */
2687
-    public function name()
2688
-    {
2689
-        //find a field that's not a text field
2690
-        $field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2691
-        if ($field_we_can_use) {
2692
-            return $this->get($field_we_can_use->get_name());
2693
-        } else {
2694
-            $first_few_properties = $this->model_field_array();
2695
-            $first_few_properties = array_slice($first_few_properties, 0, 3);
2696
-            $name_parts = array();
2697
-            foreach ($first_few_properties as $name => $value) {
2698
-                $name_parts[] = "$name:$value";
2699
-            }
2700
-            return implode(",", $name_parts);
2701
-        }
2702
-    }
2703
-
2704
-
2705
-
2706
-    /**
2707
-     * in_entity_map
2708
-     * Checks if this model object has been proven to already be in the entity map
2709
-     *
2710
-     * @return boolean
2711
-     * @throws EE_Error
2712
-     */
2713
-    public function in_entity_map()
2714
-    {
2715
-        if ($this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this) {
2716
-            //well, if we looked, did we find it in the entity map?
2717
-            return true;
2718
-        } else {
2719
-            return false;
2720
-        }
2721
-    }
2722
-
2723
-
2724
-
2725
-    /**
2726
-     * refresh_from_db
2727
-     * Makes sure the fields and values on this model object are in-sync with what's in the database.
2728
-     *
2729
-     * @throws EE_Error if this model object isn't in the entity mapper (because then you should
2730
-     * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
2731
-     */
2732
-    public function refresh_from_db()
2733
-    {
2734
-        if ($this->ID() && $this->in_entity_map()) {
2735
-            $this->get_model()->refresh_entity_map_from_db($this->ID());
2736
-        } else {
2737
-            //if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
2738
-            //if it has an ID but it's not in the map, and you're asking me to refresh it
2739
-            //that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
2740
-            //absolutely nothing in it for this ID
2741
-            if (WP_DEBUG) {
2742
-                throw new EE_Error(
2743
-                    sprintf(
2744
-                        __('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.',
2745
-                            'event_espresso'),
2746
-                        $this->ID(),
2747
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2748
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2749
-                    )
2750
-                );
2751
-            }
2752
-        }
2753
-    }
2754
-
2755
-
2756
-    /**
2757
-     * Gets the money field's amount in subunits (and if the currency has no subunits, gets it in the main units).
2758
-     * If you want to use this method, the class must implement UsesMoneyInterface and injected a MoneyFactory in
2759
-     * its constructor
2760
-     * @param string $money_field_name
2761
-     * @return int
2762
-     * @throws InvalidEntityException
2763
-     * @throws EE_Error
2764
-     * @throws DomainException
2765
-     * @since $VID:$
2766
-     */
2767
-    public function moneyInSubunits($money_field_name)
2768
-    {
2769
-        $this->verifyUsesMoney(__FUNCTION__);
2770
-        return $this->getMoneyObject($money_field_name)->amountInSubunits();
2771
-    }
2772
-
2773
-
2774
-    /**
2775
-     * Sets the money field's amount based on the incoming monetary subunits (eg pennies). If the currency has no
2776
-     * subunits, the amount is actually assumed to be in the currency's main units.
2777
-     * If you want to use this method, the class must implement UsesMoneyInterface and injected a MoneyFactory in
2778
-     * its constructor
2779
-     *
2780
-     * @param string $money_field_name
2781
-     * @param int    $amount_in_subunits
2782
-     * @throws InvalidArgumentException
2783
-     * @throws InvalidInterfaceException
2784
-     * @throws InvalidIdentifierException
2785
-     * @throws InvalidDataTypeException
2786
-     * @throws EE_Error
2787
-     * @throws DomainException
2788
-     * @since $VID:$
2789
-     */
2790
-    public function setMoneySubunits($money_field_name,$amount_in_subunits)
2791
-    {
2792
-        $this->verifyUsesMoney(__FUNCTION__);
2793
-        $money = $this->money_factory->createFromSubUnits(
2794
-            $amount_in_subunits,
2795
-            EE_Config::instance()->currency->code
2796
-        );
2797
-        $this->set($money_field_name, $money);
2798
-    }
2799
-
2800
-
2801
-    /**
2802
-     * Checks this class has implemented UsesMoneyInterface
2803
-     * @param string $function
2804
-     * @throws DomainException
2805
-     * @throws EE_Error
2806
-     * @since $VID:$
2807
-     */
2808
-    private function verifyUsesMoney($function)
2809
-    {
2810
-        if (! $this instanceof UsesMoneyInterface) {
2811
-            throw new DomainException(
2812
-                sprintf(
2813
-                    esc_html__(
2814
-                        '%1$s does not use an %2$s object for representing money values, therefore the %3$s method can not be called.',
2815
-                        'event_espresso'
2816
-                    ),
2817
-                    $this->name(),
2818
-                    'EventEspresso\core\domain\values\currency\Money',
2819
-                    "{$function}()"
2820
-                )
2821
-            );
2822
-        }
2823
-    }
2824
-
2825
-
2826
-
2827
-    /**
2828
-     * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
2829
-     * (probably a bad assumption they have made, oh well)
2830
-     *
2831
-     * @return string
2832
-     */
2833
-    public function __toString()
2834
-    {
2835
-        try {
2836
-            return sprintf('%s (%s)', $this->name(), $this->ID());
2837
-        } catch (Exception $e) {
2838
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
2839
-            return '';
2840
-        }
2841
-    }
2842
-
2843
-
2844
-
2845
-    /**
2846
-     * Clear related model objects if they're already in the DB, because otherwise when we
2847
-     * UN-serialize this model object we'll need to be careful to add them to the entity map.
2848
-     * This means if we have made changes to those related model objects, and want to unserialize
2849
-     * the this model object on a subsequent request, changes to those related model objects will be lost.
2850
-     * Instead, those related model objects should be directly serialized and stored.
2851
-     * Eg, the following won't work:
2852
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2853
-     * $att = $reg->attendee();
2854
-     * $att->set( 'ATT_fname', 'Dirk' );
2855
-     * update_option( 'my_option', serialize( $reg ) );
2856
-     * //END REQUEST
2857
-     * //START NEXT REQUEST
2858
-     * $reg = get_option( 'my_option' );
2859
-     * $reg->attendee()->save();
2860
-     * And would need to be replace with:
2861
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2862
-     * $att = $reg->attendee();
2863
-     * $att->set( 'ATT_fname', 'Dirk' );
2864
-     * update_option( 'my_option', serialize( $reg ) );
2865
-     * //END REQUEST
2866
-     * //START NEXT REQUEST
2867
-     * $att = get_option( 'my_option' );
2868
-     * $att->save();
2869
-     *
2870
-     * @return array
2871
-     * @throws EE_Error
2872
-     */
2873
-    public function __sleep()
2874
-    {
2875
-        $model = $this->get_model();
2876
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2877
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
2878
-                $classname = 'EE_' . $model->get_this_model_name();
2879
-                if (
2880
-                    $this->get_one_from_cache($relation_name) instanceof $classname
2881
-                    && $this->get_one_from_cache($relation_name)->ID()
2882
-                ) {
2883
-                    $this->clear_cache($relation_name, $this->get_one_from_cache($relation_name)->ID());
2884
-                }
2885
-            }
2886
-        }
2887
-        $this->_props_n_values_provided_in_constructor = array();
2888
-        $properties_to_serialize = get_object_vars($this);
2889
-        //don't serialize the model. It's big and that risks recursion
2890
-        unset(
2891
-            $properties_to_serialize['_model'],
2892
-            $properties_to_serialize['money_factory']
2893
-        );
2894
-        return array_keys($properties_to_serialize);
2895
-    }
2896
-
2897
-
2898
-    /**
2899
-     * restore _props_n_values_provided_in_constructor
2900
-     * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
2901
-     * and therefore should NOT be used to determine if state change has occurred since initial construction.
2902
-     * At best, you would only be able to detect if state change has occurred during THIS request.
2903
-     * @throws InvalidInterfaceException
2904
-     * @throws InvalidDataTypeException
2905
-     */
2906
-    public function __wakeup()
2907
-    {
2908
-        $this->_props_n_values_provided_in_constructor = $this->_fields;
2909
-        if( $this instanceof UsesMoneyInterface) {
2910
-            $this->money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
2911
-        }
2912
-    }
30
+	/**
31
+	 * This is an array of the original properties and values provided during construction
32
+	 * of this model object. (keys are model field names, values are their values).
33
+	 * This list is important to remember so that when we are merging data from the db, we know
34
+	 * which values to override and which to not override.
35
+	 *
36
+	 * @var array
37
+	 */
38
+	protected $_props_n_values_provided_in_constructor;
39
+
40
+	/**
41
+	 * Timezone
42
+	 * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
43
+	 * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
44
+	 * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
45
+	 * access to it.
46
+	 *
47
+	 * @var string
48
+	 */
49
+	protected $_timezone;
50
+
51
+
52
+
53
+	/**
54
+	 * date format
55
+	 * pattern or format for displaying dates
56
+	 *
57
+	 * @var string $_dt_frmt
58
+	 */
59
+	protected $_dt_frmt;
60
+
61
+
62
+
63
+	/**
64
+	 * time format
65
+	 * pattern or format for displaying time
66
+	 *
67
+	 * @var string $_tm_frmt
68
+	 */
69
+	protected $_tm_frmt;
70
+
71
+
72
+
73
+	/**
74
+	 * This property is for holding a cached array of object properties indexed by property name as the key.
75
+	 * The purpose of this is for setting a cache on properties that may have calculated values after a
76
+	 * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
77
+	 * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
78
+	 *
79
+	 * @var array
80
+	 */
81
+	protected $_cached_properties = array();
82
+
83
+	/**
84
+	 * An array containing keys of the related model, and values are either an array of related mode objects or a
85
+	 * single
86
+	 * related model object. see the model's _model_relations. The keys should match those specified. And if the
87
+	 * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
88
+	 * all others have an array)
89
+	 *
90
+	 * @var array
91
+	 */
92
+	protected $_model_relations = array();
93
+
94
+	/**
95
+	 * Array where keys are field names (see the model's _fields property) and values are their values. To see what
96
+	 * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
97
+	 *
98
+	 * @var array
99
+	 */
100
+	protected $_fields = array();
101
+
102
+	/**
103
+	 * @var boolean indicating whether or not this model object is intended to ever be saved
104
+	 * For example, we might create model objects intended to only be used for the duration
105
+	 * of this request and to be thrown away, and if they were accidentally saved
106
+	 * it would be a bug.
107
+	 */
108
+	protected $_allow_persist = true;
109
+
110
+	/**
111
+	 * @var boolean indicating whether or not this model object's properties have changed since construction
112
+	 */
113
+	protected $_has_changes = false;
114
+
115
+	/**
116
+	 * @var EEM_Base
117
+	 */
118
+	protected $_model;
119
+
120
+	/**
121
+	 * @var MoneyFactory
122
+	 */
123
+	protected $money_factory;
124
+
125
+
126
+	/**
127
+	 * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
128
+	 * play nice
129
+	 *
130
+	 * @param array $fieldValues where each key is a field (ie, array key in the 2nd
131
+	 *                                                         layer of the model's _fields array, (eg, EVT_ID,
132
+	 *                                                         TXN_amount, QST_name, etc) and values are their values
133
+	 * @param boolean $bydb a flag for setting if the class is instantiated by the
134
+	 *                                                         corresponding db model or not.
135
+	 * @param string $timezone indicate what timezone you want any datetime fields to
136
+	 *                                                         be in when instantiating a EE_Base_Class object.
137
+	 * @param array $date_formats An array of date formats to set on construct where first
138
+	 *                                                         value is the date_format and second value is the time
139
+	 *                                                         format.
140
+	 * @throws InvalidArgumentException
141
+	 * @throws InvalidInterfaceException
142
+	 * @throws InvalidDataTypeException
143
+	 * @throws EE_Error
144
+	 */
145
+	protected function __construct(
146
+		$fieldValues = array(),
147
+		$bydb = false,
148
+		$timezone = '',
149
+		$date_formats = array()
150
+	) {
151
+		$className = get_class($this);
152
+		do_action("AHEE__{$className}__construct", $this, $fieldValues);
153
+		$model = $this->get_model();
154
+		$model_fields = $model->field_settings(false);
155
+		// ensure $fieldValues is an array
156
+		$fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
157
+		// EEH_Debug_Tools::printr( $fieldValues, '$fieldValues  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
158
+		// verify client code has not passed any invalid field names
159
+		foreach ($fieldValues as $field_name => $field_value) {
160
+			if ( ! isset($model_fields[$field_name])) {
161
+				throw new EE_Error(sprintf(__("Invalid field (%s) passed to constructor of %s. Allowed fields are :%s",
162
+					"event_espresso"), $field_name, get_class($this), implode(", ", array_keys($model_fields))));
163
+			}
164
+		}
165
+		// EEH_Debug_Tools::printr( $model_fields, '$model_fields  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
166
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
167
+		if ( ! empty($date_formats) && is_array($date_formats)) {
168
+			list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
169
+		} else {
170
+			//set default formats for date and time
171
+			$this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
172
+			$this->_tm_frmt = (string)get_option('time_format', 'g:i a');
173
+		}
174
+		//if db model is instantiating
175
+		if ($bydb) {
176
+			//client code has indicated these field values are from the database
177
+			foreach ($model_fields as $fieldName => $field) {
178
+				$this->set_from_db($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null);
179
+			}
180
+		} else {
181
+			//we're constructing a brand
182
+			//new instance of the model object. Generally, this means we'll need to do more field validation
183
+			foreach ($model_fields as $fieldName => $field) {
184
+				$this->set($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true);
185
+			}
186
+		}
187
+		//remember what values were passed to this constructor
188
+		$this->_props_n_values_provided_in_constructor = $fieldValues;
189
+		//remember in entity mapper
190
+		if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
191
+			$model->add_to_entity_map($this);
192
+		}
193
+		//setup all the relations
194
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
195
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
196
+				$this->_model_relations[$relation_name] = null;
197
+			} else {
198
+				$this->_model_relations[$relation_name] = array();
199
+			}
200
+		}
201
+		/**
202
+		 * Action done at the end of each model object construction
203
+		 *
204
+		 * @param EE_Base_Class $this the model object just created
205
+		 */
206
+		do_action('AHEE__EE_Base_Class__construct__finished', $this);
207
+	}
208
+
209
+
210
+
211
+	/**
212
+	 * Gets whether or not this model object is allowed to persist/be saved to the database.
213
+	 *
214
+	 * @return boolean
215
+	 */
216
+	public function allow_persist()
217
+	{
218
+		return $this->_allow_persist;
219
+	}
220
+
221
+
222
+
223
+	/**
224
+	 * Sets whether or not this model object should be allowed to be saved to the DB.
225
+	 * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
226
+	 * you got new information that somehow made you change your mind.
227
+	 *
228
+	 * @param boolean $allow_persist
229
+	 * @return boolean
230
+	 */
231
+	public function set_allow_persist($allow_persist)
232
+	{
233
+		return $this->_allow_persist = $allow_persist;
234
+	}
235
+
236
+
237
+
238
+	/**
239
+	 * Gets the field's original value when this object was constructed during this request.
240
+	 * This can be helpful when determining if a model object has changed or not
241
+	 *
242
+	 * @param string $field_name
243
+	 * @return mixed|null
244
+	 * @throws EE_Error
245
+	 */
246
+	public function get_original($field_name)
247
+	{
248
+		if (isset($this->_props_n_values_provided_in_constructor[$field_name])
249
+			&& $field_settings = $this->get_model()->field_settings_for($field_name)
250
+		) {
251
+			return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
252
+		} else {
253
+			return null;
254
+		}
255
+	}
256
+
257
+
258
+
259
+	/**
260
+	 * @param EE_Base_Class $obj
261
+	 * @return string
262
+	 */
263
+	public function get_class($obj)
264
+	{
265
+		return get_class($obj);
266
+	}
267
+
268
+
269
+	/**
270
+	 * Overrides parent because parent expects old models.
271
+	 * This also doesn't do any validation, and won't work for serialized arrays
272
+	 *
273
+	 * @param    string $field_name
274
+	 * @param    mixed $field_value
275
+	 * @param bool $use_default
276
+	 * @throws InvalidArgumentException
277
+	 * @throws InvalidInterfaceException
278
+	 * @throws InvalidDataTypeException
279
+	 * @throws EE_Error
280
+	 */
281
+	public function set($field_name, $field_value, $use_default = false)
282
+	{
283
+		// if not using default and nothing has changed, and object has already been setup (has ID),
284
+		// then don't do anything
285
+		if (
286
+			! $use_default
287
+			&& $this->_fields[$field_name] === $field_value
288
+			&& $this->ID()
289
+		) {
290
+			return;
291
+		}
292
+		$model = $this->get_model();
293
+		$this->_has_changes = true;
294
+		$field_obj = $model->field_settings_for($field_name);
295
+		if ($field_obj instanceof EE_Model_Field_Base) {
296
+			//			if ( method_exists( $field_obj, 'set_timezone' )) {
297
+			if ($field_obj instanceof EE_Datetime_Field) {
298
+				$field_obj->set_timezone($this->_timezone);
299
+				$field_obj->set_date_format($this->_dt_frmt);
300
+				$field_obj->set_time_format($this->_tm_frmt);
301
+			}
302
+			$holder_of_value = $field_obj->prepare_for_set($field_value);
303
+			//should the value be null?
304
+			if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
305
+				$this->_fields[$field_name] = $field_obj->get_default_value();
306
+				/**
307
+				 * To save having to refactor all the models, if a default value is used for a
308
+				 * EE_Datetime_Field, and that value is not null nor is it a DateTime
309
+				 * object.  Then let's do a set again to ensure that it becomes a DateTime
310
+				 * object.
311
+				 *
312
+				 * @since 4.6.10+
313
+				 */
314
+				if (
315
+					$field_obj instanceof EE_Datetime_Field
316
+					&& $this->_fields[$field_name] !== null
317
+					&& ! $this->_fields[$field_name] instanceof DateTime
318
+				) {
319
+					empty($this->_fields[$field_name])
320
+						? $this->set($field_name, time())
321
+						: $this->set($field_name, $this->_fields[$field_name]);
322
+				}
323
+			} else {
324
+				$this->_fields[$field_name] = $holder_of_value;
325
+			}
326
+			//if we're not in the constructor...
327
+			//now check if what we set was a primary key
328
+			if (
329
+				//note: props_n_values_provided_in_constructor is only set at the END of the constructor
330
+				$this->_props_n_values_provided_in_constructor
331
+				&& $field_value
332
+				&& $field_name === $model->primary_key_name()
333
+			) {
334
+				//if so, we want all this object's fields to be filled either with
335
+				//what we've explicitly set on this model
336
+				//or what we have in the db
337
+				// echo "setting primary key!";
338
+				$fields_on_model = self::_get_model(get_class($this))->field_settings();
339
+				$obj_in_db = self::_get_model(get_class($this))->get_one_by_ID($field_value);
340
+				foreach ($fields_on_model as $field_obj) {
341
+					if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
342
+						 && $field_obj->get_name() !== $field_name
343
+					) {
344
+						$this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
345
+					}
346
+				}
347
+				//oh this model object has an ID? well make sure its in the entity mapper
348
+				$model->add_to_entity_map($this);
349
+			}
350
+			//let's unset any cache for this field_name from the $_cached_properties property.
351
+			$this->_clear_cached_property($field_name);
352
+		} else {
353
+			throw new EE_Error(sprintf(__("A valid EE_Model_Field_Base could not be found for the given field name: %s",
354
+				"event_espresso"), $field_name));
355
+		}
356
+	}
357
+
358
+
359
+
360
+	/**
361
+	 * This sets the field value on the db column if it exists for the given $column_name or
362
+	 * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
363
+	 *
364
+	 * @see EE_message::get_column_value for related documentation on the necessity of this method.
365
+	 * @param string $field_name  Must be the exact column name.
366
+	 * @param mixed  $field_value The value to set.
367
+	 * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
368
+	 * @throws EE_Error
369
+	 */
370
+	public function set_field_or_extra_meta($field_name, $field_value)
371
+	{
372
+		if ($this->get_model()->has_field($field_name)) {
373
+			$this->set($field_name, $field_value);
374
+			return true;
375
+		} else {
376
+			//ensure this object is saved first so that extra meta can be properly related.
377
+			$this->save();
378
+			return $this->update_extra_meta($field_name, $field_value);
379
+		}
380
+	}
381
+
382
+
383
+
384
+	/**
385
+	 * This retrieves the value of the db column set on this class or if that's not present
386
+	 * it will attempt to retrieve from extra_meta if found.
387
+	 * Example Usage:
388
+	 * Via EE_Message child class:
389
+	 * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
390
+	 * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
391
+	 * also have additional main fields specific to the messenger.  The system accommodates those extra
392
+	 * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
393
+	 * value for those extra fields dynamically via the EE_message object.
394
+	 *
395
+	 * @param  string $field_name expecting the fully qualified field name.
396
+	 * @return mixed|null  value for the field if found.  null if not found.
397
+	 * @throws EE_Error
398
+	 */
399
+	public function get_field_or_extra_meta($field_name)
400
+	{
401
+		if ($this->get_model()->has_field($field_name)) {
402
+			$column_value = $this->get($field_name);
403
+		} else {
404
+			//This isn't a column in the main table, let's see if it is in the extra meta.
405
+			$column_value = $this->get_extra_meta($field_name, true, null);
406
+		}
407
+		return $column_value;
408
+	}
409
+
410
+
411
+	/**
412
+	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
413
+	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
414
+	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
415
+	 * available to all child classes that may be using the EE_Datetime_Field for a field data type.
416
+	 *
417
+	 * @access public
418
+	 * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
419
+	 * @return void
420
+	 * @throws InvalidArgumentException
421
+	 * @throws InvalidInterfaceException
422
+	 * @throws InvalidDataTypeException
423
+	 * @throws EE_Error
424
+	 */
425
+	public function set_timezone($timezone = '')
426
+	{
427
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
428
+		//make sure we clear all cached properties because they won't be relevant now
429
+		$this->_clear_cached_properties();
430
+		//make sure we update field settings and the date for all EE_Datetime_Fields
431
+		$model_fields = $this->get_model()->field_settings(false);
432
+		foreach ($model_fields as $field_name => $field_obj) {
433
+			if ($field_obj instanceof EE_Datetime_Field) {
434
+				$field_obj->set_timezone($this->_timezone);
435
+				if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
436
+					$this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
437
+				}
438
+			}
439
+		}
440
+	}
441
+
442
+
443
+
444
+	/**
445
+	 * This just returns whatever is set for the current timezone.
446
+	 *
447
+	 * @access public
448
+	 * @return string timezone string
449
+	 */
450
+	public function get_timezone()
451
+	{
452
+		return $this->_timezone;
453
+	}
454
+
455
+
456
+
457
+	/**
458
+	 * This sets the internal date format to what is sent in to be used as the new default for the class
459
+	 * internally instead of wp set date format options
460
+	 *
461
+	 * @since 4.6
462
+	 * @param string $format should be a format recognizable by PHP date() functions.
463
+	 */
464
+	public function set_date_format($format)
465
+	{
466
+		$this->_dt_frmt = $format;
467
+		//clear cached_properties because they won't be relevant now.
468
+		$this->_clear_cached_properties();
469
+	}
470
+
471
+
472
+
473
+	/**
474
+	 * This sets the internal time format string to what is sent in to be used as the new default for the
475
+	 * class internally instead of wp set time format options.
476
+	 *
477
+	 * @since 4.6
478
+	 * @param string $format should be a format recognizable by PHP date() functions.
479
+	 */
480
+	public function set_time_format($format)
481
+	{
482
+		$this->_tm_frmt = $format;
483
+		//clear cached_properties because they won't be relevant now.
484
+		$this->_clear_cached_properties();
485
+	}
486
+
487
+
488
+
489
+	/**
490
+	 * This returns the current internal set format for the date and time formats.
491
+	 *
492
+	 * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
493
+	 *                             where the first value is the date format and the second value is the time format.
494
+	 * @return mixed string|array
495
+	 */
496
+	public function get_format($full = true)
497
+	{
498
+		return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
499
+	}
500
+
501
+
502
+
503
+	/**
504
+	 * cache
505
+	 * stores the passed model object on the current model object.
506
+	 * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
507
+	 *
508
+	 * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
509
+	 *                                       'Registration' associated with this model object
510
+	 * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
511
+	 *                                       that could be a payment or a registration)
512
+	 * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
513
+	 *                                       items which will be stored in an array on this object
514
+	 * @throws EE_Error
515
+	 * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
516
+	 *                  related thing, no array)
517
+	 */
518
+	public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
519
+	{
520
+		// its entirely possible that there IS no related object yet in which case there is nothing to cache.
521
+		if ( ! $object_to_cache instanceof EE_Base_Class) {
522
+			return false;
523
+		}
524
+		// also get "how" the object is related, or throw an error
525
+		if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
526
+			throw new EE_Error(sprintf(__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
527
+				$relationName, get_class($this)));
528
+		}
529
+		// how many things are related ?
530
+		if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
531
+			// if it's a "belongs to" relationship, then there's only one related model object  eg, if this is a registration, there's only 1 attendee for it
532
+			// so for these model objects just set it to be cached
533
+			$this->_model_relations[$relationName] = $object_to_cache;
534
+			$return = true;
535
+		} else {
536
+			// otherwise, this is the "many" side of a one to many relationship, so we'll add the object to the array of related objects for that type.
537
+			// eg: if this is an event, there are many registrations for that event, so we cache the registrations in an array
538
+			if ( ! is_array($this->_model_relations[$relationName])) {
539
+				// if for some reason, the cached item is a model object, then stick that in the array, otherwise start with an empty array
540
+				$this->_model_relations[$relationName] = $this->_model_relations[$relationName] instanceof EE_Base_Class
541
+					? array($this->_model_relations[$relationName]) : array();
542
+			}
543
+			// first check for a cache_id which is normally empty
544
+			if ( ! empty($cache_id)) {
545
+				// if the cache_id exists, then it means we are purposely trying to cache this with a known key that can then be used to retrieve the object later on
546
+				$this->_model_relations[$relationName][$cache_id] = $object_to_cache;
547
+				$return = $cache_id;
548
+			} elseif ($object_to_cache->ID()) {
549
+				// OR the cached object originally came from the db, so let's just use it's PK for an ID
550
+				$this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
551
+				$return = $object_to_cache->ID();
552
+			} else {
553
+				// OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
554
+				$this->_model_relations[$relationName][] = $object_to_cache;
555
+				// move the internal pointer to the end of the array
556
+				end($this->_model_relations[$relationName]);
557
+				// and grab the key so that we can return it
558
+				$return = key($this->_model_relations[$relationName]);
559
+			}
560
+		}
561
+		return $return;
562
+	}
563
+
564
+
565
+
566
+	/**
567
+	 * For adding an item to the cached_properties property.
568
+	 *
569
+	 * @access protected
570
+	 * @param string      $fieldname the property item the corresponding value is for.
571
+	 * @param mixed       $value     The value we are caching.
572
+	 * @param string|null $cache_type
573
+	 * @return void
574
+	 * @throws EE_Error
575
+	 */
576
+	protected function _set_cached_property($fieldname, $value, $cache_type = null)
577
+	{
578
+		//first make sure this property exists
579
+		$this->get_model()->field_settings_for($fieldname);
580
+		$cache_type = empty($cache_type) ? 'standard' : $cache_type;
581
+		$this->_cached_properties[$fieldname][$cache_type] = $value;
582
+	}
583
+
584
+
585
+
586
+	/**
587
+	 * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
588
+	 * This also SETS the cache if we return the actual property!
589
+	 *
590
+	 * @param string $fieldname        the name of the property we're trying to retrieve
591
+	 * @param bool   $pretty
592
+	 * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
593
+	 *                                 (in cases where the same property may be used for different outputs
594
+	 *                                 - i.e. datetime, money etc.)
595
+	 *                                 It can also accept certain pre-defined "schema" strings
596
+	 *                                 to define how to output the property.
597
+	 *                                 see the field's prepare_for_pretty_echoing for what strings can be used
598
+	 * @return mixed                   whatever the value for the property is we're retrieving
599
+	 * @throws EE_Error
600
+	 */
601
+	protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
602
+	{
603
+		//verify the field exists
604
+		$model = $this->get_model();
605
+		$model->field_settings_for($fieldname);
606
+		$cache_type = $pretty ? 'pretty' : 'standard';
607
+		$cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
608
+		if (isset($this->_cached_properties[$fieldname][$cache_type])) {
609
+			return $this->_cached_properties[$fieldname][$cache_type];
610
+		}
611
+		$value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
612
+		$this->_set_cached_property($fieldname, $value, $cache_type);
613
+		return $value;
614
+	}
615
+
616
+
617
+	/**
618
+	 * If the cache didn't fetch the needed item, this fetches it.
619
+	 * @param string $fieldname
620
+	 * @param bool $pretty
621
+	 * @param string $extra_cache_ref
622
+	 * @return mixed
623
+	 * @throws EE_Error
624
+	 */
625
+	protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
626
+	{
627
+		$field_obj = $this->get_model()->field_settings_for($fieldname);
628
+		// If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
629
+		if ($field_obj instanceof EE_Datetime_Field) {
630
+			$this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
631
+		}
632
+		if ( ! isset($this->_fields[$fieldname])) {
633
+			$this->_fields[$fieldname] = null;
634
+		}
635
+		$value = $pretty
636
+			? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
637
+			: $field_obj->prepare_for_get($this->_fields[$fieldname]);
638
+		return $value;
639
+	}
640
+
641
+
642
+	/**
643
+	 * set timezone, formats, and output for EE_Datetime_Field objects
644
+	 *
645
+	 * @param \EE_Datetime_Field $datetime_field
646
+	 * @param bool $pretty
647
+	 * @param null $date_or_time
648
+	 * @return void
649
+	 * @throws InvalidArgumentException
650
+	 * @throws InvalidInterfaceException
651
+	 * @throws InvalidDataTypeException
652
+	 * @throws EE_Error
653
+	 */
654
+	protected function _prepare_datetime_field(
655
+		EE_Datetime_Field $datetime_field,
656
+		$pretty = false,
657
+		$date_or_time = null
658
+	) {
659
+		$datetime_field->set_timezone($this->_timezone);
660
+		$datetime_field->set_date_format($this->_dt_frmt, $pretty);
661
+		$datetime_field->set_time_format($this->_tm_frmt, $pretty);
662
+		//set the output returned
663
+		switch ($date_or_time) {
664
+			case 'D' :
665
+				$datetime_field->set_date_time_output('date');
666
+				break;
667
+			case 'T' :
668
+				$datetime_field->set_date_time_output('time');
669
+				break;
670
+			default :
671
+				$datetime_field->set_date_time_output();
672
+		}
673
+	}
674
+
675
+
676
+
677
+	/**
678
+	 * This just takes care of clearing out the cached_properties
679
+	 *
680
+	 * @return void
681
+	 */
682
+	protected function _clear_cached_properties()
683
+	{
684
+		$this->_cached_properties = array();
685
+	}
686
+
687
+
688
+
689
+	/**
690
+	 * This just clears out ONE property if it exists in the cache
691
+	 *
692
+	 * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
693
+	 * @return void
694
+	 */
695
+	protected function _clear_cached_property($property_name)
696
+	{
697
+		if (isset($this->_cached_properties[$property_name])) {
698
+			unset($this->_cached_properties[$property_name]);
699
+		}
700
+	}
701
+
702
+
703
+
704
+	/**
705
+	 * Ensures that this related thing is a model object.
706
+	 *
707
+	 * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
708
+	 * @param string $model_name   name of the related thing, eg 'Attendee',
709
+	 * @return EE_Base_Class
710
+	 * @throws EE_Error
711
+	 */
712
+	protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
713
+	{
714
+		$other_model_instance = self::_get_model_instance_with_name(
715
+			self::_get_model_classname($model_name),
716
+			$this->_timezone
717
+		);
718
+		return $other_model_instance->ensure_is_obj($object_or_id);
719
+	}
720
+
721
+
722
+
723
+	/**
724
+	 * Forgets the cached model of the given relation Name. So the next time we request it,
725
+	 * we will fetch it again from the database. (Handy if you know it's changed somehow).
726
+	 * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
727
+	 * then only remove that one object from our cached array. Otherwise, clear the entire list
728
+	 *
729
+	 * @param string $relationName                         one of the keys in the _model_relations array on the model.
730
+	 *                                                     Eg 'Registration'
731
+	 * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
732
+	 *                                                     if you intend to use $clear_all = TRUE, or the relation only
733
+	 *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
734
+	 * @param bool   $clear_all                            This flags clearing the entire cache relation property if
735
+	 *                                                     this is HasMany or HABTM.
736
+	 * @throws EE_Error
737
+	 * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
738
+	 *                       relation from all
739
+	 */
740
+	public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
741
+	{
742
+		$relationship_to_model = $this->get_model()->related_settings_for($relationName);
743
+		$index_in_cache = '';
744
+		if ( ! $relationship_to_model) {
745
+			throw new EE_Error(
746
+				sprintf(
747
+					__("There is no relationship to %s on a %s. Cannot clear that cache", 'event_espresso'),
748
+					$relationName,
749
+					get_class($this)
750
+				)
751
+			);
752
+		}
753
+		if ($clear_all) {
754
+			$obj_removed = true;
755
+			$this->_model_relations[$relationName] = null;
756
+		} elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
757
+			$obj_removed = $this->_model_relations[$relationName];
758
+			$this->_model_relations[$relationName] = null;
759
+		} else {
760
+			if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
761
+				&& $object_to_remove_or_index_into_array->ID()
762
+			) {
763
+				$index_in_cache = $object_to_remove_or_index_into_array->ID();
764
+				if (is_array($this->_model_relations[$relationName])
765
+					&& ! isset($this->_model_relations[$relationName][$index_in_cache])
766
+				) {
767
+					$index_found_at = null;
768
+					//find this object in the array even though it has a different key
769
+					foreach ($this->_model_relations[$relationName] as $index => $obj) {
770
+						if (
771
+							$obj instanceof EE_Base_Class
772
+							&& (
773
+								$obj == $object_to_remove_or_index_into_array
774
+								|| $obj->ID() === $object_to_remove_or_index_into_array->ID()
775
+							)
776
+						) {
777
+							$index_found_at = $index;
778
+							break;
779
+						}
780
+					}
781
+					if ($index_found_at) {
782
+						$index_in_cache = $index_found_at;
783
+					} else {
784
+						//it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
785
+						//if it wasn't in it to begin with. So we're done
786
+						return $object_to_remove_or_index_into_array;
787
+					}
788
+				}
789
+			} elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
790
+				//so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
791
+				foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
792
+					if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
793
+						$index_in_cache = $index;
794
+					}
795
+				}
796
+			} else {
797
+				$index_in_cache = $object_to_remove_or_index_into_array;
798
+			}
799
+			//supposedly we've found it. But it could just be that the client code
800
+			//provided a bad index/object
801
+			if (
802
+			isset(
803
+				$this->_model_relations[$relationName],
804
+				$this->_model_relations[$relationName][$index_in_cache]
805
+			)
806
+			) {
807
+				$obj_removed = $this->_model_relations[$relationName][$index_in_cache];
808
+				unset($this->_model_relations[$relationName][$index_in_cache]);
809
+			} else {
810
+				//that thing was never cached anyways.
811
+				$obj_removed = null;
812
+			}
813
+		}
814
+		return $obj_removed;
815
+	}
816
+
817
+
818
+
819
+	/**
820
+	 * update_cache_after_object_save
821
+	 * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
822
+	 * obtained after being saved to the db
823
+	 *
824
+	 * @param string         $relationName       - the type of object that is cached
825
+	 * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
826
+	 * @param string         $current_cache_id   - the ID that was used when originally caching the object
827
+	 * @return boolean TRUE on success, FALSE on fail
828
+	 * @throws EE_Error
829
+	 */
830
+	public function update_cache_after_object_save(
831
+		$relationName,
832
+		EE_Base_Class $newly_saved_object,
833
+		$current_cache_id = ''
834
+	) {
835
+		// verify that incoming object is of the correct type
836
+		$obj_class = 'EE_' . $relationName;
837
+		if ($newly_saved_object instanceof $obj_class) {
838
+			/* @type EE_Base_Class $newly_saved_object */
839
+			// now get the type of relation
840
+			$relationship_to_model = $this->get_model()->related_settings_for($relationName);
841
+			// if this is a 1:1 relationship
842
+			if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
843
+				// then just replace the cached object with the newly saved object
844
+				$this->_model_relations[$relationName] = $newly_saved_object;
845
+				return true;
846
+				// or if it's some kind of sordid feral polyamorous relationship...
847
+			} elseif (is_array($this->_model_relations[$relationName])
848
+					  && isset($this->_model_relations[$relationName][$current_cache_id])
849
+			) {
850
+				// then remove the current cached item
851
+				unset($this->_model_relations[$relationName][$current_cache_id]);
852
+				// and cache the newly saved object using it's new ID
853
+				$this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
854
+				return true;
855
+			}
856
+		}
857
+		return false;
858
+	}
859
+
860
+
861
+
862
+	/**
863
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
864
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
865
+	 *
866
+	 * @param string $relationName
867
+	 * @return EE_Base_Class
868
+	 */
869
+	public function get_one_from_cache($relationName)
870
+	{
871
+		$cached_array_or_object = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName]
872
+			: null;
873
+		if (is_array($cached_array_or_object)) {
874
+			return array_shift($cached_array_or_object);
875
+		} else {
876
+			return $cached_array_or_object;
877
+		}
878
+	}
879
+
880
+
881
+	/**
882
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
883
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
884
+	 *
885
+	 * @param string $relationName
886
+	 * @throws \ReflectionException
887
+	 * @throws InvalidArgumentException
888
+	 * @throws InvalidInterfaceException
889
+	 * @throws InvalidDataTypeException
890
+	 * @throws EE_Error
891
+	 * @return EE_Base_Class[] NOT necessarily indexed by primary keys
892
+	 */
893
+	public function get_all_from_cache($relationName)
894
+	{
895
+		$objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
896
+		// if the result is not an array, but exists, make it an array
897
+		$objects = is_array($objects) ? $objects : array($objects);
898
+		//bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
899
+		//basically, if this model object was stored in the session, and these cached model objects
900
+		//already have IDs, let's make sure they're in their model's entity mapper
901
+		//otherwise we will have duplicates next time we call
902
+		// EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
903
+		$model = EE_Registry::instance()->load_model($relationName);
904
+		foreach ($objects as $model_object) {
905
+			if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
906
+				//ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
907
+				if ($model_object->ID()) {
908
+					$model->add_to_entity_map($model_object);
909
+				}
910
+			} else {
911
+				throw new EE_Error(
912
+					sprintf(
913
+						__(
914
+							'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
915
+							'event_espresso'
916
+						),
917
+						$relationName,
918
+						gettype($model_object)
919
+					)
920
+				);
921
+			}
922
+		}
923
+		return $objects;
924
+	}
925
+
926
+
927
+
928
+	/**
929
+	 * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
930
+	 * matching the given query conditions.
931
+	 *
932
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
933
+	 * @param int   $limit              How many objects to return.
934
+	 * @param array $query_params       Any additional conditions on the query.
935
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
936
+	 *                                  you can indicate just the columns you want returned
937
+	 * @return array|EE_Base_Class[]
938
+	 * @throws EE_Error
939
+	 */
940
+	public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
941
+	{
942
+		$model = $this->get_model();
943
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
944
+			? $model->get_primary_key_field()->get_name()
945
+			: $field_to_order_by;
946
+		$current_value = ! empty($field) ? $this->get($field) : null;
947
+		if (empty($field) || empty($current_value)) {
948
+			return array();
949
+		}
950
+		return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
951
+	}
952
+
953
+
954
+
955
+	/**
956
+	 * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
957
+	 * matching the given query conditions.
958
+	 *
959
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
960
+	 * @param int   $limit              How many objects to return.
961
+	 * @param array $query_params       Any additional conditions on the query.
962
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
963
+	 *                                  you can indicate just the columns you want returned
964
+	 * @return array|EE_Base_Class[]
965
+	 * @throws EE_Error
966
+	 */
967
+	public function previous_x(
968
+		$field_to_order_by = null,
969
+		$limit = 1,
970
+		$query_params = array(),
971
+		$columns_to_select = null
972
+	) {
973
+		$model = $this->get_model();
974
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
975
+			? $model->get_primary_key_field()->get_name()
976
+			: $field_to_order_by;
977
+		$current_value = ! empty($field) ? $this->get($field) : null;
978
+		if (empty($field) || empty($current_value)) {
979
+			return array();
980
+		}
981
+		return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
982
+	}
983
+
984
+
985
+
986
+	/**
987
+	 * Returns the next EE_Base_Class object in sequence from this object as found in the database
988
+	 * matching the given query conditions.
989
+	 *
990
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
991
+	 * @param array $query_params       Any additional conditions on the query.
992
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
993
+	 *                                  you can indicate just the columns you want returned
994
+	 * @return array|EE_Base_Class
995
+	 * @throws EE_Error
996
+	 */
997
+	public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
998
+	{
999
+		$model = $this->get_model();
1000
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
1001
+			? $model->get_primary_key_field()->get_name()
1002
+			: $field_to_order_by;
1003
+		$current_value = ! empty($field) ? $this->get($field) : null;
1004
+		if (empty($field) || empty($current_value)) {
1005
+			return array();
1006
+		}
1007
+		return $model->next($current_value, $field, $query_params, $columns_to_select);
1008
+	}
1009
+
1010
+
1011
+
1012
+	/**
1013
+	 * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1014
+	 * matching the given query conditions.
1015
+	 *
1016
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1017
+	 * @param array $query_params       Any additional conditions on the query.
1018
+	 * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1019
+	 *                                  you can indicate just the column you want returned
1020
+	 * @return array|EE_Base_Class
1021
+	 * @throws EE_Error
1022
+	 */
1023
+	public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1024
+	{
1025
+		$model = $this->get_model();
1026
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
1027
+			? $model->get_primary_key_field()->get_name()
1028
+			: $field_to_order_by;
1029
+		$current_value = ! empty($field) ? $this->get($field) : null;
1030
+		if (empty($field) || empty($current_value)) {
1031
+			return array();
1032
+		}
1033
+		return $model->previous($current_value, $field, $query_params, $columns_to_select);
1034
+	}
1035
+
1036
+
1037
+
1038
+	/**
1039
+	 * Overrides parent because parent expects old models.
1040
+	 * This also doesn't do any validation, and won't work for serialized arrays
1041
+	 *
1042
+	 * @param string $field_name
1043
+	 * @param mixed  $field_value_from_db
1044
+	 * @throws EE_Error
1045
+	 */
1046
+	public function set_from_db($field_name, $field_value_from_db)
1047
+	{
1048
+		$field_obj = $this->get_model()->field_settings_for($field_name);
1049
+		if ($field_obj instanceof EE_Model_Field_Base) {
1050
+			//you would think the DB has no NULLs for non-null label fields right? wrong!
1051
+			//eg, a CPT model object could have an entry in the posts table, but no
1052
+			//entry in the meta table. Meaning that all its columns in the meta table
1053
+			//are null! yikes! so when we find one like that, use defaults for its meta columns
1054
+			if ($field_value_from_db === null) {
1055
+				if ($field_obj->is_nullable()) {
1056
+					//if the field allows nulls, then let it be null
1057
+					$field_value = null;
1058
+				} else {
1059
+					$field_value = $field_obj->get_default_value();
1060
+				}
1061
+			} else {
1062
+				$field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1063
+			}
1064
+			$this->_fields[$field_name] = $field_value;
1065
+			$this->_clear_cached_property($field_name);
1066
+		}
1067
+	}
1068
+
1069
+
1070
+
1071
+	/**
1072
+	 * verifies that the specified field is of the correct type
1073
+	 *
1074
+	 * @param string $field_name
1075
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1076
+	 *                                (in cases where the same property may be used for different outputs
1077
+	 *                                - i.e. datetime, money etc.)
1078
+	 * @return mixed
1079
+	 * @throws EE_Error
1080
+	 */
1081
+	public function get($field_name, $extra_cache_ref = null)
1082
+	{
1083
+		return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1084
+	}
1085
+
1086
+
1087
+
1088
+	/**
1089
+	 * This method simply returns the RAW unprocessed value for the given property in this class
1090
+	 *
1091
+	 * @param  string $field_name A valid fieldname
1092
+	 * @return mixed              Whatever the raw value stored on the property is.
1093
+	 * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1094
+	 */
1095
+	public function get_raw($field_name)
1096
+	{
1097
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1098
+		switch(true){
1099
+			case $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime:
1100
+				$value = $this->_fields[$field_name]->format('U');
1101
+				break;
1102
+			case $field_settings instanceof EE_Money_Field && $this->_fields[$field_name] instanceof Money:
1103
+				$value = $this->_fields[$field_name]->floatAmount();
1104
+				break;
1105
+			default:
1106
+				$value = $this->_fields[$field_name];
1107
+		}
1108
+		return $value;
1109
+	}
1110
+
1111
+
1112
+
1113
+	/**
1114
+	 * This is used to return the internal DateTime object used for a field that is a
1115
+	 * EE_Datetime_Field.
1116
+	 *
1117
+	 * @param string $field_name               The field name retrieving the DateTime object.
1118
+	 * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1119
+	 * @throws EE_Error
1120
+	 *                                         an error is set and false returned.  If the field IS an
1121
+	 *                                         EE_Datetime_Field and but the field value is null, then
1122
+	 *                                         just null is returned (because that indicates that likely
1123
+	 *                                         this field is nullable).
1124
+	 */
1125
+	public function get_DateTime_object($field_name)
1126
+	{
1127
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1128
+		if ( ! $field_settings instanceof EE_Datetime_Field) {
1129
+			EE_Error::add_error(
1130
+				sprintf(
1131
+					__(
1132
+						'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1133
+						'event_espresso'
1134
+					),
1135
+					$field_name
1136
+				),
1137
+				__FILE__,
1138
+				__FUNCTION__,
1139
+				__LINE__
1140
+			);
1141
+			return false;
1142
+		}
1143
+		return $this->_fields[$field_name];
1144
+	}
1145
+
1146
+
1147
+	/**
1148
+	 * Gets a Money object for the specified field. Please note that this should only be
1149
+	 * used for fields corresponding to EE_Money_Fields, and it will always return a money object,
1150
+	 * or else it will throw an exception.
1151
+	 *
1152
+	 * @param $field_name
1153
+	 * @return Money
1154
+	 * @throws InvalidEntityException
1155
+	 * @throws EE_Error
1156
+	 * @throws DomainException
1157
+	 * @since $VID:$
1158
+	 */
1159
+	public function getMoneyObject($field_name)
1160
+	{
1161
+		$this->verifyUsesMoney(__FUNCTION__);
1162
+		$field = $this->get_model()->field_settings_for($field_name);
1163
+		$value = isset($this->_fields[$field_name]) ? $this->_fields[$field_name] : null;
1164
+		if (! $field instanceof EE_Money_Field
1165
+			|| ! $value instanceof Money) {
1166
+			throw new InvalidEntityException(
1167
+				get_class($value),
1168
+				'Money',
1169
+				sprintf(
1170
+					esc_html__(
1171
+						// @codingStandardsIgnoreStart
1172
+						'Tried to retrieve money value from %1$s with ID %2$s from field %3$s but no money object present.',
1173
+						// @codingStandardsIgnoreEnd
1174
+						'event_espresso'
1175
+					),
1176
+					get_class($this),
1177
+					$this->ID(),
1178
+					$field_name
1179
+				)
1180
+			);
1181
+		}
1182
+		return $value;
1183
+	}
1184
+
1185
+
1186
+
1187
+	/**
1188
+	 * To be used in template to immediately echo out the value, and format it for output.
1189
+	 * Eg, should call stripslashes and whatnot before echoing
1190
+	 *
1191
+	 * @param string $field_name      the name of the field as it appears in the DB
1192
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1193
+	 *                                (in cases where the same property may be used for different outputs
1194
+	 *                                - i.e. datetime, money etc.)
1195
+	 * @return void
1196
+	 * @throws EE_Error
1197
+	 */
1198
+	public function e($field_name, $extra_cache_ref = null)
1199
+	{
1200
+		echo $this->get_pretty($field_name, $extra_cache_ref);
1201
+	}
1202
+
1203
+
1204
+
1205
+	/**
1206
+	 * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1207
+	 * can be easily used as the value of form input.
1208
+	 *
1209
+	 * @param string $field_name
1210
+	 * @return void
1211
+	 * @throws EE_Error
1212
+	 */
1213
+	public function f($field_name)
1214
+	{
1215
+		$this->e($field_name, 'form_input');
1216
+	}
1217
+
1218
+	/**
1219
+	 * Same as `f()` but just returns the value instead of echoing it
1220
+	 * @param string $field_name
1221
+	 * @return string
1222
+	 * @throws EE_Error
1223
+	 */
1224
+	public function get_f($field_name)
1225
+	{
1226
+		return (string)$this->get_pretty($field_name,'form_input');
1227
+	}
1228
+
1229
+
1230
+
1231
+	/**
1232
+	 * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1233
+	 * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1234
+	 * to see what options are available.
1235
+	 * @param string $field_name
1236
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1237
+	 *                                (in cases where the same property may be used for different outputs
1238
+	 *                                - i.e. datetime, money etc.)
1239
+	 * @return mixed
1240
+	 * @throws EE_Error
1241
+	 */
1242
+	public function get_pretty($field_name, $extra_cache_ref = null)
1243
+	{
1244
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1245
+	}
1246
+
1247
+
1248
+
1249
+	/**
1250
+	 * This simply returns the datetime for the given field name
1251
+	 * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1252
+	 * (and the equivalent e_date, e_time, e_datetime).
1253
+	 *
1254
+	 * @access   protected
1255
+	 * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1256
+	 * @param string   $dt_frmt      valid datetime format used for date
1257
+	 *                               (if '' then we just use the default on the field,
1258
+	 *                               if NULL we use the last-used format)
1259
+	 * @param string   $tm_frmt      Same as above except this is for time format
1260
+	 * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1261
+	 * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1262
+	 * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1263
+	 *                               if field is not a valid dtt field, or void if echoing
1264
+	 * @throws EE_Error
1265
+	 */
1266
+	protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1267
+	{
1268
+		// clear cached property
1269
+		$this->_clear_cached_property($field_name);
1270
+		//reset format properties because they are used in get()
1271
+		$this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1272
+		$this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1273
+		if ($echo) {
1274
+			$this->e($field_name, $date_or_time);
1275
+			return '';
1276
+		}
1277
+		return $this->get($field_name, $date_or_time);
1278
+	}
1279
+
1280
+
1281
+
1282
+	/**
1283
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1284
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1285
+	 * other echoes the pretty value for dtt)
1286
+	 *
1287
+	 * @param  string $field_name name of model object datetime field holding the value
1288
+	 * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1289
+	 * @return string            datetime value formatted
1290
+	 * @throws EE_Error
1291
+	 */
1292
+	public function get_date($field_name, $format = '')
1293
+	{
1294
+		return $this->_get_datetime($field_name, $format, null, 'D');
1295
+	}
1296
+
1297
+
1298
+
1299
+	/**
1300
+	 * @param      $field_name
1301
+	 * @param string $format
1302
+	 * @throws EE_Error
1303
+	 */
1304
+	public function e_date($field_name, $format = '')
1305
+	{
1306
+		$this->_get_datetime($field_name, $format, null, 'D', true);
1307
+	}
1308
+
1309
+
1310
+
1311
+	/**
1312
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1313
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1314
+	 * other echoes the pretty value for dtt)
1315
+	 *
1316
+	 * @param  string $field_name name of model object datetime field holding the value
1317
+	 * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1318
+	 * @return string             datetime value formatted
1319
+	 * @throws EE_Error
1320
+	 */
1321
+	public function get_time($field_name, $format = '')
1322
+	{
1323
+		return $this->_get_datetime($field_name, null, $format, 'T');
1324
+	}
1325
+
1326
+
1327
+
1328
+	/**
1329
+	 * @param      $field_name
1330
+	 * @param string $format
1331
+	 * @throws EE_Error
1332
+	 */
1333
+	public function e_time($field_name, $format = '')
1334
+	{
1335
+		$this->_get_datetime($field_name, null, $format, 'T', true);
1336
+	}
1337
+
1338
+
1339
+
1340
+	/**
1341
+	 * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1342
+	 * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1343
+	 * other echoes the pretty value for dtt)
1344
+	 *
1345
+	 * @param  string $field_name name of model object datetime field holding the value
1346
+	 * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1347
+	 * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1348
+	 * @return string             datetime value formatted
1349
+	 * @throws EE_Error
1350
+	 */
1351
+	public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1352
+	{
1353
+		return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1354
+	}
1355
+
1356
+
1357
+
1358
+	/**
1359
+	 * @param string $field_name
1360
+	 * @param string $dt_frmt
1361
+	 * @param string $tm_frmt
1362
+	 * @throws EE_Error
1363
+	 */
1364
+	public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1365
+	{
1366
+		$this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * Get the i8ln value for a date using the WordPress @see date_i18n function.
1372
+	 *
1373
+	 * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1374
+	 * @param string $format PHP valid date/time string format.  If none is provided then the internal set format
1375
+	 *                           on the object will be used.
1376
+	 * @return string Date and time string in set locale or false if no field exists for the given
1377
+	 * @throws InvalidArgumentException
1378
+	 * @throws InvalidInterfaceException
1379
+	 * @throws InvalidDataTypeException
1380
+	 * @throws EE_Error
1381
+	 *                           field name.
1382
+	 */
1383
+	public function get_i18n_datetime($field_name, $format = '')
1384
+	{
1385
+		$format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1386
+		return date_i18n(
1387
+			$format,
1388
+			EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
1389
+		);
1390
+	}
1391
+
1392
+
1393
+
1394
+	/**
1395
+	 * This method validates whether the given field name is a valid field on the model object as well as it is of a
1396
+	 * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1397
+	 * thrown.
1398
+	 *
1399
+	 * @param  string $field_name The field name being checked
1400
+	 * @throws EE_Error
1401
+	 * @return EE_Datetime_Field
1402
+	 */
1403
+	protected function _get_dtt_field_settings($field_name)
1404
+	{
1405
+		$field = $this->get_model()->field_settings_for($field_name);
1406
+		//check if field is dtt
1407
+		if ($field instanceof EE_Datetime_Field) {
1408
+			return $field;
1409
+		} else {
1410
+			throw new EE_Error(sprintf(__('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',
1411
+				'event_espresso'), $field_name, self::_get_model_classname(get_class($this))));
1412
+		}
1413
+	}
1414
+
1415
+
1416
+
1417
+
1418
+	/**
1419
+	 * NOTE ABOUT BELOW:
1420
+	 * These convenience date and time setters are for setting date and time independently.  In other words you might
1421
+	 * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1422
+	 * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1423
+	 * method and make sure you send the entire datetime value for setting.
1424
+	 */
1425
+	/**
1426
+	 * sets the time on a datetime property
1427
+	 *
1428
+	 * @access protected
1429
+	 * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1430
+	 * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1431
+	 * @throws EE_Error
1432
+	 */
1433
+	protected function _set_time_for($time, $fieldname)
1434
+	{
1435
+		$this->_set_date_time('T', $time, $fieldname);
1436
+	}
1437
+
1438
+
1439
+
1440
+	/**
1441
+	 * sets the date on a datetime property
1442
+	 *
1443
+	 * @access protected
1444
+	 * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1445
+	 * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1446
+	 * @throws EE_Error
1447
+	 */
1448
+	protected function _set_date_for($date, $fieldname)
1449
+	{
1450
+		$this->_set_date_time('D', $date, $fieldname);
1451
+	}
1452
+
1453
+
1454
+	/**
1455
+	 * This takes care of setting a date or time independently on a given model object property. This method also
1456
+	 * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1457
+	 *
1458
+	 * @access protected
1459
+	 * @param string $what "T" for time, 'B' for both, 'D' for Date.
1460
+	 * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1461
+	 * @param string $fieldname the name of the field the date OR time is being set on (must match a
1462
+	 *                                        EE_Datetime_Field property)
1463
+	 * @throws InvalidArgumentException
1464
+	 * @throws InvalidInterfaceException
1465
+	 * @throws InvalidDataTypeException
1466
+	 * @throws EE_Error
1467
+	 */
1468
+	protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1469
+	{
1470
+		$field = $this->_get_dtt_field_settings($fieldname);
1471
+		$field->set_timezone($this->_timezone);
1472
+		$field->set_date_format($this->_dt_frmt);
1473
+		$field->set_time_format($this->_tm_frmt);
1474
+		switch ($what) {
1475
+			case 'T' :
1476
+				$this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1477
+					$datetime_value,
1478
+					$this->_fields[$fieldname]
1479
+				);
1480
+				break;
1481
+			case 'D' :
1482
+				$this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1483
+					$datetime_value,
1484
+					$this->_fields[$fieldname]
1485
+				);
1486
+				break;
1487
+			case 'B' :
1488
+				$this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1489
+				break;
1490
+		}
1491
+		$this->_clear_cached_property($fieldname);
1492
+	}
1493
+
1494
+
1495
+	/**
1496
+	 * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1497
+	 * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1498
+	 * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1499
+	 * that could lead to some unexpected results!
1500
+	 *
1501
+	 * @access public
1502
+	 * @param string $field_name This is the name of the field on the object that contains the date/time
1503
+	 *                                         value being returned.
1504
+	 * @param string $callback must match a valid method in this class (defaults to get_datetime)
1505
+	 * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1506
+	 * @param string $prepend You can include something to prepend on the timestamp
1507
+	 * @param string $append You can include something to append on the timestamp
1508
+	 * @throws InvalidArgumentException
1509
+	 * @throws InvalidInterfaceException
1510
+	 * @throws InvalidDataTypeException
1511
+	 * @throws EE_Error
1512
+	 * @return string timestamp
1513
+	 */
1514
+	public function display_in_my_timezone(
1515
+		$field_name,
1516
+		$callback = 'get_datetime',
1517
+		$args = null,
1518
+		$prepend = '',
1519
+		$append = ''
1520
+	) {
1521
+		$timezone = EEH_DTT_Helper::get_timezone();
1522
+		if ($timezone === $this->_timezone) {
1523
+			return '';
1524
+		}
1525
+		$original_timezone = $this->_timezone;
1526
+		$this->set_timezone($timezone);
1527
+		$fn = (array)$field_name;
1528
+		$args = array_merge($fn, (array)$args);
1529
+		if ( ! method_exists($this, $callback)) {
1530
+			throw new EE_Error(
1531
+				sprintf(
1532
+					__(
1533
+						'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1534
+						'event_espresso'
1535
+					),
1536
+					$callback
1537
+				)
1538
+			);
1539
+		}
1540
+		$args = (array)$args;
1541
+		$return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1542
+		$this->set_timezone($original_timezone);
1543
+		return $return;
1544
+	}
1545
+
1546
+
1547
+
1548
+	/**
1549
+	 * Deletes this model object.
1550
+	 * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1551
+	 * override
1552
+	 * `EE_Base_Class::_delete` NOT this class.
1553
+	 *
1554
+	 * @return boolean | int
1555
+	 * @throws EE_Error
1556
+	 */
1557
+	public function delete()
1558
+	{
1559
+		/**
1560
+		 * Called just before the `EE_Base_Class::_delete` method call.
1561
+		 * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1562
+		 * should be aware that `_delete` may not always result in a permanent delete.  For example, `EE_Soft_Delete_Base_Class::_delete`
1563
+		 * soft deletes (trash) the object and does not permanently delete it.
1564
+		 *
1565
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1566
+		 */
1567
+		do_action('AHEE__EE_Base_Class__delete__before', $this);
1568
+		$result = $this->_delete();
1569
+		/**
1570
+		 * Called just after the `EE_Base_Class::_delete` method call.
1571
+		 * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1572
+		 * should be aware that `_delete` may not always result in a permanent delete.  For example `EE_Soft_Base_Class::_delete`
1573
+		 * soft deletes (trash) the object and does not permanently delete it.
1574
+		 *
1575
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1576
+		 * @param boolean       $result
1577
+		 */
1578
+		do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1579
+		return $result;
1580
+	}
1581
+
1582
+
1583
+
1584
+	/**
1585
+	 * Calls the specific delete method for the instantiated class.
1586
+	 * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1587
+	 * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1588
+	 * `EE_Base_Class::delete`
1589
+	 *
1590
+	 * @return bool|int
1591
+	 * @throws EE_Error
1592
+	 */
1593
+	protected function _delete()
1594
+	{
1595
+		return $this->delete_permanently();
1596
+	}
1597
+
1598
+
1599
+
1600
+	/**
1601
+	 * Deletes this model object permanently from db (but keep in mind related models my block the delete and return an
1602
+	 * error)
1603
+	 *
1604
+	 * @return bool | int
1605
+	 * @throws EE_Error
1606
+	 */
1607
+	public function delete_permanently()
1608
+	{
1609
+		/**
1610
+		 * Called just before HARD deleting a model object
1611
+		 *
1612
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1613
+		 */
1614
+		do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1615
+		$model = $this->get_model();
1616
+		$result = $model->delete_permanently_by_ID($this->ID());
1617
+		$this->refresh_cache_of_related_objects();
1618
+		/**
1619
+		 * Called just after HARD deleting a model object
1620
+		 *
1621
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1622
+		 * @param boolean       $result
1623
+		 */
1624
+		do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1625
+		return $result;
1626
+	}
1627
+
1628
+
1629
+
1630
+	/**
1631
+	 * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1632
+	 * related model objects
1633
+	 *
1634
+	 * @throws EE_Error
1635
+	 */
1636
+	public function refresh_cache_of_related_objects()
1637
+	{
1638
+		$model = $this->get_model();
1639
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1640
+			if ( ! empty($this->_model_relations[$relation_name])) {
1641
+				$related_objects = $this->_model_relations[$relation_name];
1642
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
1643
+					//this relation only stores a single model object, not an array
1644
+					//but let's make it consistent
1645
+					$related_objects = array($related_objects);
1646
+				}
1647
+				foreach ($related_objects as $related_object) {
1648
+					//only refresh their cache if they're in memory
1649
+					if ($related_object instanceof EE_Base_Class) {
1650
+						$related_object->clear_cache($model->get_this_model_name(), $this);
1651
+					}
1652
+				}
1653
+			}
1654
+		}
1655
+	}
1656
+
1657
+
1658
+
1659
+	/**
1660
+	 *        Saves this object to the database. An array may be supplied to set some values on this
1661
+	 * object just before saving.
1662
+	 *
1663
+	 * @access public
1664
+	 * @param array $set_cols_n_values keys are field names, values are their new values,
1665
+	 *                                 if provided during the save() method (often client code will change the fields'
1666
+	 *                                 values before calling save)
1667
+	 * @throws EE_Error
1668
+	 * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1669
+	 *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1670
+	 */
1671
+	public function save($set_cols_n_values = array())
1672
+	{
1673
+		$model = $this->get_model();
1674
+		/**
1675
+		 * Filters the fields we're about to save on the model object
1676
+		 *
1677
+		 * @param array         $set_cols_n_values
1678
+		 * @param EE_Base_Class $model_object
1679
+		 */
1680
+		$set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1681
+			$this);
1682
+		//set attributes as provided in $set_cols_n_values
1683
+		foreach ($set_cols_n_values as $column => $value) {
1684
+			$this->set($column, $value);
1685
+		}
1686
+		// no changes ? then don't do anything
1687
+		if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1688
+			return 0;
1689
+		}
1690
+		/**
1691
+		 * Saving a model object.
1692
+		 * Before we perform a save, this action is fired.
1693
+		 *
1694
+		 * @param EE_Base_Class $model_object the model object about to be saved.
1695
+		 */
1696
+		do_action('AHEE__EE_Base_Class__save__begin', $this);
1697
+		if ( ! $this->allow_persist()) {
1698
+			return 0;
1699
+		}
1700
+		//now get current attribute values
1701
+		$save_cols_n_values = $this->_fields;
1702
+		//if the object already has an ID, update it. Otherwise, insert it
1703
+		//also: change the assumption about values passed to the model NOT being prepare dby the model object. They have been
1704
+		$old_assumption_concerning_value_preparation = $model
1705
+															->get_assumption_concerning_values_already_prepared_by_model_object();
1706
+		$model->assume_values_already_prepared_by_model_object(true);
1707
+		//does this model have an autoincrement PK?
1708
+		if ($model->has_primary_key_field()) {
1709
+			if ($model->get_primary_key_field()->is_auto_increment()) {
1710
+				//ok check if it's set, if so: update; if not, insert
1711
+				if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1712
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1713
+				} else {
1714
+					unset($save_cols_n_values[$model->primary_key_name()]);
1715
+					$results = $model->insert($save_cols_n_values);
1716
+					if ($results) {
1717
+						//if successful, set the primary key
1718
+						//but don't use the normal SET method, because it will check if
1719
+						//an item with the same ID exists in the mapper & db, then
1720
+						//will find it in the db (because we just added it) and THAT object
1721
+						//will get added to the mapper before we can add this one!
1722
+						//but if we just avoid using the SET method, all that headache can be avoided
1723
+						$pk_field_name = $model->primary_key_name();
1724
+						$this->_fields[$pk_field_name] = $results;
1725
+						$this->_clear_cached_property($pk_field_name);
1726
+						$model->add_to_entity_map($this);
1727
+						$this->_update_cached_related_model_objs_fks();
1728
+					}
1729
+				}
1730
+			} else {//PK is NOT auto-increment
1731
+				//so check if one like it already exists in the db
1732
+				if ($model->exists_by_ID($this->ID())) {
1733
+					if (WP_DEBUG && ! $this->in_entity_map()) {
1734
+						throw new EE_Error(
1735
+							sprintf(
1736
+								__('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',
1737
+									'event_espresso'),
1738
+								get_class($this),
1739
+								get_class($model) . '::instance()->add_to_entity_map()',
1740
+								get_class($model) . '::instance()->get_one_by_ID()',
1741
+								'<br />'
1742
+							)
1743
+						);
1744
+					}
1745
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1746
+				} else {
1747
+					$results = $model->insert($save_cols_n_values);
1748
+					$this->_update_cached_related_model_objs_fks();
1749
+				}
1750
+			}
1751
+		} else {//there is NO primary key
1752
+			$already_in_db = false;
1753
+			foreach ($model->unique_indexes() as $index) {
1754
+				$uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1755
+				if ($model->exists(array($uniqueness_where_params))) {
1756
+					$already_in_db = true;
1757
+				}
1758
+			}
1759
+			if ($already_in_db) {
1760
+				$combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1761
+					$model->get_combined_primary_key_fields());
1762
+				$results = $model->update($save_cols_n_values, $combined_pk_fields_n_values);
1763
+			} else {
1764
+				$results = $model->insert($save_cols_n_values);
1765
+			}
1766
+		}
1767
+		//restore the old assumption about values being prepared by the model object
1768
+		$model
1769
+			 ->assume_values_already_prepared_by_model_object($old_assumption_concerning_value_preparation);
1770
+		/**
1771
+		 * After saving the model object this action is called
1772
+		 *
1773
+		 * @param EE_Base_Class $model_object which was just saved
1774
+		 * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1775
+		 *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1776
+		 */
1777
+		do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1778
+		$this->_has_changes = false;
1779
+		return $results;
1780
+	}
1781
+
1782
+
1783
+
1784
+	/**
1785
+	 * Updates the foreign key on related models objects pointing to this to have this model object's ID
1786
+	 * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1787
+	 * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1788
+	 * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1789
+	 * 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
1790
+	 * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1791
+	 * or not they exist in the DB (if they do, their DB records will be automatically updated)
1792
+	 *
1793
+	 * @return void
1794
+	 * @throws EE_Error
1795
+	 */
1796
+	protected function _update_cached_related_model_objs_fks()
1797
+	{
1798
+		$model = $this->get_model();
1799
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1800
+			if ($relation_obj instanceof EE_Has_Many_Relation) {
1801
+				foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1802
+					$fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1803
+						$model->get_this_model_name()
1804
+					);
1805
+					$related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1806
+					if ($related_model_obj_in_cache->ID()) {
1807
+						$related_model_obj_in_cache->save();
1808
+					}
1809
+				}
1810
+			}
1811
+		}
1812
+	}
1813
+
1814
+
1815
+
1816
+	/**
1817
+	 * Saves this model object and its NEW cached relations to the database.
1818
+	 * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1819
+	 * In order for that to work, we would need to mark model objects as dirty/clean...
1820
+	 * because otherwise, there's a potential for infinite looping of saving
1821
+	 * Saves the cached related model objects, and ensures the relation between them
1822
+	 * and this object and properly setup
1823
+	 *
1824
+	 * @return int ID of new model object on save; 0 on failure+
1825
+	 * @throws EE_Error
1826
+	 */
1827
+	public function save_new_cached_related_model_objs()
1828
+	{
1829
+		//make sure this has been saved
1830
+		if ( ! $this->ID()) {
1831
+			$id = $this->save();
1832
+		} else {
1833
+			$id = $this->ID();
1834
+		}
1835
+		//now save all the NEW cached model objects  (ie they don't exist in the DB)
1836
+		foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1837
+			if ($this->_model_relations[$relationName]) {
1838
+				//is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1839
+				//or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1840
+				if ($relationObj instanceof EE_Belongs_To_Relation) {
1841
+					//add a relation to that relation type (which saves the appropriate thing in the process)
1842
+					//but ONLY if it DOES NOT exist in the DB
1843
+					/* @var $related_model_obj EE_Base_Class */
1844
+					$related_model_obj = $this->_model_relations[$relationName];
1845
+					//					if( ! $related_model_obj->ID()){
1846
+					$this->_add_relation_to($related_model_obj, $relationName);
1847
+					$related_model_obj->save_new_cached_related_model_objs();
1848
+					//					}
1849
+				} else {
1850
+					foreach ($this->_model_relations[$relationName] as $related_model_obj) {
1851
+						//add a relation to that relation type (which saves the appropriate thing in the process)
1852
+						//but ONLY if it DOES NOT exist in the DB
1853
+						//						if( ! $related_model_obj->ID()){
1854
+						$this->_add_relation_to($related_model_obj, $relationName);
1855
+						$related_model_obj->save_new_cached_related_model_objs();
1856
+						//						}
1857
+					}
1858
+				}
1859
+			}
1860
+		}
1861
+		return $id;
1862
+	}
1863
+
1864
+
1865
+
1866
+	/**
1867
+	 * for getting a model while instantiated.
1868
+	 *
1869
+	 * @return EEM_Base | EEM_CPT_Base
1870
+	 */
1871
+	public function get_model()
1872
+	{
1873
+		if( ! $this->_model){
1874
+			$modelName = self::_get_model_classname(get_class($this));
1875
+			$this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1876
+		} else {
1877
+			$this->_model->set_timezone($this->_timezone);
1878
+		}
1879
+
1880
+		return $this->_model;
1881
+	}
1882
+
1883
+
1884
+
1885
+	/**
1886
+	 * @param $props_n_values
1887
+	 * @param $classname
1888
+	 * @return mixed bool|EE_Base_Class|EEM_CPT_Base
1889
+	 * @throws EE_Error
1890
+	 */
1891
+	protected static function _get_object_from_entity_mapper($props_n_values, $classname)
1892
+	{
1893
+		//TODO: will not work for Term_Relationships because they have no PK!
1894
+		$primary_id_ref = self::_get_primary_key_name($classname);
1895
+		if (array_key_exists($primary_id_ref, $props_n_values) && ! empty($props_n_values[$primary_id_ref])) {
1896
+			$id = $props_n_values[$primary_id_ref];
1897
+			return self::_get_model($classname)->get_from_entity_map($id);
1898
+		}
1899
+		return false;
1900
+	}
1901
+
1902
+
1903
+
1904
+	/**
1905
+	 * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
1906
+	 * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
1907
+	 * 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
1908
+	 * we return false.
1909
+	 *
1910
+	 * @param  array  $props_n_values   incoming array of properties and their values
1911
+	 * @param  string $classname        the classname of the child class
1912
+	 * @param null    $timezone
1913
+	 * @param array   $date_formats     incoming date_formats in an array where the first value is the
1914
+	 *                                  date_format and the second value is the time format
1915
+	 * @return mixed (EE_Base_Class|bool)
1916
+	 * @throws EE_Error
1917
+	 */
1918
+	protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
1919
+	{
1920
+		$existing = null;
1921
+		$model = self::_get_model($classname, $timezone);
1922
+		if ($model->has_primary_key_field()) {
1923
+			$primary_id_ref = self::_get_primary_key_name($classname);
1924
+			if (array_key_exists($primary_id_ref, $props_n_values)
1925
+				&& ! empty($props_n_values[$primary_id_ref])
1926
+			) {
1927
+				$existing = $model->get_one_by_ID(
1928
+					$props_n_values[$primary_id_ref]
1929
+				);
1930
+			}
1931
+		} elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
1932
+			//no primary key on this model, but there's still a matching item in the DB
1933
+			$existing = self::_get_model($classname, $timezone)->get_one_by_ID(
1934
+				self::_get_model($classname, $timezone)->get_index_primary_key_string($props_n_values)
1935
+			);
1936
+		}
1937
+		if ($existing) {
1938
+			//set date formats if present before setting values
1939
+			if ( ! empty($date_formats) && is_array($date_formats)) {
1940
+				$existing->set_date_format($date_formats[0]);
1941
+				$existing->set_time_format($date_formats[1]);
1942
+			} else {
1943
+				//set default formats for date and time
1944
+				$existing->set_date_format(get_option('date_format'));
1945
+				$existing->set_time_format(get_option('time_format'));
1946
+			}
1947
+			foreach ($props_n_values as $property => $field_value) {
1948
+				$existing->set($property, $field_value);
1949
+			}
1950
+			return $existing;
1951
+		} else {
1952
+			return false;
1953
+		}
1954
+	}
1955
+
1956
+
1957
+
1958
+	/**
1959
+	 * Gets the EEM_*_Model for this class
1960
+	 *
1961
+	 * @access public now, as this is more convenient
1962
+	 * @param      $classname
1963
+	 * @param null $timezone
1964
+	 * @throws EE_Error
1965
+	 * @return EEM_Base
1966
+	 */
1967
+	protected static function _get_model($classname, $timezone = null)
1968
+	{
1969
+		//find model for this class
1970
+		if ( ! $classname) {
1971
+			throw new EE_Error(
1972
+				sprintf(
1973
+					__(
1974
+						"What were you thinking calling _get_model(%s)?? You need to specify the class name",
1975
+						"event_espresso"
1976
+					),
1977
+					$classname
1978
+				)
1979
+			);
1980
+		}
1981
+		$modelName = self::_get_model_classname($classname);
1982
+		return self::_get_model_instance_with_name($modelName, $timezone);
1983
+	}
1984
+
1985
+
1986
+	/**
1987
+	 * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
1988
+	 *
1989
+	 * @param string $model_classname
1990
+	 * @param null $timezone
1991
+	 * @return EEM_Base
1992
+	 * @throws \ReflectionException
1993
+	 * @throws InvalidArgumentException
1994
+	 * @throws InvalidInterfaceException
1995
+	 * @throws InvalidDataTypeException
1996
+	 * @throws EE_Error
1997
+	 */
1998
+	protected static function _get_model_instance_with_name($model_classname, $timezone = null)
1999
+	{
2000
+		$model_classname = str_replace('EEM_', '', $model_classname);
2001
+		$model = EE_Registry::instance()->load_model($model_classname);
2002
+		$model->set_timezone($timezone);
2003
+		return $model;
2004
+	}
2005
+
2006
+
2007
+
2008
+	/**
2009
+	 * If a model name is provided (eg Registration), gets the model classname for that model.
2010
+	 * Also works if a model class's classname is provided (eg EE_Registration).
2011
+	 *
2012
+	 * @param null $model_name
2013
+	 * @return string like EEM_Attendee
2014
+	 */
2015
+	private static function _get_model_classname($model_name = null)
2016
+	{
2017
+		if (strpos($model_name, "EE_") === 0) {
2018
+			$model_classname = str_replace("EE_", "EEM_", $model_name);
2019
+		} else {
2020
+			$model_classname = "EEM_" . $model_name;
2021
+		}
2022
+		return $model_classname;
2023
+	}
2024
+
2025
+
2026
+
2027
+	/**
2028
+	 * returns the name of the primary key attribute
2029
+	 *
2030
+	 * @param null $classname
2031
+	 * @throws EE_Error
2032
+	 * @return string
2033
+	 */
2034
+	protected static function _get_primary_key_name($classname = null)
2035
+	{
2036
+		if ( ! $classname) {
2037
+			throw new EE_Error(
2038
+				sprintf(
2039
+					__("What were you thinking calling _get_primary_key_name(%s)", "event_espresso"),
2040
+					$classname
2041
+				)
2042
+			);
2043
+		}
2044
+		return self::_get_model($classname)->get_primary_key_field()->get_name();
2045
+	}
2046
+
2047
+
2048
+
2049
+	/**
2050
+	 * Gets the value of the primary key.
2051
+	 * If the object hasn't yet been saved, it should be whatever the model field's default was
2052
+	 * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2053
+	 * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2054
+	 *
2055
+	 * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2056
+	 * @throws EE_Error
2057
+	 */
2058
+	public function ID()
2059
+	{
2060
+		$model = $this->get_model();
2061
+		//now that we know the name of the variable, use a variable variable to get its value and return its
2062
+		if ($model->has_primary_key_field()) {
2063
+			return $this->_fields[$model->primary_key_name()];
2064
+		} else {
2065
+			return $model->get_index_primary_key_string($this->_fields);
2066
+		}
2067
+	}
2068
+
2069
+
2070
+
2071
+	/**
2072
+	 * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2073
+	 * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2074
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2075
+	 *
2076
+	 * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2077
+	 * @param string $relationName                     eg 'Events','Question',etc.
2078
+	 *                                                 an attendee to a group, you also want to specify which role they
2079
+	 *                                                 will have in that group. So you would use this parameter to
2080
+	 *                                                 specify array('role-column-name'=>'role-id')
2081
+	 * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2082
+	 *                                                 allow you to further constrict the relation to being added.
2083
+	 *                                                 However, keep in mind that the columns (keys) given must match a
2084
+	 *                                                 column on the JOIN table and currently only the HABTM models
2085
+	 *                                                 accept these additional conditions.  Also remember that if an
2086
+	 *                                                 exact match isn't found for these extra cols/val pairs, then a
2087
+	 *                                                 NEW row is created in the join table.
2088
+	 * @param null   $cache_id
2089
+	 * @throws EE_Error
2090
+	 * @return EE_Base_Class the object the relation was added to
2091
+	 */
2092
+	public function _add_relation_to(
2093
+		$otherObjectModelObjectOrID,
2094
+		$relationName,
2095
+		$extra_join_model_fields_n_values = array(),
2096
+		$cache_id = null
2097
+	) {
2098
+		$model = $this->get_model();
2099
+		//if this thing exists in the DB, save the relation to the DB
2100
+		if ($this->ID()) {
2101
+			$otherObject = $model
2102
+								->add_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2103
+									$extra_join_model_fields_n_values);
2104
+			//clear cache so future get_many_related and get_first_related() return new results.
2105
+			$this->clear_cache($relationName, $otherObject, true);
2106
+			if ($otherObject instanceof EE_Base_Class) {
2107
+				$otherObject->clear_cache($model->get_this_model_name(), $this);
2108
+			}
2109
+		} else {
2110
+			//this thing doesn't exist in the DB,  so just cache it
2111
+			if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2112
+				throw new EE_Error(sprintf(
2113
+					__('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',
2114
+						'event_espresso'),
2115
+					$otherObjectModelObjectOrID,
2116
+					get_class($this)
2117
+				));
2118
+			} else {
2119
+				$otherObject = $otherObjectModelObjectOrID;
2120
+			}
2121
+			$this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2122
+		}
2123
+		if ($otherObject instanceof EE_Base_Class) {
2124
+			//fix the reciprocal relation too
2125
+			if ($otherObject->ID()) {
2126
+				//its saved so assumed relations exist in the DB, so we can just
2127
+				//clear the cache so future queries use the updated info in the DB
2128
+				$otherObject->clear_cache($model->get_this_model_name(), null, true);
2129
+			} else {
2130
+				//it's not saved, so it caches relations like this
2131
+				$otherObject->cache($model->get_this_model_name(), $this);
2132
+			}
2133
+		}
2134
+		return $otherObject;
2135
+	}
2136
+
2137
+
2138
+
2139
+	/**
2140
+	 * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2141
+	 * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2142
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2143
+	 * from the cache
2144
+	 *
2145
+	 * @param mixed  $otherObjectModelObjectOrID
2146
+	 *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2147
+	 *                to the DB yet
2148
+	 * @param string $relationName
2149
+	 * @param array  $where_query
2150
+	 *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2151
+	 *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2152
+	 *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2153
+	 *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2154
+	 *                created in the join table.
2155
+	 * @return EE_Base_Class the relation was removed from
2156
+	 * @throws EE_Error
2157
+	 */
2158
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2159
+	{
2160
+		if ($this->ID()) {
2161
+			//if this exists in the DB, save the relation change to the DB too
2162
+			$otherObject = $this->get_model()
2163
+								->remove_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2164
+									$where_query);
2165
+			$this->clear_cache($relationName, $otherObject);
2166
+		} else {
2167
+			//this doesn't exist in the DB, just remove it from the cache
2168
+			$otherObject = $this->clear_cache($relationName, $otherObjectModelObjectOrID);
2169
+		}
2170
+		if ($otherObject instanceof EE_Base_Class) {
2171
+			$otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2172
+		}
2173
+		return $otherObject;
2174
+	}
2175
+
2176
+
2177
+
2178
+	/**
2179
+	 * Removes ALL the related things for the $relationName.
2180
+	 *
2181
+	 * @param string $relationName
2182
+	 * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2183
+	 * @return EE_Base_Class
2184
+	 * @throws EE_Error
2185
+	 */
2186
+	public function _remove_relations($relationName, $where_query_params = array())
2187
+	{
2188
+		if ($this->ID()) {
2189
+			//if this exists in the DB, save the relation change to the DB too
2190
+			$otherObjects = $this->get_model()->remove_relations($this, $relationName, $where_query_params);
2191
+			$this->clear_cache($relationName, null, true);
2192
+		} else {
2193
+			//this doesn't exist in the DB, just remove it from the cache
2194
+			$otherObjects = $this->clear_cache($relationName, null, true);
2195
+		}
2196
+		if (is_array($otherObjects)) {
2197
+			foreach ($otherObjects as $otherObject) {
2198
+				$otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2199
+			}
2200
+		}
2201
+		return $otherObjects;
2202
+	}
2203
+
2204
+
2205
+
2206
+	/**
2207
+	 * Gets all the related model objects of the specified type. Eg, if the current class if
2208
+	 * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2209
+	 * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2210
+	 * because we want to get even deleted items etc.
2211
+	 *
2212
+	 * @param string $relationName key in the model's _model_relations array
2213
+	 * @param array  $query_params like EEM_Base::get_all
2214
+	 * @return EE_Base_Class[] Results not necessarily indexed by IDs, because some results might not have primary keys
2215
+	 * @throws EE_Error
2216
+	 *                             or might not be saved yet. Consider using EEM_Base::get_IDs() on these results if
2217
+	 *                             you want IDs
2218
+	 */
2219
+	public function get_many_related($relationName, $query_params = array())
2220
+	{
2221
+		if ($this->ID()) {
2222
+			//this exists in the DB, so get the related things from either the cache or the DB
2223
+			//if there are query parameters, forget about caching the related model objects.
2224
+			if ($query_params) {
2225
+				$related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2226
+			} else {
2227
+				//did we already cache the result of this query?
2228
+				$cached_results = $this->get_all_from_cache($relationName);
2229
+				if ( ! $cached_results) {
2230
+					$related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2231
+					//if no query parameters were passed, then we got all the related model objects
2232
+					//for that relation. We can cache them then.
2233
+					foreach ($related_model_objects as $related_model_object) {
2234
+						$this->cache($relationName, $related_model_object);
2235
+					}
2236
+				} else {
2237
+					$related_model_objects = $cached_results;
2238
+				}
2239
+			}
2240
+		} else {
2241
+			//this doesn't exist in the DB, so just get the related things from the cache
2242
+			$related_model_objects = $this->get_all_from_cache($relationName);
2243
+		}
2244
+		return $related_model_objects;
2245
+	}
2246
+
2247
+
2248
+	/**
2249
+	 * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2250
+	 * unless otherwise specified in the $query_params
2251
+	 *
2252
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2253
+	 * @param array $query_params like EEM_Base::get_all's
2254
+	 * @param string $field_to_count name of field to count by. By default, uses primary key
2255
+	 * @param bool $distinct if we want to only count the distinct values for the column then you can trigger
2256
+	 *                               that by the setting $distinct to TRUE;
2257
+	 * @return int
2258
+	 * @throws EE_Error
2259
+	 */
2260
+	public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2261
+	{
2262
+		return $this->get_model()->count_related($this, $relation_name, $query_params, $field_to_count, $distinct);
2263
+	}
2264
+
2265
+
2266
+	/**
2267
+	 * Instead of getting the related model objects, simply sums up the values of the specified field.
2268
+	 * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2269
+	 *
2270
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2271
+	 * @param array $query_params like EEM_Base::get_all's
2272
+	 * @param string $field_to_sum name of field to count by.
2273
+	 *                              By default, uses primary key (which doesn't make much sense, so you should probably
2274
+	 *                              change it)
2275
+	 * @return int
2276
+	 * @throws EE_Error
2277
+	 */
2278
+	public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2279
+	{
2280
+		return $this->get_model()->sum_related($this, $relation_name, $query_params, $field_to_sum);
2281
+	}
2282
+
2283
+
2284
+
2285
+	/**
2286
+	 * Gets the first (ie, one) related model object of the specified type.
2287
+	 *
2288
+	 * @param string $relationName key in the model's _model_relations array
2289
+	 * @param array  $query_params like EEM_Base::get_all
2290
+	 * @return EE_Base_Class (not an array, a single object)
2291
+	 * @throws EE_Error
2292
+	 */
2293
+	public function get_first_related($relationName, $query_params = array())
2294
+	{
2295
+		$model = $this->get_model();
2296
+		if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2297
+			//if they've provided some query parameters, don't bother trying to cache the result
2298
+			//also make sure we're not caching the result of get_first_related
2299
+			//on a relation which should have an array of objects (because the cache might have an array of objects)
2300
+			if ($query_params
2301
+				|| ! $model->related_settings_for($relationName)
2302
+					 instanceof
2303
+					 EE_Belongs_To_Relation
2304
+			) {
2305
+				$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2306
+			} else {
2307
+				//first, check if we've already cached the result of this query
2308
+				$cached_result = $this->get_one_from_cache($relationName);
2309
+				if ( ! $cached_result) {
2310
+					$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2311
+					$this->cache($relationName, $related_model_object);
2312
+				} else {
2313
+					$related_model_object = $cached_result;
2314
+				}
2315
+			}
2316
+		} else {
2317
+			$related_model_object = null;
2318
+			//this doesn't exist in the Db, but maybe the relation is of type belongs to, and so the related thing might
2319
+			if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2320
+				$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2321
+			}
2322
+			//this doesn't exist in the DB and apparently the thing it belongs to doesn't either, just get what's cached on this object
2323
+			if ( ! $related_model_object) {
2324
+				$related_model_object = $this->get_one_from_cache($relationName);
2325
+			}
2326
+		}
2327
+		return $related_model_object;
2328
+	}
2329
+
2330
+
2331
+
2332
+	/**
2333
+	 * Does a delete on all related objects of type $relationName and removes
2334
+	 * the current model object's relation to them. If they can't be deleted (because
2335
+	 * of blocking related model objects) does nothing. If the related model objects are
2336
+	 * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2337
+	 * If this model object doesn't exist yet in the DB, just removes its related things
2338
+	 *
2339
+	 * @param string $relationName
2340
+	 * @param array  $query_params like EEM_Base::get_all's
2341
+	 * @return int how many deleted
2342
+	 * @throws EE_Error
2343
+	 */
2344
+	public function delete_related($relationName, $query_params = array())
2345
+	{
2346
+		if ($this->ID()) {
2347
+			$count = $this->get_model()->delete_related($this, $relationName, $query_params);
2348
+		} else {
2349
+			$count = count($this->get_all_from_cache($relationName));
2350
+			$this->clear_cache($relationName, null, true);
2351
+		}
2352
+		return $count;
2353
+	}
2354
+
2355
+
2356
+
2357
+	/**
2358
+	 * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2359
+	 * the current model object's relation to them. If they can't be deleted (because
2360
+	 * of blocking related model objects) just does a soft delete on it instead, if possible.
2361
+	 * If the related thing isn't a soft-deletable model object, this function is identical
2362
+	 * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2363
+	 *
2364
+	 * @param string $relationName
2365
+	 * @param array  $query_params like EEM_Base::get_all's
2366
+	 * @return int how many deleted (including those soft deleted)
2367
+	 * @throws EE_Error
2368
+	 */
2369
+	public function delete_related_permanently($relationName, $query_params = array())
2370
+	{
2371
+		if ($this->ID()) {
2372
+			$count = $this->get_model()->delete_related_permanently($this, $relationName, $query_params);
2373
+		} else {
2374
+			$count = count($this->get_all_from_cache($relationName));
2375
+		}
2376
+		$this->clear_cache($relationName, null, true);
2377
+		return $count;
2378
+	}
2379
+
2380
+
2381
+
2382
+	/**
2383
+	 * is_set
2384
+	 * Just a simple utility function children can use for checking if property exists
2385
+	 *
2386
+	 * @access  public
2387
+	 * @param  string $field_name property to check
2388
+	 * @return bool                              TRUE if existing,FALSE if not.
2389
+	 */
2390
+	public function is_set($field_name)
2391
+	{
2392
+		return isset($this->_fields[$field_name]);
2393
+	}
2394
+
2395
+
2396
+
2397
+	/**
2398
+	 * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2399
+	 * EE_Error exception if they don't
2400
+	 *
2401
+	 * @param  mixed (string|array) $properties properties to check
2402
+	 * @throws EE_Error
2403
+	 * @return bool                              TRUE if existing, throw EE_Error if not.
2404
+	 */
2405
+	protected function _property_exists($properties)
2406
+	{
2407
+		foreach ((array)$properties as $property_name) {
2408
+			//first make sure this property exists
2409
+			if ( ! $this->_fields[$property_name]) {
2410
+				throw new EE_Error(
2411
+					sprintf(
2412
+						__(
2413
+							'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2414
+							'event_espresso'
2415
+						),
2416
+						$property_name
2417
+					)
2418
+				);
2419
+			}
2420
+		}
2421
+		return true;
2422
+	}
2423
+
2424
+
2425
+
2426
+	/**
2427
+	 * This simply returns an array of model fields for this object
2428
+	 *
2429
+	 * @return array
2430
+	 * @throws EE_Error
2431
+	 */
2432
+	public function model_field_array()
2433
+	{
2434
+		$fields = $this->get_model()->field_settings(false);
2435
+		$properties = array();
2436
+		//remove prepended underscore
2437
+		foreach ($fields as $field_name => $settings) {
2438
+			$properties[$field_name] = $this->get($field_name);
2439
+		}
2440
+		return $properties;
2441
+	}
2442
+
2443
+
2444
+
2445
+	/**
2446
+	 * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2447
+	 * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2448
+	 * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
2449
+	 * requiring a plugin to extend the EE_Base_Class (which works fine is there's only 1 plugin, but when will that
2450
+	 * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
2451
+	 * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
2452
+	 * was called, and an array of the original arguments passed to the function. Whatever their callback function
2453
+	 * returns will be returned by this function. Example: in functions.php (or in a plugin):
2454
+	 * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
2455
+	 * my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2456
+	 * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2457
+	 *        return $previousReturnValue.$returnString;
2458
+	 * }
2459
+	 * require('EE_Answer.class.php');
2460
+	 * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2461
+	 * echo $answer->my_callback('monkeys',100);
2462
+	 * //will output "you called my_callback! and passed args:monkeys,100"
2463
+	 *
2464
+	 * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2465
+	 * @param array  $args       array of original arguments passed to the function
2466
+	 * @throws EE_Error
2467
+	 * @return mixed whatever the plugin which calls add_filter decides
2468
+	 */
2469
+	public function __call($methodName, $args)
2470
+	{
2471
+		$className = get_class($this);
2472
+		$tagName = "FHEE__{$className}__{$methodName}";
2473
+		if ( ! has_filter($tagName)) {
2474
+			throw new EE_Error(
2475
+				sprintf(
2476
+					__(
2477
+						"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;}",
2478
+						"event_espresso"
2479
+					),
2480
+					$methodName,
2481
+					$className,
2482
+					$tagName
2483
+				)
2484
+			);
2485
+		}
2486
+		return apply_filters($tagName, null, $this, $args);
2487
+	}
2488
+
2489
+
2490
+	/**
2491
+	 * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2492
+	 * A $previous_value can be specified in case there are many meta rows with the same key
2493
+	 *
2494
+	 * @param string $meta_key
2495
+	 * @param mixed $meta_value
2496
+	 * @param mixed $previous_value
2497
+	 * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2498
+	 * @throws InvalidArgumentException
2499
+	 * @throws InvalidInterfaceException
2500
+	 * @throws InvalidDataTypeException
2501
+	 * @throws EE_Error
2502
+	 * NOTE: if the values haven't changed, returns 0
2503
+	 */
2504
+	public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2505
+	{
2506
+		$query_params = array(
2507
+			array(
2508
+				'EXM_key'  => $meta_key,
2509
+				'OBJ_ID'   => $this->ID(),
2510
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2511
+			),
2512
+		);
2513
+		if ($previous_value !== null) {
2514
+			$query_params[0]['EXM_value'] = $meta_value;
2515
+		}
2516
+		$existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2517
+		if ( ! $existing_rows_like_that) {
2518
+			return $this->add_extra_meta($meta_key, $meta_value);
2519
+		}
2520
+		foreach ($existing_rows_like_that as $existing_row) {
2521
+			$existing_row->save(array('EXM_value' => $meta_value));
2522
+		}
2523
+		return count($existing_rows_like_that);
2524
+	}
2525
+
2526
+
2527
+	/**
2528
+	 * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2529
+	 * no other extra meta for this model object have the same key. Returns TRUE if the
2530
+	 * extra meta row was entered, false if not
2531
+	 *
2532
+	 * @param string $meta_key
2533
+	 * @param mixed $meta_value
2534
+	 * @param boolean $unique
2535
+	 * @return boolean
2536
+	 * @throws InvalidArgumentException
2537
+	 * @throws InvalidInterfaceException
2538
+	 * @throws InvalidDataTypeException
2539
+	 * @throws EE_Error
2540
+	 */
2541
+	public function add_extra_meta($meta_key, $meta_value, $unique = false)
2542
+	{
2543
+		if ($unique) {
2544
+			$existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2545
+				array(
2546
+					array(
2547
+						'EXM_key'  => $meta_key,
2548
+						'OBJ_ID'   => $this->ID(),
2549
+						'EXM_type' => $this->get_model()->get_this_model_name(),
2550
+					),
2551
+				)
2552
+			);
2553
+			if ($existing_extra_meta) {
2554
+				return false;
2555
+			}
2556
+		}
2557
+		$new_extra_meta = EE_Extra_Meta::new_instance(
2558
+			array(
2559
+				'EXM_key'   => $meta_key,
2560
+				'EXM_value' => $meta_value,
2561
+				'OBJ_ID'    => $this->ID(),
2562
+				'EXM_type'  => $this->get_model()->get_this_model_name(),
2563
+			)
2564
+		);
2565
+		$new_extra_meta->save();
2566
+		return true;
2567
+	}
2568
+
2569
+
2570
+	/**
2571
+	 * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2572
+	 * is specified, only deletes extra meta records with that value.
2573
+	 *
2574
+	 * @param string $meta_key
2575
+	 * @param mixed $meta_value
2576
+	 * @return int number of extra meta rows deleted
2577
+	 * @throws InvalidArgumentException
2578
+	 * @throws InvalidInterfaceException
2579
+	 * @throws InvalidDataTypeException
2580
+	 * @throws EE_Error
2581
+	 */
2582
+	public function delete_extra_meta($meta_key, $meta_value = null)
2583
+	{
2584
+		$query_params = array(
2585
+			array(
2586
+				'EXM_key'  => $meta_key,
2587
+				'OBJ_ID'   => $this->ID(),
2588
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2589
+			),
2590
+		);
2591
+		if ($meta_value !== null) {
2592
+			$query_params[0]['EXM_value'] = $meta_value;
2593
+		}
2594
+		return EEM_Extra_Meta::instance()->delete($query_params);
2595
+	}
2596
+
2597
+
2598
+
2599
+	/**
2600
+	 * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2601
+	 * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2602
+	 * You can specify $default is case you haven't found the extra meta
2603
+	 *
2604
+	 * @param string  $meta_key
2605
+	 * @param boolean $single
2606
+	 * @param mixed   $default if we don't find anything, what should we return?
2607
+	 * @return mixed single value if $single; array if ! $single
2608
+	 * @throws EE_Error
2609
+	 */
2610
+	public function get_extra_meta($meta_key, $single = false, $default = null)
2611
+	{
2612
+		if ($single) {
2613
+			$result = $this->get_first_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2614
+			if ($result instanceof EE_Extra_Meta) {
2615
+				return $result->value();
2616
+			}
2617
+		} else {
2618
+			$results = $this->get_many_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2619
+			if ($results) {
2620
+				$values = array();
2621
+				foreach ($results as $result) {
2622
+					if ($result instanceof EE_Extra_Meta) {
2623
+						$values[$result->ID()] = $result->value();
2624
+					}
2625
+				}
2626
+				return $values;
2627
+			}
2628
+		}
2629
+		//if nothing discovered yet return default.
2630
+		return apply_filters(
2631
+			'FHEE__EE_Base_Class__get_extra_meta__default_value',
2632
+			$default,
2633
+			$meta_key,
2634
+			$single,
2635
+			$this
2636
+			);
2637
+	}
2638
+
2639
+
2640
+
2641
+	/**
2642
+	 * Returns a simple array of all the extra meta associated with this model object.
2643
+	 * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2644
+	 * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2645
+	 * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2646
+	 * If $one_of_each_key is false, it will return an array with the top-level keys being
2647
+	 * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2648
+	 * finally the extra meta's value as each sub-value. (eg
2649
+	 * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2650
+	 *
2651
+	 * @param boolean $one_of_each_key
2652
+	 * @return array
2653
+	 * @throws EE_Error
2654
+	 */
2655
+	public function all_extra_meta_array($one_of_each_key = true)
2656
+	{
2657
+		$return_array = array();
2658
+		if ($one_of_each_key) {
2659
+			$extra_meta_objs = $this->get_many_related('Extra_Meta', array('group_by' => 'EXM_key'));
2660
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2661
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2662
+					$return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2663
+				}
2664
+			}
2665
+		} else {
2666
+			$extra_meta_objs = $this->get_many_related('Extra_Meta');
2667
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2668
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2669
+					if ( ! isset($return_array[$extra_meta_obj->key()])) {
2670
+						$return_array[$extra_meta_obj->key()] = array();
2671
+					}
2672
+					$return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2673
+				}
2674
+			}
2675
+		}
2676
+		return $return_array;
2677
+	}
2678
+
2679
+
2680
+
2681
+	/**
2682
+	 * Gets a pretty nice displayable nice for this model object. Often overridden
2683
+	 *
2684
+	 * @return string
2685
+	 * @throws EE_Error
2686
+	 */
2687
+	public function name()
2688
+	{
2689
+		//find a field that's not a text field
2690
+		$field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2691
+		if ($field_we_can_use) {
2692
+			return $this->get($field_we_can_use->get_name());
2693
+		} else {
2694
+			$first_few_properties = $this->model_field_array();
2695
+			$first_few_properties = array_slice($first_few_properties, 0, 3);
2696
+			$name_parts = array();
2697
+			foreach ($first_few_properties as $name => $value) {
2698
+				$name_parts[] = "$name:$value";
2699
+			}
2700
+			return implode(",", $name_parts);
2701
+		}
2702
+	}
2703
+
2704
+
2705
+
2706
+	/**
2707
+	 * in_entity_map
2708
+	 * Checks if this model object has been proven to already be in the entity map
2709
+	 *
2710
+	 * @return boolean
2711
+	 * @throws EE_Error
2712
+	 */
2713
+	public function in_entity_map()
2714
+	{
2715
+		if ($this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this) {
2716
+			//well, if we looked, did we find it in the entity map?
2717
+			return true;
2718
+		} else {
2719
+			return false;
2720
+		}
2721
+	}
2722
+
2723
+
2724
+
2725
+	/**
2726
+	 * refresh_from_db
2727
+	 * Makes sure the fields and values on this model object are in-sync with what's in the database.
2728
+	 *
2729
+	 * @throws EE_Error if this model object isn't in the entity mapper (because then you should
2730
+	 * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
2731
+	 */
2732
+	public function refresh_from_db()
2733
+	{
2734
+		if ($this->ID() && $this->in_entity_map()) {
2735
+			$this->get_model()->refresh_entity_map_from_db($this->ID());
2736
+		} else {
2737
+			//if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
2738
+			//if it has an ID but it's not in the map, and you're asking me to refresh it
2739
+			//that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
2740
+			//absolutely nothing in it for this ID
2741
+			if (WP_DEBUG) {
2742
+				throw new EE_Error(
2743
+					sprintf(
2744
+						__('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.',
2745
+							'event_espresso'),
2746
+						$this->ID(),
2747
+						get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2748
+						get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2749
+					)
2750
+				);
2751
+			}
2752
+		}
2753
+	}
2754
+
2755
+
2756
+	/**
2757
+	 * Gets the money field's amount in subunits (and if the currency has no subunits, gets it in the main units).
2758
+	 * If you want to use this method, the class must implement UsesMoneyInterface and injected a MoneyFactory in
2759
+	 * its constructor
2760
+	 * @param string $money_field_name
2761
+	 * @return int
2762
+	 * @throws InvalidEntityException
2763
+	 * @throws EE_Error
2764
+	 * @throws DomainException
2765
+	 * @since $VID:$
2766
+	 */
2767
+	public function moneyInSubunits($money_field_name)
2768
+	{
2769
+		$this->verifyUsesMoney(__FUNCTION__);
2770
+		return $this->getMoneyObject($money_field_name)->amountInSubunits();
2771
+	}
2772
+
2773
+
2774
+	/**
2775
+	 * Sets the money field's amount based on the incoming monetary subunits (eg pennies). If the currency has no
2776
+	 * subunits, the amount is actually assumed to be in the currency's main units.
2777
+	 * If you want to use this method, the class must implement UsesMoneyInterface and injected a MoneyFactory in
2778
+	 * its constructor
2779
+	 *
2780
+	 * @param string $money_field_name
2781
+	 * @param int    $amount_in_subunits
2782
+	 * @throws InvalidArgumentException
2783
+	 * @throws InvalidInterfaceException
2784
+	 * @throws InvalidIdentifierException
2785
+	 * @throws InvalidDataTypeException
2786
+	 * @throws EE_Error
2787
+	 * @throws DomainException
2788
+	 * @since $VID:$
2789
+	 */
2790
+	public function setMoneySubunits($money_field_name,$amount_in_subunits)
2791
+	{
2792
+		$this->verifyUsesMoney(__FUNCTION__);
2793
+		$money = $this->money_factory->createFromSubUnits(
2794
+			$amount_in_subunits,
2795
+			EE_Config::instance()->currency->code
2796
+		);
2797
+		$this->set($money_field_name, $money);
2798
+	}
2799
+
2800
+
2801
+	/**
2802
+	 * Checks this class has implemented UsesMoneyInterface
2803
+	 * @param string $function
2804
+	 * @throws DomainException
2805
+	 * @throws EE_Error
2806
+	 * @since $VID:$
2807
+	 */
2808
+	private function verifyUsesMoney($function)
2809
+	{
2810
+		if (! $this instanceof UsesMoneyInterface) {
2811
+			throw new DomainException(
2812
+				sprintf(
2813
+					esc_html__(
2814
+						'%1$s does not use an %2$s object for representing money values, therefore the %3$s method can not be called.',
2815
+						'event_espresso'
2816
+					),
2817
+					$this->name(),
2818
+					'EventEspresso\core\domain\values\currency\Money',
2819
+					"{$function}()"
2820
+				)
2821
+			);
2822
+		}
2823
+	}
2824
+
2825
+
2826
+
2827
+	/**
2828
+	 * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
2829
+	 * (probably a bad assumption they have made, oh well)
2830
+	 *
2831
+	 * @return string
2832
+	 */
2833
+	public function __toString()
2834
+	{
2835
+		try {
2836
+			return sprintf('%s (%s)', $this->name(), $this->ID());
2837
+		} catch (Exception $e) {
2838
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
2839
+			return '';
2840
+		}
2841
+	}
2842
+
2843
+
2844
+
2845
+	/**
2846
+	 * Clear related model objects if they're already in the DB, because otherwise when we
2847
+	 * UN-serialize this model object we'll need to be careful to add them to the entity map.
2848
+	 * This means if we have made changes to those related model objects, and want to unserialize
2849
+	 * the this model object on a subsequent request, changes to those related model objects will be lost.
2850
+	 * Instead, those related model objects should be directly serialized and stored.
2851
+	 * Eg, the following won't work:
2852
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2853
+	 * $att = $reg->attendee();
2854
+	 * $att->set( 'ATT_fname', 'Dirk' );
2855
+	 * update_option( 'my_option', serialize( $reg ) );
2856
+	 * //END REQUEST
2857
+	 * //START NEXT REQUEST
2858
+	 * $reg = get_option( 'my_option' );
2859
+	 * $reg->attendee()->save();
2860
+	 * And would need to be replace with:
2861
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2862
+	 * $att = $reg->attendee();
2863
+	 * $att->set( 'ATT_fname', 'Dirk' );
2864
+	 * update_option( 'my_option', serialize( $reg ) );
2865
+	 * //END REQUEST
2866
+	 * //START NEXT REQUEST
2867
+	 * $att = get_option( 'my_option' );
2868
+	 * $att->save();
2869
+	 *
2870
+	 * @return array
2871
+	 * @throws EE_Error
2872
+	 */
2873
+	public function __sleep()
2874
+	{
2875
+		$model = $this->get_model();
2876
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2877
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
2878
+				$classname = 'EE_' . $model->get_this_model_name();
2879
+				if (
2880
+					$this->get_one_from_cache($relation_name) instanceof $classname
2881
+					&& $this->get_one_from_cache($relation_name)->ID()
2882
+				) {
2883
+					$this->clear_cache($relation_name, $this->get_one_from_cache($relation_name)->ID());
2884
+				}
2885
+			}
2886
+		}
2887
+		$this->_props_n_values_provided_in_constructor = array();
2888
+		$properties_to_serialize = get_object_vars($this);
2889
+		//don't serialize the model. It's big and that risks recursion
2890
+		unset(
2891
+			$properties_to_serialize['_model'],
2892
+			$properties_to_serialize['money_factory']
2893
+		);
2894
+		return array_keys($properties_to_serialize);
2895
+	}
2896
+
2897
+
2898
+	/**
2899
+	 * restore _props_n_values_provided_in_constructor
2900
+	 * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
2901
+	 * and therefore should NOT be used to determine if state change has occurred since initial construction.
2902
+	 * At best, you would only be able to detect if state change has occurred during THIS request.
2903
+	 * @throws InvalidInterfaceException
2904
+	 * @throws InvalidDataTypeException
2905
+	 */
2906
+	public function __wakeup()
2907
+	{
2908
+		$this->_props_n_values_provided_in_constructor = $this->_fields;
2909
+		if( $this instanceof UsesMoneyInterface) {
2910
+			$this->money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
2911
+		}
2912
+	}
2913 2913
 
2914 2914
 
2915 2915
 
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -168,8 +168,8 @@  discard block
 block discarded – undo
168 168
             list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
169 169
         } else {
170 170
             //set default formats for date and time
171
-            $this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
172
-            $this->_tm_frmt = (string)get_option('time_format', 'g:i a');
171
+            $this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
172
+            $this->_tm_frmt = (string) get_option('time_format', 'g:i a');
173 173
         }
174 174
         //if db model is instantiating
175 175
         if ($bydb) {
@@ -495,7 +495,7 @@  discard block
 block discarded – undo
495 495
      */
496 496
     public function get_format($full = true)
497 497
     {
498
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
498
+        return $full ? $this->_dt_frmt.' '.$this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
499 499
     }
500 500
 
501 501
 
@@ -604,7 +604,7 @@  discard block
 block discarded – undo
604 604
         $model = $this->get_model();
605 605
         $model->field_settings_for($fieldname);
606 606
         $cache_type = $pretty ? 'pretty' : 'standard';
607
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
607
+        $cache_type .= ! empty($extra_cache_ref) ? '_'.$extra_cache_ref : '';
608 608
         if (isset($this->_cached_properties[$fieldname][$cache_type])) {
609 609
             return $this->_cached_properties[$fieldname][$cache_type];
610 610
         }
@@ -833,7 +833,7 @@  discard block
 block discarded – undo
833 833
         $current_cache_id = ''
834 834
     ) {
835 835
         // verify that incoming object is of the correct type
836
-        $obj_class = 'EE_' . $relationName;
836
+        $obj_class = 'EE_'.$relationName;
837 837
         if ($newly_saved_object instanceof $obj_class) {
838 838
             /* @type EE_Base_Class $newly_saved_object */
839 839
             // now get the type of relation
@@ -1095,7 +1095,7 @@  discard block
 block discarded – undo
1095 1095
     public function get_raw($field_name)
1096 1096
     {
1097 1097
         $field_settings = $this->get_model()->field_settings_for($field_name);
1098
-        switch(true){
1098
+        switch (true) {
1099 1099
             case $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime:
1100 1100
                 $value = $this->_fields[$field_name]->format('U');
1101 1101
                 break;
@@ -1161,7 +1161,7 @@  discard block
 block discarded – undo
1161 1161
         $this->verifyUsesMoney(__FUNCTION__);
1162 1162
         $field = $this->get_model()->field_settings_for($field_name);
1163 1163
         $value = isset($this->_fields[$field_name]) ? $this->_fields[$field_name] : null;
1164
-        if (! $field instanceof EE_Money_Field
1164
+        if ( ! $field instanceof EE_Money_Field
1165 1165
             || ! $value instanceof Money) {
1166 1166
             throw new InvalidEntityException(
1167 1167
                 get_class($value),
@@ -1223,7 +1223,7 @@  discard block
 block discarded – undo
1223 1223
      */
1224 1224
     public function get_f($field_name)
1225 1225
     {
1226
-        return (string)$this->get_pretty($field_name,'form_input');
1226
+        return (string) $this->get_pretty($field_name, 'form_input');
1227 1227
     }
1228 1228
 
1229 1229
 
@@ -1382,7 +1382,7 @@  discard block
 block discarded – undo
1382 1382
      */
1383 1383
     public function get_i18n_datetime($field_name, $format = '')
1384 1384
     {
1385
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1385
+        $format = empty($format) ? $this->_dt_frmt.' '.$this->_tm_frmt : $format;
1386 1386
         return date_i18n(
1387 1387
             $format,
1388 1388
             EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
@@ -1524,8 +1524,8 @@  discard block
 block discarded – undo
1524 1524
         }
1525 1525
         $original_timezone = $this->_timezone;
1526 1526
         $this->set_timezone($timezone);
1527
-        $fn = (array)$field_name;
1528
-        $args = array_merge($fn, (array)$args);
1527
+        $fn = (array) $field_name;
1528
+        $args = array_merge($fn, (array) $args);
1529 1529
         if ( ! method_exists($this, $callback)) {
1530 1530
             throw new EE_Error(
1531 1531
                 sprintf(
@@ -1537,8 +1537,8 @@  discard block
 block discarded – undo
1537 1537
                 )
1538 1538
             );
1539 1539
         }
1540
-        $args = (array)$args;
1541
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1540
+        $args = (array) $args;
1541
+        $return = $prepend.call_user_func_array(array($this, $callback), $args).$append;
1542 1542
         $this->set_timezone($original_timezone);
1543 1543
         return $return;
1544 1544
     }
@@ -1677,14 +1677,14 @@  discard block
 block discarded – undo
1677 1677
          * @param array         $set_cols_n_values
1678 1678
          * @param EE_Base_Class $model_object
1679 1679
          */
1680
-        $set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1680
+        $set_cols_n_values = (array) apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1681 1681
             $this);
1682 1682
         //set attributes as provided in $set_cols_n_values
1683 1683
         foreach ($set_cols_n_values as $column => $value) {
1684 1684
             $this->set($column, $value);
1685 1685
         }
1686 1686
         // no changes ? then don't do anything
1687
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1687
+        if ( ! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1688 1688
             return 0;
1689 1689
         }
1690 1690
         /**
@@ -1736,8 +1736,8 @@  discard block
 block discarded – undo
1736 1736
                                 __('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',
1737 1737
                                     'event_espresso'),
1738 1738
                                 get_class($this),
1739
-                                get_class($model) . '::instance()->add_to_entity_map()',
1740
-                                get_class($model) . '::instance()->get_one_by_ID()',
1739
+                                get_class($model).'::instance()->add_to_entity_map()',
1740
+                                get_class($model).'::instance()->get_one_by_ID()',
1741 1741
                                 '<br />'
1742 1742
                             )
1743 1743
                         );
@@ -1870,7 +1870,7 @@  discard block
 block discarded – undo
1870 1870
      */
1871 1871
     public function get_model()
1872 1872
     {
1873
-        if( ! $this->_model){
1873
+        if ( ! $this->_model) {
1874 1874
             $modelName = self::_get_model_classname(get_class($this));
1875 1875
             $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1876 1876
         } else {
@@ -2017,7 +2017,7 @@  discard block
 block discarded – undo
2017 2017
         if (strpos($model_name, "EE_") === 0) {
2018 2018
             $model_classname = str_replace("EE_", "EEM_", $model_name);
2019 2019
         } else {
2020
-            $model_classname = "EEM_" . $model_name;
2020
+            $model_classname = "EEM_".$model_name;
2021 2021
         }
2022 2022
         return $model_classname;
2023 2023
     }
@@ -2404,7 +2404,7 @@  discard block
 block discarded – undo
2404 2404
      */
2405 2405
     protected function _property_exists($properties)
2406 2406
     {
2407
-        foreach ((array)$properties as $property_name) {
2407
+        foreach ((array) $properties as $property_name) {
2408 2408
             //first make sure this property exists
2409 2409
             if ( ! $this->_fields[$property_name]) {
2410 2410
                 throw new EE_Error(
@@ -2744,8 +2744,8 @@  discard block
 block discarded – undo
2744 2744
                         __('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.',
2745 2745
                             'event_espresso'),
2746 2746
                         $this->ID(),
2747
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2748
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2747
+                        get_class($this->get_model()).'::instance()->add_to_entity_map()',
2748
+                        get_class($this->get_model()).'::instance()->refresh_entity_map()'
2749 2749
                     )
2750 2750
                 );
2751 2751
             }
@@ -2787,7 +2787,7 @@  discard block
 block discarded – undo
2787 2787
      * @throws DomainException
2788 2788
      * @since $VID:$
2789 2789
      */
2790
-    public function setMoneySubunits($money_field_name,$amount_in_subunits)
2790
+    public function setMoneySubunits($money_field_name, $amount_in_subunits)
2791 2791
     {
2792 2792
         $this->verifyUsesMoney(__FUNCTION__);
2793 2793
         $money = $this->money_factory->createFromSubUnits(
@@ -2807,7 +2807,7 @@  discard block
 block discarded – undo
2807 2807
      */
2808 2808
     private function verifyUsesMoney($function)
2809 2809
     {
2810
-        if (! $this instanceof UsesMoneyInterface) {
2810
+        if ( ! $this instanceof UsesMoneyInterface) {
2811 2811
             throw new DomainException(
2812 2812
                 sprintf(
2813 2813
                     esc_html__(
@@ -2875,7 +2875,7 @@  discard block
 block discarded – undo
2875 2875
         $model = $this->get_model();
2876 2876
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2877 2877
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
2878
-                $classname = 'EE_' . $model->get_this_model_name();
2878
+                $classname = 'EE_'.$model->get_this_model_name();
2879 2879
                 if (
2880 2880
                     $this->get_one_from_cache($relation_name) instanceof $classname
2881 2881
                     && $this->get_one_from_cache($relation_name)->ID()
@@ -2906,7 +2906,7 @@  discard block
 block discarded – undo
2906 2906
     public function __wakeup()
2907 2907
     {
2908 2908
         $this->_props_n_values_provided_in_constructor = $this->_fields;
2909
-        if( $this instanceof UsesMoneyInterface) {
2909
+        if ($this instanceof UsesMoneyInterface) {
2910 2910
             $this->money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
2911 2911
         }
2912 2912
     }
Please login to merge, or discard this patch.
core/db_classes/EE_Payment.class.php 3 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -25,7 +25,7 @@  discard block
 block discarded – undo
25 25
      * @param array        $props_n_values      incoming values
26 26
      * @param string       $timezone            incoming timezone (if not set the timezone set for the website will be
27 27
      *                                          used.)
28
-     * @param array        $date_formats        incoming date_formats in an array where the first value is the
28
+     * @param string[]        $date_formats        incoming date_formats in an array where the first value is the
29 29
      *                                          date_format and the second value is the time format
30 30
      * @param MoneyFactory $money_factory
31 31
      * @return EE_Payment
@@ -671,7 +671,7 @@  discard block
 block discarded – undo
671 671
 	 * Gets all the extra meta info on this payment
672 672
 	 *
673 673
 	 * @param array $query_params like EEM_Base::get_all
674
-	 * @return EE_Extra_Meta
674
+	 * @return EE_Base_Class[]
675 675
 	 * @throws EE_Error
676 676
 	 */
677 677
 	public function extra_meta( $query_params = array() ) {
@@ -920,7 +920,7 @@  discard block
 block discarded – undo
920 920
 
921 921
     /**
922 922
      * Returns the payment's transaction's primary registration
923
-     * @return EE_Registration|null
923
+     * @return EE_Base_Class|null
924 924
      * @throws EE_Error
925 925
      */
926 926
     public function get_primary_registration()
Please login to merge, or discard this patch.
Spacing   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -8,8 +8,8 @@  discard block
 block discarded – undo
8 8
 use EventEspresso\core\services\currency\MoneyFactory;
9 9
 use EventEspresso\core\services\loaders\LoaderFactory;
10 10
 
11
-if ( ! defined( 'EVENT_ESPRESSO_VERSION' ) ) {
12
-	exit( 'No direct script access allowed' );
11
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
12
+	exit('No direct script access allowed');
13 13
 }
14 14
 
15 15
 /**
@@ -111,7 +111,7 @@  discard block
 block discarded – undo
111 111
         array $date_formats = array(),
112 112
         MoneyFactory $money_factory = null
113 113
     ) {
114
-        if (! $money_factory instanceof MoneyFactory) {
114
+        if ( ! $money_factory instanceof MoneyFactory) {
115 115
             $money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
116 116
         }
117 117
         $this->money_factory = $money_factory;
@@ -126,8 +126,8 @@  discard block
 block discarded – undo
126 126
 	 * @param int $TXN_ID
127 127
 	 * @throws EE_Error
128 128
 	 */
129
-	public function set_transaction_id( $TXN_ID = 0 ) {
130
-		$this->set( 'TXN_ID', $TXN_ID );
129
+	public function set_transaction_id($TXN_ID = 0) {
130
+		$this->set('TXN_ID', $TXN_ID);
131 131
 	}
132 132
 
133 133
 
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
 	 * @throws EE_Error
140 140
 	 */
141 141
 	public function transaction() {
142
-		return $this->get_first_related( 'Transaction' );
142
+		return $this->get_first_related('Transaction');
143 143
 	}
144 144
 
145 145
 
@@ -151,8 +151,8 @@  discard block
 block discarded – undo
151 151
 	 * @param string $STS_ID
152 152
 	 * @throws EE_Error
153 153
 	 */
154
-	public function set_status( $STS_ID = '' ) {
155
-		$this->set( 'STS_ID', $STS_ID );
154
+	public function set_status($STS_ID = '') {
155
+		$this->set('STS_ID', $STS_ID);
156 156
 	}
157 157
 
158 158
 
@@ -164,8 +164,8 @@  discard block
 block discarded – undo
164 164
 	 * @param int $timestamp
165 165
 	 * @throws EE_Error
166 166
 	 */
167
-	public function set_timestamp( $timestamp = 0 ) {
168
-		$this->set( 'PAY_timestamp', $timestamp );
167
+	public function set_timestamp($timestamp = 0) {
168
+		$this->set('PAY_timestamp', $timestamp);
169 169
 	}
170 170
 
171 171
 
@@ -177,8 +177,8 @@  discard block
 block discarded – undo
177 177
 	 * @param string $PAY_source
178 178
 	 * @throws EE_Error
179 179
 	 */
180
-	public function set_source( $PAY_source = '' ) {
181
-		$this->set( 'PAY_source', $PAY_source );
180
+	public function set_source($PAY_source = '') {
181
+		$this->set('PAY_source', $PAY_source);
182 182
 	}
183 183
 
184 184
 
@@ -190,8 +190,8 @@  discard block
 block discarded – undo
190 190
 	 * @param float $amount
191 191
 	 * @throws EE_Error
192 192
 	 */
193
-	public function set_amount( $amount = 0.00 ) {
194
-		$this->set( 'PAY_amount', (float)$amount );
193
+	public function set_amount($amount = 0.00) {
194
+		$this->set('PAY_amount', (float) $amount);
195 195
 	}
196 196
 
197 197
 
@@ -203,8 +203,8 @@  discard block
 block discarded – undo
203 203
 	 * @param string $gateway_response
204 204
 	 * @throws EE_Error
205 205
 	 */
206
-	public function set_gateway_response( $gateway_response = '' ) {
207
-		$this->set( 'PAY_gateway_response', $gateway_response );
206
+	public function set_gateway_response($gateway_response = '') {
207
+		$this->set('PAY_gateway_response', $gateway_response);
208 208
 	}
209 209
 
210 210
 
@@ -227,7 +227,7 @@  discard block
 block discarded – undo
227 227
 			),
228 228
 			'4.6.0'
229 229
 		);
230
-		return $this->payment_method() ? $this->payment_method()->name() : __( 'Unknown', 'event_espresso' );
230
+		return $this->payment_method() ? $this->payment_method()->name() : __('Unknown', 'event_espresso');
231 231
 	}
232 232
 
233 233
 
@@ -239,8 +239,8 @@  discard block
 block discarded – undo
239 239
 	 * @param string $txn_id_chq_nmbr
240 240
 	 * @throws EE_Error
241 241
 	 */
242
-	public function set_txn_id_chq_nmbr( $txn_id_chq_nmbr = '' ) {
243
-		$this->set( 'PAY_txn_id_chq_nmbr', $txn_id_chq_nmbr );
242
+	public function set_txn_id_chq_nmbr($txn_id_chq_nmbr = '') {
243
+		$this->set('PAY_txn_id_chq_nmbr', $txn_id_chq_nmbr);
244 244
 	}
245 245
 
246 246
 
@@ -252,8 +252,8 @@  discard block
 block discarded – undo
252 252
 	 * @param string $po_number
253 253
 	 * @throws EE_Error
254 254
 	 */
255
-	public function set_po_number( $po_number = '' ) {
256
-		$this->set( 'PAY_po_number', $po_number );
255
+	public function set_po_number($po_number = '') {
256
+		$this->set('PAY_po_number', $po_number);
257 257
 	}
258 258
 
259 259
 
@@ -265,8 +265,8 @@  discard block
 block discarded – undo
265 265
 	 * @param string $extra_accntng
266 266
 	 * @throws EE_Error
267 267
 	 */
268
-	public function set_extra_accntng( $extra_accntng = '' ) {
269
-		$this->set( 'PAY_extra_accntng', $extra_accntng );
268
+	public function set_extra_accntng($extra_accntng = '') {
269
+		$this->set('PAY_extra_accntng', $extra_accntng);
270 270
 	}
271 271
 
272 272
 
@@ -278,11 +278,11 @@  discard block
 block discarded – undo
278 278
 	 * @param bool $via_admin
279 279
 	 * @throws EE_Error
280 280
 	 */
281
-	public function set_payment_made_via_admin( $via_admin = false ) {
282
-		if ( $via_admin ) {
283
-			$this->set( 'PAY_source', EEM_Payment_Method::scope_admin );
281
+	public function set_payment_made_via_admin($via_admin = false) {
282
+		if ($via_admin) {
283
+			$this->set('PAY_source', EEM_Payment_Method::scope_admin);
284 284
 		} else {
285
-			$this->set( 'PAY_source', EEM_Payment_Method::scope_cart );
285
+			$this->set('PAY_source', EEM_Payment_Method::scope_cart);
286 286
 		}
287 287
 	}
288 288
 
@@ -295,13 +295,13 @@  discard block
 block discarded – undo
295 295
 	 * @param string|array $details
296 296
 	 * @throws EE_Error
297 297
 	 */
298
-	public function set_details( $details = '' ) {
299
-		if ( is_array( $details ) ) {
300
-			array_walk_recursive( $details, array( $this, '_strip_all_tags_within_array' ) );
298
+	public function set_details($details = '') {
299
+		if (is_array($details)) {
300
+			array_walk_recursive($details, array($this, '_strip_all_tags_within_array'));
301 301
 		} else {
302
-			$details = wp_strip_all_tags( $details );
302
+			$details = wp_strip_all_tags($details);
303 303
 		}
304
-		$this->set( 'PAY_details', $details );
304
+		$this->set('PAY_details', $details);
305 305
 	}
306 306
 
307 307
 
@@ -312,8 +312,8 @@  discard block
 block discarded – undo
312 312
 	 * @param string $redirect_url
313 313
 	 * @throws EE_Error
314 314
 	 */
315
-	public function set_redirect_url( $redirect_url ) {
316
-		$this->set( 'PAY_redirect_url', $redirect_url );
315
+	public function set_redirect_url($redirect_url) {
316
+		$this->set('PAY_redirect_url', $redirect_url);
317 317
 	}
318 318
 
319 319
 
@@ -324,8 +324,8 @@  discard block
 block discarded – undo
324 324
 	 * @param array $redirect_args
325 325
 	 * @throws EE_Error
326 326
 	 */
327
-	public function set_redirect_args( $redirect_args ) {
328
-		$this->set( 'PAY_redirect_args', $redirect_args );
327
+	public function set_redirect_args($redirect_args) {
328
+		$this->set('PAY_redirect_args', $redirect_args);
329 329
 	}
330 330
 
331 331
 
@@ -337,7 +337,7 @@  discard block
 block discarded – undo
337 337
 	 * @throws EE_Error
338 338
 	 */
339 339
 	public function TXN_ID() {
340
-		return $this->get( 'TXN_ID' );
340
+		return $this->get('TXN_ID');
341 341
 	}
342 342
 
343 343
 
@@ -349,7 +349,7 @@  discard block
 block discarded – undo
349 349
 	 * @throws EE_Error
350 350
 	 */
351 351
 	public function status() {
352
-		return $this->get( 'STS_ID' );
352
+		return $this->get('STS_ID');
353 353
 	}
354 354
 
355 355
 
@@ -361,7 +361,7 @@  discard block
 block discarded – undo
361 361
 	 * @throws EE_Error
362 362
 	 */
363 363
 	public function STS_ID() {
364
-		return $this->get( 'STS_ID' );
364
+		return $this->get('STS_ID');
365 365
 	}
366 366
 
367 367
 
@@ -375,8 +375,8 @@  discard block
 block discarded – undo
375 375
 	 * @return string
376 376
 	 * @throws EE_Error
377 377
 	 */
378
-	public function timestamp( $dt_frmt = '', $tm_frmt = '' ) {
379
-		return $this->get_i18n_datetime( 'PAY_timestamp', trim( $dt_frmt . ' ' . $tm_frmt) );
378
+	public function timestamp($dt_frmt = '', $tm_frmt = '') {
379
+		return $this->get_i18n_datetime('PAY_timestamp', trim($dt_frmt.' '.$tm_frmt));
380 380
 	}
381 381
 
382 382
 
@@ -388,7 +388,7 @@  discard block
 block discarded – undo
388 388
 	 * @throws EE_Error
389 389
 	 */
390 390
 	public function source() {
391
-		return $this->get( 'PAY_source' );
391
+		return $this->get('PAY_source');
392 392
 	}
393 393
 
394 394
 
@@ -401,7 +401,7 @@  discard block
 block discarded – undo
401 401
 	 * @throws EE_Error
402 402
 	 */
403 403
 	public function amount() {
404
-		return (float)$this->get( 'PAY_amount' );
404
+		return (float) $this->get('PAY_amount');
405 405
 	}
406 406
 
407 407
 
@@ -411,7 +411,7 @@  discard block
 block discarded – undo
411 411
 	 * @throws EE_Error
412 412
 	 */
413 413
 	public function amount_no_code() {
414
-		return $this->get_pretty( 'PAY_amount', 'no_currency_code' );
414
+		return $this->get_pretty('PAY_amount', 'no_currency_code');
415 415
 	}
416 416
 
417 417
 
@@ -423,7 +423,7 @@  discard block
 block discarded – undo
423 423
 	 * @throws EE_Error
424 424
 	 */
425 425
 	public function gateway_response() {
426
-		return $this->get( 'PAY_gateway_response' );
426
+		return $this->get('PAY_gateway_response');
427 427
 	}
428 428
 
429 429
 
@@ -435,7 +435,7 @@  discard block
 block discarded – undo
435 435
 	 * @throws EE_Error
436 436
 	 */
437 437
 	public function txn_id_chq_nmbr() {
438
-		return $this->get( 'PAY_txn_id_chq_nmbr' );
438
+		return $this->get('PAY_txn_id_chq_nmbr');
439 439
 	}
440 440
 
441 441
 
@@ -447,7 +447,7 @@  discard block
 block discarded – undo
447 447
 	 * @throws EE_Error
448 448
 	 */
449 449
 	public function po_number() {
450
-		return $this->get( 'PAY_po_number' );
450
+		return $this->get('PAY_po_number');
451 451
 	}
452 452
 
453 453
 
@@ -459,7 +459,7 @@  discard block
 block discarded – undo
459 459
 	 * @throws EE_Error
460 460
 	 */
461 461
 	public function extra_accntng() {
462
-		return $this->get( 'PAY_extra_accntng' );
462
+		return $this->get('PAY_extra_accntng');
463 463
 	}
464 464
 
465 465
 
@@ -471,7 +471,7 @@  discard block
 block discarded – undo
471 471
 	 * @throws EE_Error
472 472
 	 */
473 473
 	public function payment_made_via_admin() {
474
-		return ( $this->get( 'PAY_source' ) === EEM_Payment_Method::scope_admin );
474
+		return ($this->get('PAY_source') === EEM_Payment_Method::scope_admin);
475 475
 	}
476 476
 
477 477
 
@@ -483,7 +483,7 @@  discard block
 block discarded – undo
483 483
 	 * @throws EE_Error
484 484
 	 */
485 485
 	public function details() {
486
-		return $this->get( 'PAY_details' );
486
+		return $this->get('PAY_details');
487 487
 	}
488 488
 
489 489
 
@@ -495,7 +495,7 @@  discard block
 block discarded – undo
495 495
 	 * @throws EE_Error
496 496
 	 */
497 497
 	public function redirect_url() {
498
-		return $this->get( 'PAY_redirect_url' );
498
+		return $this->get('PAY_redirect_url');
499 499
 	}
500 500
 
501 501
 
@@ -507,7 +507,7 @@  discard block
 block discarded – undo
507 507
 	 * @throws EE_Error
508 508
 	 */
509 509
 	public function redirect_args() {
510
-		return $this->get( 'PAY_redirect_args' );
510
+		return $this->get('PAY_redirect_args');
511 511
 	}
512 512
 
513 513
 
@@ -519,8 +519,8 @@  discard block
 block discarded – undo
519 519
 	 * @return void
520 520
 	 * @throws EE_Error
521 521
 	 */
522
-	public function e_pretty_status( $show_icons = false ) {
523
-		echo $this->pretty_status( $show_icons );
522
+	public function e_pretty_status($show_icons = false) {
523
+		echo $this->pretty_status($show_icons);
524 524
 	}
525 525
 
526 526
 
@@ -534,14 +534,14 @@  discard block
 block discarded – undo
534 534
      * @throws InvalidDataTypeException
535 535
      * @throws EE_Error
536 536
      */
537
-	public function pretty_status( $show_icons = false ) {
537
+	public function pretty_status($show_icons = false) {
538 538
 		$status = EEM_Status::instance()->localized_status(
539
-			array( $this->STS_ID() => __( 'unknown', 'event_espresso' ) ),
539
+			array($this->STS_ID() => __('unknown', 'event_espresso')),
540 540
 			false,
541 541
 			'sentence'
542 542
 		);
543 543
 		$icon = '';
544
-		switch ( $this->STS_ID() ) {
544
+		switch ($this->STS_ID()) {
545 545
 			case EEM_Payment::status_id_approved:
546 546
 				$icon = $show_icons
547 547
 					? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>'
@@ -563,7 +563,7 @@  discard block
 block discarded – undo
563 563
 					: '';
564 564
 				break;
565 565
 		}
566
-		return $icon . $status[ $this->STS_ID() ];
566
+		return $icon.$status[$this->STS_ID()];
567 567
 	}
568 568
 
569 569
 
@@ -575,7 +575,7 @@  discard block
 block discarded – undo
575 575
 	 * @throws EE_Error
576 576
 	 */
577 577
 	public function is_approved() {
578
-		return $this->status_is( EEM_Payment::status_id_approved );
578
+		return $this->status_is(EEM_Payment::status_id_approved);
579 579
 	}
580 580
 
581 581
 
@@ -589,7 +589,7 @@  discard block
 block discarded – undo
589 589
 	 * @return boolean whether the status of this payment equals the status id
590 590
 	 * @throws EE_Error
591 591
 	 */
592
-	protected function status_is( $STS_ID ) {
592
+	protected function status_is($STS_ID) {
593 593
 		return $STS_ID === $this->STS_ID() ? true : false;
594 594
 	}
595 595
 
@@ -602,7 +602,7 @@  discard block
 block discarded – undo
602 602
 	 * @throws EE_Error
603 603
 	 */
604 604
 	public function is_pending() {
605
-		return $this->status_is( EEM_Payment::status_id_pending );
605
+		return $this->status_is(EEM_Payment::status_id_pending);
606 606
 	}
607 607
 
608 608
 
@@ -614,7 +614,7 @@  discard block
 block discarded – undo
614 614
 	 * @throws EE_Error
615 615
 	 */
616 616
 	public function is_cancelled() {
617
-		return $this->status_is( EEM_Payment::status_id_cancelled );
617
+		return $this->status_is(EEM_Payment::status_id_cancelled);
618 618
 	}
619 619
 
620 620
 
@@ -626,7 +626,7 @@  discard block
 block discarded – undo
626 626
 	 * @throws EE_Error
627 627
 	 */
628 628
 	public function is_declined() {
629
-		return $this->status_is( EEM_Payment::status_id_declined );
629
+		return $this->status_is(EEM_Payment::status_id_declined);
630 630
 	}
631 631
 
632 632
 
@@ -638,7 +638,7 @@  discard block
 block discarded – undo
638 638
 	 * @throws EE_Error
639 639
 	 */
640 640
 	public function is_failed() {
641
-		return $this->status_is( EEM_Payment::status_id_failed );
641
+		return $this->status_is(EEM_Payment::status_id_failed);
642 642
 	}
643 643
 
644 644
 
@@ -662,7 +662,7 @@  discard block
 block discarded – undo
662 662
 	 * @throws EE_Error
663 663
 	 */
664 664
 	public function status_obj() {
665
-		return $this->get_first_related( 'Status' );
665
+		return $this->get_first_related('Status');
666 666
 	}
667 667
 
668 668
 
@@ -674,8 +674,8 @@  discard block
 block discarded – undo
674 674
 	 * @return EE_Extra_Meta
675 675
 	 * @throws EE_Error
676 676
 	 */
677
-	public function extra_meta( $query_params = array() ) {
678
-		return $this->get_many_related( 'Extra_Meta', $query_params );
677
+	public function extra_meta($query_params = array()) {
678
+		return $this->get_many_related('Extra_Meta', $query_params);
679 679
 	}
680 680
 
681 681
 
@@ -689,7 +689,7 @@  discard block
 block discarded – undo
689 689
 	 * @throws EE_Error
690 690
 	 */
691 691
 	public function payment_method() {
692
-		return $this->get_first_related( 'Payment_Method' );
692
+		return $this->get_first_related('Payment_Method');
693 693
 	}
694 694
 
695 695
 
@@ -707,18 +707,18 @@  discard block
 block discarded – undo
707 707
 	 * @return string html
708 708
 	 * @throws EE_Error
709 709
 	 */
710
-	public function redirect_form( $inside_form_html = null ) {
710
+	public function redirect_form($inside_form_html = null) {
711 711
 		$redirect_url = $this->redirect_url();
712
-		if ( ! empty( $redirect_url ) ) {
712
+		if ( ! empty($redirect_url)) {
713 713
 			// what ? no inner form content?
714
-			if ( $inside_form_html === null ) {
714
+			if ($inside_form_html === null) {
715 715
 				$inside_form_html = EEH_HTML::p(
716 716
 					sprintf(
717 717
 						__(
718 718
 							'If you are not automatically redirected to the payment website within 10 seconds... %1$s %2$s Click Here %3$s',
719 719
 							'event_espresso'
720 720
 						),
721
-						EEH_HTML::br( 2 ),
721
+						EEH_HTML::br(2),
722 722
 						'<input type="submit" value="',
723 723
 						'">'
724 724
 					),
@@ -734,22 +734,22 @@  discard block
 block discarded – undo
734 734
 			);
735 735
 			//if it's a GET request, we need to remove all the GET params in the querystring
736 736
 			//and put them into the form instead
737
-			if ( $method === 'GET' ) {
738
-				$querystring = parse_url( $redirect_url, PHP_URL_QUERY );
737
+			if ($method === 'GET') {
738
+				$querystring = parse_url($redirect_url, PHP_URL_QUERY);
739 739
 				$get_params = null;
740
-				parse_str( $querystring, $get_params );
741
-				$inside_form_html .= $this->_args_as_inputs( $get_params );
742
-				$redirect_url = str_replace( '?' . $querystring, '', $redirect_url );
740
+				parse_str($querystring, $get_params);
741
+				$inside_form_html .= $this->_args_as_inputs($get_params);
742
+				$redirect_url = str_replace('?'.$querystring, '', $redirect_url);
743 743
 			}
744
-			$form = EEH_HTML::nl( 1 )
744
+			$form = EEH_HTML::nl(1)
745 745
 			        . '<form method="'
746 746
 			        . $method
747 747
 			        . '" name="gateway_form" action="'
748 748
 			        . $redirect_url
749 749
 			        . '">';
750
-			$form .= EEH_HTML::nl( 1 ) . $this->redirect_args_as_inputs();
750
+			$form .= EEH_HTML::nl(1).$this->redirect_args_as_inputs();
751 751
 			$form .= $inside_form_html;
752
-			$form .= EEH_HTML::nl( -1 ) . '</form>' . EEH_HTML::nl( -1 );
752
+			$form .= EEH_HTML::nl( -1 ).'</form>'.EEH_HTML::nl( -1 );
753 753
 			return $form;
754 754
 		} else {
755 755
 			return null;
@@ -766,7 +766,7 @@  discard block
 block discarded – undo
766 766
 	 * @throws EE_Error
767 767
 	 */
768 768
 	public function redirect_args_as_inputs() {
769
-		return $this->_args_as_inputs( $this->redirect_args() );
769
+		return $this->_args_as_inputs($this->redirect_args());
770 770
 	}
771 771
 
772 772
 
@@ -778,15 +778,15 @@  discard block
 block discarded – undo
778 778
 	 * @param array $args key-value pairs
779 779
 	 * @return string
780 780
 	 */
781
-	protected function _args_as_inputs( $args ) {
781
+	protected function _args_as_inputs($args) {
782 782
 		$html = '';
783
-		if ( $args !== null && is_array( $args ) ) {
784
-			foreach ( $args as $name => $value ) {
785
-				$html .= EEH_HTML::nl( 0 )
783
+		if ($args !== null && is_array($args)) {
784
+			foreach ($args as $name => $value) {
785
+				$html .= EEH_HTML::nl(0)
786 786
 				         . '<input type="hidden" name="'
787 787
 				         . $name
788 788
 				         . '" value="'
789
-				         . esc_attr( $value )
789
+				         . esc_attr($value)
790 790
 				         . '"/>';
791 791
 			}
792 792
 		}
@@ -815,14 +815,14 @@  discard block
 block discarded – undo
815 815
 	 * @access private
816 816
 	 * @param mixed $item
817 817
 	 */
818
-	private function _strip_all_tags_within_array( &$item ) {
819
-		if ( is_object( $item ) ) {
820
-			$item = (array)$item;
818
+	private function _strip_all_tags_within_array(&$item) {
819
+		if (is_object($item)) {
820
+			$item = (array) $item;
821 821
 		}
822
-		if ( is_array( $item ) ) {
823
-			array_walk_recursive( $item, array( $this, '_strip_all_tags_within_array' ) );
822
+		if (is_array($item)) {
823
+			array_walk_recursive($item, array($this, '_strip_all_tags_within_array'));
824 824
 		} else {
825
-			$item = wp_strip_all_tags( $item );
825
+			$item = wp_strip_all_tags($item);
826 826
 		}
827 827
 	}
828 828
 
@@ -839,7 +839,7 @@  discard block
 block discarded – undo
839 839
 		$original_status = EEH_Array::is_set(
840 840
 			$this->_props_n_values_provided_in_constructor,
841 841
 			'STS_ID',
842
-			$this->get_model()->field_settings_for( 'STS_ID' )->get_default_value()
842
+			$this->get_model()->field_settings_for('STS_ID')->get_default_value()
843 843
 		);
844 844
 		$current_status = $this->status();
845 845
 		if (
@@ -865,11 +865,11 @@  discard block
 block discarded – undo
865 865
 	 * @return mixed
866 866
 	 * @throws EE_Error
867 867
 	 */
868
-	public function get_pretty( $field_name, $extra_cache_ref = null ) {
869
-		if ( $field_name === 'PAY_gateway' ) {
870
-			return $this->payment_method() ? $this->payment_method()->name() : __( 'Unknown', 'event_espresso' );
868
+	public function get_pretty($field_name, $extra_cache_ref = null) {
869
+		if ($field_name === 'PAY_gateway') {
870
+			return $this->payment_method() ? $this->payment_method()->name() : __('Unknown', 'event_espresso');
871 871
 		}
872
-		return $this->_get_cached_property( $field_name, true, $extra_cache_ref );
872
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
873 873
 	}
874 874
 
875 875
 
@@ -881,8 +881,8 @@  discard block
 block discarded – undo
881 881
 	 * @return EE_Registration_Payment[]
882 882
 	 * @throws EE_Error
883 883
 	 */
884
-	public function registration_payments( $query_params = array() ) {
885
-		return $this->get_many_related( 'Registration_Payment', $query_params );
884
+	public function registration_payments($query_params = array()) {
885
+		return $this->get_many_related('Registration_Payment', $query_params);
886 886
 	}
887 887
 
888 888
 
@@ -940,7 +940,7 @@  discard block
 block discarded – undo
940 940
     public function get_primary_attendee()
941 941
     {
942 942
         $primary_reg = $this->get_primary_registration();
943
-        if( $primary_reg instanceof EE_Registration) {
943
+        if ($primary_reg instanceof EE_Registration) {
944 944
             return $primary_reg->attendee();
945 945
         }
946 946
         return null;
Please login to merge, or discard this patch.
Indentation   +214 added lines, -214 removed lines patch added patch discarded remove patch
@@ -21,105 +21,105 @@  discard block
 block discarded – undo
21 21
  */
22 22
 class EE_Payment extends EE_Base_Class implements EEI_Payment, UsesMoneyInterface {
23 23
 
24
-    /**
25
-     * @param array        $props_n_values      incoming values
26
-     * @param string       $timezone            incoming timezone (if not set the timezone set for the website will be
27
-     *                                          used.)
28
-     * @param array        $date_formats        incoming date_formats in an array where the first value is the
29
-     *                                          date_format and the second value is the time format
30
-     * @param MoneyFactory $money_factory
31
-     * @return EE_Payment
32
-     * @throws InvalidArgumentException
33
-     * @throws InvalidInterfaceException
34
-     * @throws InvalidDataTypeException
35
-     * @throws EE_Error
36
-     */
37
-    public static function new_instance(
38
-        $props_n_values = array(),
39
-        $timezone = null,
40
-        $date_formats = array(),
41
-        MoneyFactory $money_factory = null
42
-    ) {
43
-        $has_object = parent::_check_for_object(
44
-            $props_n_values,
45
-            __CLASS__,
46
-            $timezone,
47
-            $date_formats
48
-        );
49
-        return $has_object
50
-            ? $has_object
51
-            : new self(
52
-                $props_n_values,
53
-                false,
54
-                $timezone,
55
-                $date_formats,
56
-                $money_factory
57
-            );
58
-    }
59
-
60
-
61
-    /**
62
-     * @param array        $props_n_values      incoming values from the database
63
-     * @param string       $timezone            incoming timezone as set by the model.  If not set the timezone for
64
-     *                                          the website will be used.
65
-     * @param MoneyFactory $money_factory
66
-     * @return EE_Payment
67
-     * @throws InvalidArgumentException
68
-     * @throws InvalidInterfaceException
69
-     * @throws InvalidDataTypeException
70
-     * @throws EE_Error
71
-     */
72
-    public static function new_instance_from_db(
73
-        $props_n_values = array(),
74
-        $timezone = null,
75
-        MoneyFactory $money_factory = null
76
-    ) {
77
-        return new self(
78
-            $props_n_values,
79
-            true,
80
-            $timezone,
81
-            array(),
82
-            $money_factory
83
-        );
84
-    }
85
-
86
-
87
-    /**
88
-     * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
89
-     * play nice
90
-     *
91
-     * @param array        $fieldValues  where each key is a field (ie, array key in the 2nd layer of the model's
92
-     *                                   _fields array, (eg, EVT_ID, TXN_amount, QST_name, etc) and values are their
93
-     *                                   values
94
-     * @param boolean      $bydb         a flag for setting if the class is instantiated by the corresponding db model
95
-     *                                   or not.
96
-     * @param string       $timezone     indicate what timezone you want any datetime fields to be in when
97
-     *                                   instantiating
98
-     *                                   a EE_Base_Class object.
99
-     * @param array        $date_formats An array of date formats to set on construct where first value is the
100
-     *                                   date_format and second value is the time format.
101
-     * @param MoneyFactory $money_factory
102
-     * @throws InvalidArgumentException
103
-     * @throws InvalidInterfaceException
104
-     * @throws InvalidDataTypeException
105
-     * @throws EE_Error
106
-     */
107
-    protected function __construct(
108
-        array $fieldValues = array(),
109
-        $bydb = false,
110
-        $timezone = '',
111
-        array $date_formats = array(),
112
-        MoneyFactory $money_factory = null
113
-    ) {
114
-        if (! $money_factory instanceof MoneyFactory) {
115
-            $money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
116
-        }
117
-        $this->money_factory = $money_factory;
118
-        parent::__construct($fieldValues, $bydb, $timezone, $date_formats);
119
-    }
120
-
121
-
122
-    /**
24
+	/**
25
+	 * @param array        $props_n_values      incoming values
26
+	 * @param string       $timezone            incoming timezone (if not set the timezone set for the website will be
27
+	 *                                          used.)
28
+	 * @param array        $date_formats        incoming date_formats in an array where the first value is the
29
+	 *                                          date_format and the second value is the time format
30
+	 * @param MoneyFactory $money_factory
31
+	 * @return EE_Payment
32
+	 * @throws InvalidArgumentException
33
+	 * @throws InvalidInterfaceException
34
+	 * @throws InvalidDataTypeException
35
+	 * @throws EE_Error
36
+	 */
37
+	public static function new_instance(
38
+		$props_n_values = array(),
39
+		$timezone = null,
40
+		$date_formats = array(),
41
+		MoneyFactory $money_factory = null
42
+	) {
43
+		$has_object = parent::_check_for_object(
44
+			$props_n_values,
45
+			__CLASS__,
46
+			$timezone,
47
+			$date_formats
48
+		);
49
+		return $has_object
50
+			? $has_object
51
+			: new self(
52
+				$props_n_values,
53
+				false,
54
+				$timezone,
55
+				$date_formats,
56
+				$money_factory
57
+			);
58
+	}
59
+
60
+
61
+	/**
62
+	 * @param array        $props_n_values      incoming values from the database
63
+	 * @param string       $timezone            incoming timezone as set by the model.  If not set the timezone for
64
+	 *                                          the website will be used.
65
+	 * @param MoneyFactory $money_factory
66
+	 * @return EE_Payment
67
+	 * @throws InvalidArgumentException
68
+	 * @throws InvalidInterfaceException
69
+	 * @throws InvalidDataTypeException
70
+	 * @throws EE_Error
71
+	 */
72
+	public static function new_instance_from_db(
73
+		$props_n_values = array(),
74
+		$timezone = null,
75
+		MoneyFactory $money_factory = null
76
+	) {
77
+		return new self(
78
+			$props_n_values,
79
+			true,
80
+			$timezone,
81
+			array(),
82
+			$money_factory
83
+		);
84
+	}
85
+
86
+
87
+	/**
88
+	 * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
89
+	 * play nice
90
+	 *
91
+	 * @param array        $fieldValues  where each key is a field (ie, array key in the 2nd layer of the model's
92
+	 *                                   _fields array, (eg, EVT_ID, TXN_amount, QST_name, etc) and values are their
93
+	 *                                   values
94
+	 * @param boolean      $bydb         a flag for setting if the class is instantiated by the corresponding db model
95
+	 *                                   or not.
96
+	 * @param string       $timezone     indicate what timezone you want any datetime fields to be in when
97
+	 *                                   instantiating
98
+	 *                                   a EE_Base_Class object.
99
+	 * @param array        $date_formats An array of date formats to set on construct where first value is the
100
+	 *                                   date_format and second value is the time format.
101
+	 * @param MoneyFactory $money_factory
102
+	 * @throws InvalidArgumentException
103
+	 * @throws InvalidInterfaceException
104
+	 * @throws InvalidDataTypeException
105
+	 * @throws EE_Error
106
+	 */
107
+	protected function __construct(
108
+		array $fieldValues = array(),
109
+		$bydb = false,
110
+		$timezone = '',
111
+		array $date_formats = array(),
112
+		MoneyFactory $money_factory = null
113
+	) {
114
+		if (! $money_factory instanceof MoneyFactory) {
115
+			$money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
116
+		}
117
+		$this->money_factory = $money_factory;
118
+		parent::__construct($fieldValues, $bydb, $timezone, $date_formats);
119
+	}
120
+
121
+
122
+	/**
123 123
 	 * Set Transaction ID
124 124
 	 *
125 125
 	 * @access public
@@ -524,16 +524,16 @@  discard block
 block discarded – undo
524 524
 	}
525 525
 
526 526
 
527
-    /**
528
-     * returns a pretty version of the status, good for displaying to users
529
-     *
530
-     * @param bool $show_icons
531
-     * @return string
532
-     * @throws InvalidArgumentException
533
-     * @throws InvalidInterfaceException
534
-     * @throws InvalidDataTypeException
535
-     * @throws EE_Error
536
-     */
527
+	/**
528
+	 * returns a pretty version of the status, good for displaying to users
529
+	 *
530
+	 * @param bool $show_icons
531
+	 * @return string
532
+	 * @throws InvalidArgumentException
533
+	 * @throws InvalidInterfaceException
534
+	 * @throws InvalidDataTypeException
535
+	 * @throws EE_Error
536
+	 */
537 537
 	public function pretty_status( $show_icons = false ) {
538 538
 		$status = EEM_Status::instance()->localized_status(
539 539
 			array( $this->STS_ID() => __( 'unknown', 'event_espresso' ) ),
@@ -742,11 +742,11 @@  discard block
 block discarded – undo
742 742
 				$redirect_url = str_replace( '?' . $querystring, '', $redirect_url );
743 743
 			}
744 744
 			$form = EEH_HTML::nl( 1 )
745
-			        . '<form method="'
746
-			        . $method
747
-			        . '" name="gateway_form" action="'
748
-			        . $redirect_url
749
-			        . '">';
745
+					. '<form method="'
746
+					. $method
747
+					. '" name="gateway_form" action="'
748
+					. $redirect_url
749
+					. '">';
750 750
 			$form .= EEH_HTML::nl( 1 ) . $this->redirect_args_as_inputs();
751 751
 			$form .= $inside_form_html;
752 752
 			$form .= EEH_HTML::nl( -1 ) . '</form>' . EEH_HTML::nl( -1 );
@@ -783,11 +783,11 @@  discard block
 block discarded – undo
783 783
 		if ( $args !== null && is_array( $args ) ) {
784 784
 			foreach ( $args as $name => $value ) {
785 785
 				$html .= EEH_HTML::nl( 0 )
786
-				         . '<input type="hidden" name="'
787
-				         . $name
788
-				         . '" value="'
789
-				         . esc_attr( $value )
790
-				         . '"/>';
786
+						 . '<input type="hidden" name="'
787
+						 . $name
788
+						 . '" value="'
789
+						 . esc_attr( $value )
790
+						 . '"/>';
791 791
 			}
792 792
 		}
793 793
 		return $html;
@@ -886,101 +886,101 @@  discard block
 block discarded – undo
886 886
 	}
887 887
 
888 888
 
889
-    /**
890
-     * Gets the first event for this payment (it's possible that it could be for multiple)
891
-     *
892
-     * @return EE_Event|null
893
-     * @throws EE_Error
894
-     */
895
-    public function get_first_event()
896
-    {
897
-        $transaction = $this->transaction();
898
-        if ($transaction instanceof EE_Transaction) {
899
-            $primary_registrant = $transaction->primary_registration();
900
-            if ($primary_registrant instanceof EE_Registration) {
901
-                return $primary_registrant->event_obj();
902
-            }
903
-        }
904
-        return null;
905
-    }
906
-
907
-
908
-    /**
909
-     * Gets the name of the first event for which is being paid
910
-     *
911
-     * @return string
912
-     * @throws EE_Error
913
-     */
914
-    public function get_first_event_name()
915
-    {
916
-        $event = $this->get_first_event();
917
-        return $event instanceof EE_Event ? $event->name() : __('Event', 'event_espresso');
918
-    }
919
-
920
-
921
-    /**
922
-     * Returns the payment's transaction's primary registration
923
-     * @return EE_Registration|null
924
-     * @throws EE_Error
925
-     */
926
-    public function get_primary_registration()
927
-    {
928
-        if ($this->transaction() instanceof EE_Transaction) {
929
-            return $this->transaction()->primary_registration();
930
-        }
931
-        return null;
932
-    }
933
-
934
-
935
-    /**
936
-     * Gets the payment's transaction's primary registration's attendee, or null
937
-     * @return EE_Attendee|null
938
-     * @throws EE_Error
939
-     */
940
-    public function get_primary_attendee()
941
-    {
942
-        $primary_reg = $this->get_primary_registration();
943
-        if( $primary_reg instanceof EE_Registration) {
944
-            return $primary_reg->attendee();
945
-        }
946
-        return null;
947
-    }
948
-
949
-
950
-    /**
951
-     * Returns the payment's amount in subunits (if the currency has subunits; otherwise this will actually be
952
-     * in the currency's main units)
953
-     *
954
-     * @return int
955
-     * @throws EE_Error
956
-     * @throws InvalidEntityException
957
-     * @throws DomainException
958
-     * @since $VID:$
959
-     */
960
-    public function amountInSubunits()
961
-    {
962
-        return $this->moneyInSubunits('PAY_amount');
963
-    }
964
-
965
-
966
-    /**
967
-     * Sets the payment's amount based on the incoming monetary subunits (eg pennies). If the currency has no subunits,
968
-     * the amount is actually assumed to be in the currency's main units
969
-     *
970
-     * @param int $amount_in_subunits
971
-     * @return void
972
-     * @throws EE_Error
973
-     * @throws InvalidArgumentException
974
-     * @throws InvalidInterfaceException
975
-     * @throws InvalidIdentifierException
976
-     * @throws InvalidDataTypeException
977
-     * @throws DomainException
978
-     * @since $VID:$
979
-     */
980
-    public function setAmountInSubunits($amount_in_subunits)
981
-    {
982
-        $this->setMoneySubunits('PAY_amount', $amount_in_subunits);
983
-    }
889
+	/**
890
+	 * Gets the first event for this payment (it's possible that it could be for multiple)
891
+	 *
892
+	 * @return EE_Event|null
893
+	 * @throws EE_Error
894
+	 */
895
+	public function get_first_event()
896
+	{
897
+		$transaction = $this->transaction();
898
+		if ($transaction instanceof EE_Transaction) {
899
+			$primary_registrant = $transaction->primary_registration();
900
+			if ($primary_registrant instanceof EE_Registration) {
901
+				return $primary_registrant->event_obj();
902
+			}
903
+		}
904
+		return null;
905
+	}
906
+
907
+
908
+	/**
909
+	 * Gets the name of the first event for which is being paid
910
+	 *
911
+	 * @return string
912
+	 * @throws EE_Error
913
+	 */
914
+	public function get_first_event_name()
915
+	{
916
+		$event = $this->get_first_event();
917
+		return $event instanceof EE_Event ? $event->name() : __('Event', 'event_espresso');
918
+	}
919
+
920
+
921
+	/**
922
+	 * Returns the payment's transaction's primary registration
923
+	 * @return EE_Registration|null
924
+	 * @throws EE_Error
925
+	 */
926
+	public function get_primary_registration()
927
+	{
928
+		if ($this->transaction() instanceof EE_Transaction) {
929
+			return $this->transaction()->primary_registration();
930
+		}
931
+		return null;
932
+	}
933
+
934
+
935
+	/**
936
+	 * Gets the payment's transaction's primary registration's attendee, or null
937
+	 * @return EE_Attendee|null
938
+	 * @throws EE_Error
939
+	 */
940
+	public function get_primary_attendee()
941
+	{
942
+		$primary_reg = $this->get_primary_registration();
943
+		if( $primary_reg instanceof EE_Registration) {
944
+			return $primary_reg->attendee();
945
+		}
946
+		return null;
947
+	}
948
+
949
+
950
+	/**
951
+	 * Returns the payment's amount in subunits (if the currency has subunits; otherwise this will actually be
952
+	 * in the currency's main units)
953
+	 *
954
+	 * @return int
955
+	 * @throws EE_Error
956
+	 * @throws InvalidEntityException
957
+	 * @throws DomainException
958
+	 * @since $VID:$
959
+	 */
960
+	public function amountInSubunits()
961
+	{
962
+		return $this->moneyInSubunits('PAY_amount');
963
+	}
964
+
965
+
966
+	/**
967
+	 * Sets the payment's amount based on the incoming monetary subunits (eg pennies). If the currency has no subunits,
968
+	 * the amount is actually assumed to be in the currency's main units
969
+	 *
970
+	 * @param int $amount_in_subunits
971
+	 * @return void
972
+	 * @throws EE_Error
973
+	 * @throws InvalidArgumentException
974
+	 * @throws InvalidInterfaceException
975
+	 * @throws InvalidIdentifierException
976
+	 * @throws InvalidDataTypeException
977
+	 * @throws DomainException
978
+	 * @since $VID:$
979
+	 */
980
+	public function setAmountInSubunits($amount_in_subunits)
981
+	{
982
+		$this->setMoneySubunits('PAY_amount', $amount_in_subunits);
983
+	}
984 984
 }
985 985
 /* End of file EE_Payment.class.php */
986 986
 /* Location: /includes/classes/EE_Payment.class.php */
Please login to merge, or discard this patch.