Completed
Branch FET/11129/facilitate-stripe-an... (d5ad13)
by
unknown
222:28 queued 209:58
created
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   +2843 added lines, -2843 removed lines patch added patch discarded remove patch
@@ -10,7 +10,7 @@  discard block
 block discarded – undo
10 10
 use EventEspresso\core\services\loaders\LoaderFactory;
11 11
 
12 12
 if ( ! defined('EVENT_ESPRESSO_VERSION')) {
13
-    exit('No direct script access allowed');
13
+	exit('No direct script access allowed');
14 14
 }
15 15
 do_action('AHEE_log', __FILE__, ' FILE LOADED', '');
16 16
 
@@ -36,2848 +36,2848 @@  discard block
 block discarded – undo
36 36
 abstract class EE_Base_Class
37 37
 {
38 38
 
39
-    /**
40
-     * This is an array of the original properties and values provided during construction
41
-     * of this model object. (keys are model field names, values are their values).
42
-     * This list is important to remember so that when we are merging data from the db, we know
43
-     * which values to override and which to not override.
44
-     *
45
-     * @var array
46
-     */
47
-    protected $_props_n_values_provided_in_constructor;
48
-
49
-    /**
50
-     * Timezone
51
-     * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
52
-     * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
53
-     * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
54
-     * access to it.
55
-     *
56
-     * @var string
57
-     */
58
-    protected $_timezone;
59
-
60
-
61
-
62
-    /**
63
-     * date format
64
-     * pattern or format for displaying dates
65
-     *
66
-     * @var string $_dt_frmt
67
-     */
68
-    protected $_dt_frmt;
69
-
70
-
71
-
72
-    /**
73
-     * time format
74
-     * pattern or format for displaying time
75
-     *
76
-     * @var string $_tm_frmt
77
-     */
78
-    protected $_tm_frmt;
79
-
80
-
81
-
82
-    /**
83
-     * This property is for holding a cached array of object properties indexed by property name as the key.
84
-     * The purpose of this is for setting a cache on properties that may have calculated values after a
85
-     * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
86
-     * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
87
-     *
88
-     * @var array
89
-     */
90
-    protected $_cached_properties = array();
91
-
92
-    /**
93
-     * An array containing keys of the related model, and values are either an array of related mode objects or a
94
-     * single
95
-     * related model object. see the model's _model_relations. The keys should match those specified. And if the
96
-     * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
97
-     * all others have an array)
98
-     *
99
-     * @var array
100
-     */
101
-    protected $_model_relations = array();
102
-
103
-    /**
104
-     * Array where keys are field names (see the model's _fields property) and values are their values. To see what
105
-     * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
106
-     *
107
-     * @var array
108
-     */
109
-    protected $_fields = array();
110
-
111
-    /**
112
-     * @var boolean indicating whether or not this model object is intended to ever be saved
113
-     * For example, we might create model objects intended to only be used for the duration
114
-     * of this request and to be thrown away, and if they were accidentally saved
115
-     * it would be a bug.
116
-     */
117
-    protected $_allow_persist = true;
118
-
119
-    /**
120
-     * @var boolean indicating whether or not this model object's properties have changed since construction
121
-     */
122
-    protected $_has_changes = false;
123
-
124
-    /**
125
-     * @var EEM_Base
126
-     */
127
-    protected $_model;
128
-
129
-    /**
130
-     * @var MoneyFactory
131
-     */
132
-    protected $money_factory;
133
-
134
-
135
-    /**
136
-     * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
137
-     * play nice
138
-     *
139
-     * @param array $fieldValues where each key is a field (ie, array key in the 2nd
140
-     *                                                         layer of the model's _fields array, (eg, EVT_ID,
141
-     *                                                         TXN_amount, QST_name, etc) and values are their values
142
-     * @param boolean $bydb a flag for setting if the class is instantiated by the
143
-     *                                                         corresponding db model or not.
144
-     * @param string $timezone indicate what timezone you want any datetime fields to
145
-     *                                                         be in when instantiating a EE_Base_Class object.
146
-     * @param array $date_formats An array of date formats to set on construct where first
147
-     *                                                         value is the date_format and second value is the time
148
-     *                                                         format.
149
-     * @param MoneyFactory|null $money_factory
150
-     * @throws InvalidArgumentException
151
-     * @throws InvalidInterfaceException
152
-     * @throws InvalidDataTypeException
153
-     * @throws EE_Error
154
-     */
155
-    protected function __construct(
156
-        $fieldValues = array(),
157
-        $bydb = false,
158
-        $timezone = '',
159
-        $date_formats = array(),
160
-        MoneyFactory $money_factory = null
161
-    ) {
162
-        if (! $money_factory instanceof MoneyFactory) {
163
-            $money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
164
-        }
165
-        $this->money_factory = $money_factory;
166
-        $className = get_class($this);
167
-        do_action("AHEE__{$className}__construct", $this, $fieldValues);
168
-        $model = $this->get_model();
169
-        $model_fields = $model->field_settings(false);
170
-        // ensure $fieldValues is an array
171
-        $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
172
-        // EEH_Debug_Tools::printr( $fieldValues, '$fieldValues  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
173
-        // verify client code has not passed any invalid field names
174
-        foreach ($fieldValues as $field_name => $field_value) {
175
-            if ( ! isset($model_fields[$field_name])) {
176
-                throw new EE_Error(sprintf(__("Invalid field (%s) passed to constructor of %s. Allowed fields are :%s",
177
-                    "event_espresso"), $field_name, get_class($this), implode(", ", array_keys($model_fields))));
178
-            }
179
-        }
180
-        // EEH_Debug_Tools::printr( $model_fields, '$model_fields  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
181
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
182
-        if ( ! empty($date_formats) && is_array($date_formats)) {
183
-            list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
184
-        } else {
185
-            //set default formats for date and time
186
-            $this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
187
-            $this->_tm_frmt = (string)get_option('time_format', 'g:i a');
188
-        }
189
-        //if db model is instantiating
190
-        if ($bydb) {
191
-            //client code has indicated these field values are from the database
192
-            foreach ($model_fields as $fieldName => $field) {
193
-                $this->set_from_db($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null);
194
-            }
195
-        } else {
196
-            //we're constructing a brand
197
-            //new instance of the model object. Generally, this means we'll need to do more field validation
198
-            foreach ($model_fields as $fieldName => $field) {
199
-                $this->set($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true);
200
-            }
201
-        }
202
-        //remember what values were passed to this constructor
203
-        $this->_props_n_values_provided_in_constructor = $fieldValues;
204
-        //remember in entity mapper
205
-        if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
206
-            $model->add_to_entity_map($this);
207
-        }
208
-        //setup all the relations
209
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
210
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
211
-                $this->_model_relations[$relation_name] = null;
212
-            } else {
213
-                $this->_model_relations[$relation_name] = array();
214
-            }
215
-        }
216
-        /**
217
-         * Action done at the end of each model object construction
218
-         *
219
-         * @param EE_Base_Class $this the model object just created
220
-         */
221
-        do_action('AHEE__EE_Base_Class__construct__finished', $this);
222
-    }
223
-
224
-
225
-
226
-    /**
227
-     * Gets whether or not this model object is allowed to persist/be saved to the database.
228
-     *
229
-     * @return boolean
230
-     */
231
-    public function allow_persist()
232
-    {
233
-        return $this->_allow_persist;
234
-    }
235
-
236
-
237
-
238
-    /**
239
-     * Sets whether or not this model object should be allowed to be saved to the DB.
240
-     * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
241
-     * you got new information that somehow made you change your mind.
242
-     *
243
-     * @param boolean $allow_persist
244
-     * @return boolean
245
-     */
246
-    public function set_allow_persist($allow_persist)
247
-    {
248
-        return $this->_allow_persist = $allow_persist;
249
-    }
250
-
251
-
252
-
253
-    /**
254
-     * Gets the field's original value when this object was constructed during this request.
255
-     * This can be helpful when determining if a model object has changed or not
256
-     *
257
-     * @param string $field_name
258
-     * @return mixed|null
259
-     * @throws EE_Error
260
-     */
261
-    public function get_original($field_name)
262
-    {
263
-        if (isset($this->_props_n_values_provided_in_constructor[$field_name])
264
-            && $field_settings = $this->get_model()->field_settings_for($field_name)
265
-        ) {
266
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
267
-        } else {
268
-            return null;
269
-        }
270
-    }
271
-
272
-
273
-
274
-    /**
275
-     * @param EE_Base_Class $obj
276
-     * @return string
277
-     */
278
-    public function get_class($obj)
279
-    {
280
-        return get_class($obj);
281
-    }
282
-
283
-
284
-    /**
285
-     * Overrides parent because parent expects old models.
286
-     * This also doesn't do any validation, and won't work for serialized arrays
287
-     *
288
-     * @param    string $field_name
289
-     * @param    mixed $field_value
290
-     * @param bool $use_default
291
-     * @throws InvalidArgumentException
292
-     * @throws InvalidInterfaceException
293
-     * @throws InvalidDataTypeException
294
-     * @throws EE_Error
295
-     */
296
-    public function set($field_name, $field_value, $use_default = false)
297
-    {
298
-        // if not using default and nothing has changed, and object has already been setup (has ID),
299
-        // then don't do anything
300
-        if (
301
-            ! $use_default
302
-            && $this->_fields[$field_name] === $field_value
303
-            && $this->ID()
304
-        ) {
305
-            return;
306
-        }
307
-        $model = $this->get_model();
308
-        $this->_has_changes = true;
309
-        $field_obj = $model->field_settings_for($field_name);
310
-        if ($field_obj instanceof EE_Model_Field_Base) {
311
-            //			if ( method_exists( $field_obj, 'set_timezone' )) {
312
-            if ($field_obj instanceof EE_Datetime_Field) {
313
-                $field_obj->set_timezone($this->_timezone);
314
-                $field_obj->set_date_format($this->_dt_frmt);
315
-                $field_obj->set_time_format($this->_tm_frmt);
316
-            }
317
-            $holder_of_value = $field_obj->prepare_for_set($field_value);
318
-            //should the value be null?
319
-            if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
320
-                $this->_fields[$field_name] = $field_obj->get_default_value();
321
-                /**
322
-                 * To save having to refactor all the models, if a default value is used for a
323
-                 * EE_Datetime_Field, and that value is not null nor is it a DateTime
324
-                 * object.  Then let's do a set again to ensure that it becomes a DateTime
325
-                 * object.
326
-                 *
327
-                 * @since 4.6.10+
328
-                 */
329
-                if (
330
-                    $field_obj instanceof EE_Datetime_Field
331
-                    && $this->_fields[$field_name] !== null
332
-                    && ! $this->_fields[$field_name] instanceof DateTime
333
-                ) {
334
-                    empty($this->_fields[$field_name])
335
-                        ? $this->set($field_name, time())
336
-                        : $this->set($field_name, $this->_fields[$field_name]);
337
-                }
338
-            } else {
339
-                $this->_fields[$field_name] = $holder_of_value;
340
-            }
341
-            //if we're not in the constructor...
342
-            //now check if what we set was a primary key
343
-            if (
344
-                //note: props_n_values_provided_in_constructor is only set at the END of the constructor
345
-                $this->_props_n_values_provided_in_constructor
346
-                && $field_value
347
-                && $field_name === $model->primary_key_name()
348
-            ) {
349
-                //if so, we want all this object's fields to be filled either with
350
-                //what we've explicitly set on this model
351
-                //or what we have in the db
352
-                // echo "setting primary key!";
353
-                $fields_on_model = self::_get_model(get_class($this))->field_settings();
354
-                $obj_in_db = self::_get_model(get_class($this))->get_one_by_ID($field_value);
355
-                foreach ($fields_on_model as $field_obj) {
356
-                    if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
357
-                         && $field_obj->get_name() !== $field_name
358
-                    ) {
359
-                        $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
360
-                    }
361
-                }
362
-                //oh this model object has an ID? well make sure its in the entity mapper
363
-                $model->add_to_entity_map($this);
364
-            }
365
-            //let's unset any cache for this field_name from the $_cached_properties property.
366
-            $this->_clear_cached_property($field_name);
367
-        } else {
368
-            throw new EE_Error(sprintf(__("A valid EE_Model_Field_Base could not be found for the given field name: %s",
369
-                "event_espresso"), $field_name));
370
-        }
371
-    }
372
-
373
-
374
-
375
-    /**
376
-     * This sets the field value on the db column if it exists for the given $column_name or
377
-     * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
378
-     *
379
-     * @see EE_message::get_column_value for related documentation on the necessity of this method.
380
-     * @param string $field_name  Must be the exact column name.
381
-     * @param mixed  $field_value The value to set.
382
-     * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
383
-     * @throws EE_Error
384
-     */
385
-    public function set_field_or_extra_meta($field_name, $field_value)
386
-    {
387
-        if ($this->get_model()->has_field($field_name)) {
388
-            $this->set($field_name, $field_value);
389
-            return true;
390
-        } else {
391
-            //ensure this object is saved first so that extra meta can be properly related.
392
-            $this->save();
393
-            return $this->update_extra_meta($field_name, $field_value);
394
-        }
395
-    }
396
-
397
-
398
-
399
-    /**
400
-     * This retrieves the value of the db column set on this class or if that's not present
401
-     * it will attempt to retrieve from extra_meta if found.
402
-     * Example Usage:
403
-     * Via EE_Message child class:
404
-     * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
405
-     * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
406
-     * also have additional main fields specific to the messenger.  The system accommodates those extra
407
-     * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
408
-     * value for those extra fields dynamically via the EE_message object.
409
-     *
410
-     * @param  string $field_name expecting the fully qualified field name.
411
-     * @return mixed|null  value for the field if found.  null if not found.
412
-     * @throws EE_Error
413
-     */
414
-    public function get_field_or_extra_meta($field_name)
415
-    {
416
-        if ($this->get_model()->has_field($field_name)) {
417
-            $column_value = $this->get($field_name);
418
-        } else {
419
-            //This isn't a column in the main table, let's see if it is in the extra meta.
420
-            $column_value = $this->get_extra_meta($field_name, true, null);
421
-        }
422
-        return $column_value;
423
-    }
424
-
425
-
426
-    /**
427
-     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
428
-     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
429
-     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
430
-     * available to all child classes that may be using the EE_Datetime_Field for a field data type.
431
-     *
432
-     * @access public
433
-     * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
434
-     * @return void
435
-     * @throws InvalidArgumentException
436
-     * @throws InvalidInterfaceException
437
-     * @throws InvalidDataTypeException
438
-     * @throws EE_Error
439
-     */
440
-    public function set_timezone($timezone = '')
441
-    {
442
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
443
-        //make sure we clear all cached properties because they won't be relevant now
444
-        $this->_clear_cached_properties();
445
-        //make sure we update field settings and the date for all EE_Datetime_Fields
446
-        $model_fields = $this->get_model()->field_settings(false);
447
-        foreach ($model_fields as $field_name => $field_obj) {
448
-            if ($field_obj instanceof EE_Datetime_Field) {
449
-                $field_obj->set_timezone($this->_timezone);
450
-                if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
451
-                    $this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
452
-                }
453
-            }
454
-        }
455
-    }
456
-
457
-
458
-
459
-    /**
460
-     * This just returns whatever is set for the current timezone.
461
-     *
462
-     * @access public
463
-     * @return string timezone string
464
-     */
465
-    public function get_timezone()
466
-    {
467
-        return $this->_timezone;
468
-    }
469
-
470
-
471
-
472
-    /**
473
-     * This sets the internal date format to what is sent in to be used as the new default for the class
474
-     * internally instead of wp set date format options
475
-     *
476
-     * @since 4.6
477
-     * @param string $format should be a format recognizable by PHP date() functions.
478
-     */
479
-    public function set_date_format($format)
480
-    {
481
-        $this->_dt_frmt = $format;
482
-        //clear cached_properties because they won't be relevant now.
483
-        $this->_clear_cached_properties();
484
-    }
485
-
486
-
487
-
488
-    /**
489
-     * This sets the internal time format string to what is sent in to be used as the new default for the
490
-     * class internally instead of wp set time format options.
491
-     *
492
-     * @since 4.6
493
-     * @param string $format should be a format recognizable by PHP date() functions.
494
-     */
495
-    public function set_time_format($format)
496
-    {
497
-        $this->_tm_frmt = $format;
498
-        //clear cached_properties because they won't be relevant now.
499
-        $this->_clear_cached_properties();
500
-    }
501
-
502
-
503
-
504
-    /**
505
-     * This returns the current internal set format for the date and time formats.
506
-     *
507
-     * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
508
-     *                             where the first value is the date format and the second value is the time format.
509
-     * @return mixed string|array
510
-     */
511
-    public function get_format($full = true)
512
-    {
513
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
514
-    }
515
-
516
-
517
-
518
-    /**
519
-     * cache
520
-     * stores the passed model object on the current model object.
521
-     * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
522
-     *
523
-     * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
524
-     *                                       'Registration' associated with this model object
525
-     * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
526
-     *                                       that could be a payment or a registration)
527
-     * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
528
-     *                                       items which will be stored in an array on this object
529
-     * @throws EE_Error
530
-     * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
531
-     *                  related thing, no array)
532
-     */
533
-    public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
534
-    {
535
-        // its entirely possible that there IS no related object yet in which case there is nothing to cache.
536
-        if ( ! $object_to_cache instanceof EE_Base_Class) {
537
-            return false;
538
-        }
539
-        // also get "how" the object is related, or throw an error
540
-        if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
541
-            throw new EE_Error(sprintf(__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
542
-                $relationName, get_class($this)));
543
-        }
544
-        // how many things are related ?
545
-        if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
546
-            // 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
547
-            // so for these model objects just set it to be cached
548
-            $this->_model_relations[$relationName] = $object_to_cache;
549
-            $return = true;
550
-        } else {
551
-            // 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.
552
-            // eg: if this is an event, there are many registrations for that event, so we cache the registrations in an array
553
-            if ( ! is_array($this->_model_relations[$relationName])) {
554
-                // if for some reason, the cached item is a model object, then stick that in the array, otherwise start with an empty array
555
-                $this->_model_relations[$relationName] = $this->_model_relations[$relationName] instanceof EE_Base_Class
556
-                    ? array($this->_model_relations[$relationName]) : array();
557
-            }
558
-            // first check for a cache_id which is normally empty
559
-            if ( ! empty($cache_id)) {
560
-                // 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
561
-                $this->_model_relations[$relationName][$cache_id] = $object_to_cache;
562
-                $return = $cache_id;
563
-            } elseif ($object_to_cache->ID()) {
564
-                // OR the cached object originally came from the db, so let's just use it's PK for an ID
565
-                $this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
566
-                $return = $object_to_cache->ID();
567
-            } else {
568
-                // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
569
-                $this->_model_relations[$relationName][] = $object_to_cache;
570
-                // move the internal pointer to the end of the array
571
-                end($this->_model_relations[$relationName]);
572
-                // and grab the key so that we can return it
573
-                $return = key($this->_model_relations[$relationName]);
574
-            }
575
-        }
576
-        return $return;
577
-    }
578
-
579
-
580
-
581
-    /**
582
-     * For adding an item to the cached_properties property.
583
-     *
584
-     * @access protected
585
-     * @param string      $fieldname the property item the corresponding value is for.
586
-     * @param mixed       $value     The value we are caching.
587
-     * @param string|null $cache_type
588
-     * @return void
589
-     * @throws EE_Error
590
-     */
591
-    protected function _set_cached_property($fieldname, $value, $cache_type = null)
592
-    {
593
-        //first make sure this property exists
594
-        $this->get_model()->field_settings_for($fieldname);
595
-        $cache_type = empty($cache_type) ? 'standard' : $cache_type;
596
-        $this->_cached_properties[$fieldname][$cache_type] = $value;
597
-    }
598
-
599
-
600
-
601
-    /**
602
-     * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
603
-     * This also SETS the cache if we return the actual property!
604
-     *
605
-     * @param string $fieldname        the name of the property we're trying to retrieve
606
-     * @param bool   $pretty
607
-     * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
608
-     *                                 (in cases where the same property may be used for different outputs
609
-     *                                 - i.e. datetime, money etc.)
610
-     *                                 It can also accept certain pre-defined "schema" strings
611
-     *                                 to define how to output the property.
612
-     *                                 see the field's prepare_for_pretty_echoing for what strings can be used
613
-     * @return mixed                   whatever the value for the property is we're retrieving
614
-     * @throws EE_Error
615
-     */
616
-    protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
617
-    {
618
-        //verify the field exists
619
-        $model = $this->get_model();
620
-        $model->field_settings_for($fieldname);
621
-        $cache_type = $pretty ? 'pretty' : 'standard';
622
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
623
-        if (isset($this->_cached_properties[$fieldname][$cache_type])) {
624
-            return $this->_cached_properties[$fieldname][$cache_type];
625
-        }
626
-        $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
627
-        $this->_set_cached_property($fieldname, $value, $cache_type);
628
-        return $value;
629
-    }
630
-
631
-
632
-    /**
633
-     * If the cache didn't fetch the needed item, this fetches it.
634
-     * @param string $fieldname
635
-     * @param bool $pretty
636
-     * @param string $extra_cache_ref
637
-     * @return mixed
638
-     * @throws EE_Error
639
-     */
640
-    protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
641
-    {
642
-        $field_obj = $this->get_model()->field_settings_for($fieldname);
643
-        // If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
644
-        if ($field_obj instanceof EE_Datetime_Field) {
645
-            $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
646
-        }
647
-        if ( ! isset($this->_fields[$fieldname])) {
648
-            $this->_fields[$fieldname] = null;
649
-        }
650
-        $value = $pretty
651
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
652
-            : $field_obj->prepare_for_get($this->_fields[$fieldname]);
653
-        return $value;
654
-    }
655
-
656
-
657
-    /**
658
-     * set timezone, formats, and output for EE_Datetime_Field objects
659
-     *
660
-     * @param \EE_Datetime_Field $datetime_field
661
-     * @param bool $pretty
662
-     * @param null $date_or_time
663
-     * @return void
664
-     * @throws InvalidArgumentException
665
-     * @throws InvalidInterfaceException
666
-     * @throws InvalidDataTypeException
667
-     * @throws EE_Error
668
-     */
669
-    protected function _prepare_datetime_field(
670
-        EE_Datetime_Field $datetime_field,
671
-        $pretty = false,
672
-        $date_or_time = null
673
-    ) {
674
-        $datetime_field->set_timezone($this->_timezone);
675
-        $datetime_field->set_date_format($this->_dt_frmt, $pretty);
676
-        $datetime_field->set_time_format($this->_tm_frmt, $pretty);
677
-        //set the output returned
678
-        switch ($date_or_time) {
679
-            case 'D' :
680
-                $datetime_field->set_date_time_output('date');
681
-                break;
682
-            case 'T' :
683
-                $datetime_field->set_date_time_output('time');
684
-                break;
685
-            default :
686
-                $datetime_field->set_date_time_output();
687
-        }
688
-    }
689
-
690
-
691
-
692
-    /**
693
-     * This just takes care of clearing out the cached_properties
694
-     *
695
-     * @return void
696
-     */
697
-    protected function _clear_cached_properties()
698
-    {
699
-        $this->_cached_properties = array();
700
-    }
701
-
702
-
703
-
704
-    /**
705
-     * This just clears out ONE property if it exists in the cache
706
-     *
707
-     * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
708
-     * @return void
709
-     */
710
-    protected function _clear_cached_property($property_name)
711
-    {
712
-        if (isset($this->_cached_properties[$property_name])) {
713
-            unset($this->_cached_properties[$property_name]);
714
-        }
715
-    }
716
-
717
-
718
-
719
-    /**
720
-     * Ensures that this related thing is a model object.
721
-     *
722
-     * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
723
-     * @param string $model_name   name of the related thing, eg 'Attendee',
724
-     * @return EE_Base_Class
725
-     * @throws EE_Error
726
-     */
727
-    protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
728
-    {
729
-        $other_model_instance = self::_get_model_instance_with_name(
730
-            self::_get_model_classname($model_name),
731
-            $this->_timezone
732
-        );
733
-        return $other_model_instance->ensure_is_obj($object_or_id);
734
-    }
735
-
736
-
737
-
738
-    /**
739
-     * Forgets the cached model of the given relation Name. So the next time we request it,
740
-     * we will fetch it again from the database. (Handy if you know it's changed somehow).
741
-     * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
742
-     * then only remove that one object from our cached array. Otherwise, clear the entire list
743
-     *
744
-     * @param string $relationName                         one of the keys in the _model_relations array on the model.
745
-     *                                                     Eg 'Registration'
746
-     * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
747
-     *                                                     if you intend to use $clear_all = TRUE, or the relation only
748
-     *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
749
-     * @param bool   $clear_all                            This flags clearing the entire cache relation property if
750
-     *                                                     this is HasMany or HABTM.
751
-     * @throws EE_Error
752
-     * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
753
-     *                       relation from all
754
-     */
755
-    public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
756
-    {
757
-        $relationship_to_model = $this->get_model()->related_settings_for($relationName);
758
-        $index_in_cache = '';
759
-        if ( ! $relationship_to_model) {
760
-            throw new EE_Error(
761
-                sprintf(
762
-                    __("There is no relationship to %s on a %s. Cannot clear that cache", 'event_espresso'),
763
-                    $relationName,
764
-                    get_class($this)
765
-                )
766
-            );
767
-        }
768
-        if ($clear_all) {
769
-            $obj_removed = true;
770
-            $this->_model_relations[$relationName] = null;
771
-        } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
772
-            $obj_removed = $this->_model_relations[$relationName];
773
-            $this->_model_relations[$relationName] = null;
774
-        } else {
775
-            if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
776
-                && $object_to_remove_or_index_into_array->ID()
777
-            ) {
778
-                $index_in_cache = $object_to_remove_or_index_into_array->ID();
779
-                if (is_array($this->_model_relations[$relationName])
780
-                    && ! isset($this->_model_relations[$relationName][$index_in_cache])
781
-                ) {
782
-                    $index_found_at = null;
783
-                    //find this object in the array even though it has a different key
784
-                    foreach ($this->_model_relations[$relationName] as $index => $obj) {
785
-                        if (
786
-                            $obj instanceof EE_Base_Class
787
-                            && (
788
-                                $obj == $object_to_remove_or_index_into_array
789
-                                || $obj->ID() === $object_to_remove_or_index_into_array->ID()
790
-                            )
791
-                        ) {
792
-                            $index_found_at = $index;
793
-                            break;
794
-                        }
795
-                    }
796
-                    if ($index_found_at) {
797
-                        $index_in_cache = $index_found_at;
798
-                    } else {
799
-                        //it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
800
-                        //if it wasn't in it to begin with. So we're done
801
-                        return $object_to_remove_or_index_into_array;
802
-                    }
803
-                }
804
-            } elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
805
-                //so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
806
-                foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
807
-                    if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
808
-                        $index_in_cache = $index;
809
-                    }
810
-                }
811
-            } else {
812
-                $index_in_cache = $object_to_remove_or_index_into_array;
813
-            }
814
-            //supposedly we've found it. But it could just be that the client code
815
-            //provided a bad index/object
816
-            if (
817
-            isset(
818
-                $this->_model_relations[$relationName],
819
-                $this->_model_relations[$relationName][$index_in_cache]
820
-            )
821
-            ) {
822
-                $obj_removed = $this->_model_relations[$relationName][$index_in_cache];
823
-                unset($this->_model_relations[$relationName][$index_in_cache]);
824
-            } else {
825
-                //that thing was never cached anyways.
826
-                $obj_removed = null;
827
-            }
828
-        }
829
-        return $obj_removed;
830
-    }
831
-
832
-
833
-
834
-    /**
835
-     * update_cache_after_object_save
836
-     * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
837
-     * obtained after being saved to the db
838
-     *
839
-     * @param string         $relationName       - the type of object that is cached
840
-     * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
841
-     * @param string         $current_cache_id   - the ID that was used when originally caching the object
842
-     * @return boolean TRUE on success, FALSE on fail
843
-     * @throws EE_Error
844
-     */
845
-    public function update_cache_after_object_save(
846
-        $relationName,
847
-        EE_Base_Class $newly_saved_object,
848
-        $current_cache_id = ''
849
-    ) {
850
-        // verify that incoming object is of the correct type
851
-        $obj_class = 'EE_' . $relationName;
852
-        if ($newly_saved_object instanceof $obj_class) {
853
-            /* @type EE_Base_Class $newly_saved_object */
854
-            // now get the type of relation
855
-            $relationship_to_model = $this->get_model()->related_settings_for($relationName);
856
-            // if this is a 1:1 relationship
857
-            if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
858
-                // then just replace the cached object with the newly saved object
859
-                $this->_model_relations[$relationName] = $newly_saved_object;
860
-                return true;
861
-                // or if it's some kind of sordid feral polyamorous relationship...
862
-            } elseif (is_array($this->_model_relations[$relationName])
863
-                      && isset($this->_model_relations[$relationName][$current_cache_id])
864
-            ) {
865
-                // then remove the current cached item
866
-                unset($this->_model_relations[$relationName][$current_cache_id]);
867
-                // and cache the newly saved object using it's new ID
868
-                $this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
869
-                return true;
870
-            }
871
-        }
872
-        return false;
873
-    }
874
-
875
-
876
-
877
-    /**
878
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
879
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
880
-     *
881
-     * @param string $relationName
882
-     * @return EE_Base_Class
883
-     */
884
-    public function get_one_from_cache($relationName)
885
-    {
886
-        $cached_array_or_object = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName]
887
-            : null;
888
-        if (is_array($cached_array_or_object)) {
889
-            return array_shift($cached_array_or_object);
890
-        } else {
891
-            return $cached_array_or_object;
892
-        }
893
-    }
894
-
895
-
896
-    /**
897
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
898
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
899
-     *
900
-     * @param string $relationName
901
-     * @throws \ReflectionException
902
-     * @throws InvalidArgumentException
903
-     * @throws InvalidInterfaceException
904
-     * @throws InvalidDataTypeException
905
-     * @throws EE_Error
906
-     * @return EE_Base_Class[] NOT necessarily indexed by primary keys
907
-     */
908
-    public function get_all_from_cache($relationName)
909
-    {
910
-        $objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
911
-        // if the result is not an array, but exists, make it an array
912
-        $objects = is_array($objects) ? $objects : array($objects);
913
-        //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
914
-        //basically, if this model object was stored in the session, and these cached model objects
915
-        //already have IDs, let's make sure they're in their model's entity mapper
916
-        //otherwise we will have duplicates next time we call
917
-        // EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
918
-        $model = EE_Registry::instance()->load_model($relationName);
919
-        foreach ($objects as $model_object) {
920
-            if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
921
-                //ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
922
-                if ($model_object->ID()) {
923
-                    $model->add_to_entity_map($model_object);
924
-                }
925
-            } else {
926
-                throw new EE_Error(
927
-                    sprintf(
928
-                        __(
929
-                            'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
930
-                            'event_espresso'
931
-                        ),
932
-                        $relationName,
933
-                        gettype($model_object)
934
-                    )
935
-                );
936
-            }
937
-        }
938
-        return $objects;
939
-    }
940
-
941
-
942
-
943
-    /**
944
-     * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
945
-     * matching the given query conditions.
946
-     *
947
-     * @param null  $field_to_order_by  What field is being used as the reference point.
948
-     * @param int   $limit              How many objects to return.
949
-     * @param array $query_params       Any additional conditions on the query.
950
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
951
-     *                                  you can indicate just the columns you want returned
952
-     * @return array|EE_Base_Class[]
953
-     * @throws EE_Error
954
-     */
955
-    public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
956
-    {
957
-        $model = $this->get_model();
958
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
959
-            ? $model->get_primary_key_field()->get_name()
960
-            : $field_to_order_by;
961
-        $current_value = ! empty($field) ? $this->get($field) : null;
962
-        if (empty($field) || empty($current_value)) {
963
-            return array();
964
-        }
965
-        return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
966
-    }
967
-
968
-
969
-
970
-    /**
971
-     * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
972
-     * matching the given query conditions.
973
-     *
974
-     * @param null  $field_to_order_by  What field is being used as the reference point.
975
-     * @param int   $limit              How many objects to return.
976
-     * @param array $query_params       Any additional conditions on the query.
977
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
978
-     *                                  you can indicate just the columns you want returned
979
-     * @return array|EE_Base_Class[]
980
-     * @throws EE_Error
981
-     */
982
-    public function previous_x(
983
-        $field_to_order_by = null,
984
-        $limit = 1,
985
-        $query_params = array(),
986
-        $columns_to_select = null
987
-    ) {
988
-        $model = $this->get_model();
989
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
990
-            ? $model->get_primary_key_field()->get_name()
991
-            : $field_to_order_by;
992
-        $current_value = ! empty($field) ? $this->get($field) : null;
993
-        if (empty($field) || empty($current_value)) {
994
-            return array();
995
-        }
996
-        return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
997
-    }
998
-
999
-
1000
-
1001
-    /**
1002
-     * Returns the next EE_Base_Class object in sequence from this object as found in the database
1003
-     * matching the given query conditions.
1004
-     *
1005
-     * @param null  $field_to_order_by  What field is being used as the reference point.
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
1008
-     *                                  you can indicate just the columns you want returned
1009
-     * @return array|EE_Base_Class
1010
-     * @throws EE_Error
1011
-     */
1012
-    public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1013
-    {
1014
-        $model = $this->get_model();
1015
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
1016
-            ? $model->get_primary_key_field()->get_name()
1017
-            : $field_to_order_by;
1018
-        $current_value = ! empty($field) ? $this->get($field) : null;
1019
-        if (empty($field) || empty($current_value)) {
1020
-            return array();
1021
-        }
1022
-        return $model->next($current_value, $field, $query_params, $columns_to_select);
1023
-    }
1024
-
1025
-
1026
-
1027
-    /**
1028
-     * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1029
-     * matching the given query conditions.
1030
-     *
1031
-     * @param null  $field_to_order_by  What field is being used as the reference point.
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
1034
-     *                                  you can indicate just the column you want returned
1035
-     * @return array|EE_Base_Class
1036
-     * @throws EE_Error
1037
-     */
1038
-    public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1039
-    {
1040
-        $model = $this->get_model();
1041
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
1042
-            ? $model->get_primary_key_field()->get_name()
1043
-            : $field_to_order_by;
1044
-        $current_value = ! empty($field) ? $this->get($field) : null;
1045
-        if (empty($field) || empty($current_value)) {
1046
-            return array();
1047
-        }
1048
-        return $model->previous($current_value, $field, $query_params, $columns_to_select);
1049
-    }
1050
-
1051
-
1052
-
1053
-    /**
1054
-     * Overrides parent because parent expects old models.
1055
-     * This also doesn't do any validation, and won't work for serialized arrays
1056
-     *
1057
-     * @param string $field_name
1058
-     * @param mixed  $field_value_from_db
1059
-     * @throws EE_Error
1060
-     */
1061
-    public function set_from_db($field_name, $field_value_from_db)
1062
-    {
1063
-        $field_obj = $this->get_model()->field_settings_for($field_name);
1064
-        if ($field_obj instanceof EE_Model_Field_Base) {
1065
-            //you would think the DB has no NULLs for non-null label fields right? wrong!
1066
-            //eg, a CPT model object could have an entry in the posts table, but no
1067
-            //entry in the meta table. Meaning that all its columns in the meta table
1068
-            //are null! yikes! so when we find one like that, use defaults for its meta columns
1069
-            if ($field_value_from_db === null) {
1070
-                if ($field_obj->is_nullable()) {
1071
-                    //if the field allows nulls, then let it be null
1072
-                    $field_value = null;
1073
-                } else {
1074
-                    $field_value = $field_obj->get_default_value();
1075
-                }
1076
-            } else {
1077
-                $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1078
-            }
1079
-            $this->_fields[$field_name] = $field_value;
1080
-            $this->_clear_cached_property($field_name);
1081
-        }
1082
-    }
1083
-
1084
-
1085
-
1086
-    /**
1087
-     * verifies that the specified field is of the correct type
1088
-     *
1089
-     * @param string $field_name
1090
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1091
-     *                                (in cases where the same property may be used for different outputs
1092
-     *                                - i.e. datetime, money etc.)
1093
-     * @return mixed
1094
-     * @throws EE_Error
1095
-     */
1096
-    public function get($field_name, $extra_cache_ref = null)
1097
-    {
1098
-        return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1099
-    }
1100
-
1101
-
1102
-
1103
-    /**
1104
-     * This method simply returns the RAW unprocessed value for the given property in this class
1105
-     *
1106
-     * @param  string $field_name A valid fieldname
1107
-     * @return mixed              Whatever the raw value stored on the property is.
1108
-     * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1109
-     */
1110
-    public function get_raw($field_name)
1111
-    {
1112
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1113
-        switch(true){
1114
-            case $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime:
1115
-                $value = $this->_fields[$field_name]->format('U');
1116
-                break;
1117
-            case $field_settings instanceof EE_Money_Field && $this->_fields[$field_name] instanceof Money:
1118
-                $value = $this->_fields[$field_name]->floatAmount();
1119
-                break;
1120
-            default:
1121
-                $value = $this->_fields[$field_name];
1122
-        }
1123
-        return $value;
1124
-    }
1125
-
1126
-
1127
-
1128
-    /**
1129
-     * This is used to return the internal DateTime object used for a field that is a
1130
-     * EE_Datetime_Field.
1131
-     *
1132
-     * @param string $field_name               The field name retrieving the DateTime object.
1133
-     * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1134
-     * @throws EE_Error
1135
-     *                                         an error is set and false returned.  If the field IS an
1136
-     *                                         EE_Datetime_Field and but the field value is null, then
1137
-     *                                         just null is returned (because that indicates that likely
1138
-     *                                         this field is nullable).
1139
-     */
1140
-    public function get_DateTime_object($field_name)
1141
-    {
1142
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1143
-        if ( ! $field_settings instanceof EE_Datetime_Field) {
1144
-            EE_Error::add_error(
1145
-                sprintf(
1146
-                    __(
1147
-                        'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1148
-                        'event_espresso'
1149
-                    ),
1150
-                    $field_name
1151
-                ),
1152
-                __FILE__,
1153
-                __FUNCTION__,
1154
-                __LINE__
1155
-            );
1156
-            return false;
1157
-        }
1158
-        return $this->_fields[$field_name];
1159
-    }
1160
-
1161
-
1162
-
1163
-    /**
1164
-     * Gets a Money object for the specified field. Please note that this should only be
1165
-     * used for fields corresponding to EE_Money_Fields, and it will always return a money object,
1166
-     * or else it will throw an exception.
1167
-     *
1168
-     * @param $field_name
1169
-     * @return Money
1170
-     * @throws InvalidEntityException
1171
-     * @throws EE_Error
1172
-     */
1173
-    public function getMoneyObject($field_name)
1174
-    {
1175
-        $field = $this->get_model()->field_settings_for($field_name);
1176
-        $value = isset($this->_fields[$field_name]) ? $this->_fields[$field_name] : null;
1177
-        if (! $field instanceof EE_Money_Field
1178
-            || ! $value instanceof Money) {
1179
-            throw new InvalidEntityException(
1180
-                get_class($value),
1181
-                'Money',
1182
-                sprintf(
1183
-                    esc_html__(
1184
-                        // @codingStandardsIgnoreStart
1185
-                        'Tried to retrieve money value from %1$s with ID %2$s from field %3$s but no money object present.',
1186
-                        // @codingStandardsIgnoreEnd
1187
-                        'event_espresso'
1188
-                    ),
1189
-                    get_class($this),
1190
-                    $this->ID(),
1191
-                    $field_name
1192
-                )
1193
-            );
1194
-        }
1195
-        return $value;
1196
-    }
1197
-
1198
-
1199
-
1200
-    /**
1201
-     * To be used in template to immediately echo out the value, and format it for output.
1202
-     * Eg, should call stripslashes and whatnot before echoing
1203
-     *
1204
-     * @param string $field_name      the name of the field as it appears in the DB
1205
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1206
-     *                                (in cases where the same property may be used for different outputs
1207
-     *                                - i.e. datetime, money etc.)
1208
-     * @return void
1209
-     * @throws EE_Error
1210
-     */
1211
-    public function e($field_name, $extra_cache_ref = null)
1212
-    {
1213
-        echo $this->get_pretty($field_name, $extra_cache_ref);
1214
-    }
1215
-
1216
-
1217
-
1218
-    /**
1219
-     * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1220
-     * can be easily used as the value of form input.
1221
-     *
1222
-     * @param string $field_name
1223
-     * @return void
1224
-     * @throws EE_Error
1225
-     */
1226
-    public function f($field_name)
1227
-    {
1228
-        $this->e($field_name, 'form_input');
1229
-    }
1230
-
1231
-    /**
1232
-     * Same as `f()` but just returns the value instead of echoing it
1233
-     * @param string $field_name
1234
-     * @return string
1235
-     * @throws EE_Error
1236
-     */
1237
-    public function get_f($field_name)
1238
-    {
1239
-        return (string)$this->get_pretty($field_name,'form_input');
1240
-    }
1241
-
1242
-
1243
-
1244
-    /**
1245
-     * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1246
-     * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1247
-     * to see what options are available.
1248
-     * @param string $field_name
1249
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1250
-     *                                (in cases where the same property may be used for different outputs
1251
-     *                                - i.e. datetime, money etc.)
1252
-     * @return mixed
1253
-     * @throws EE_Error
1254
-     */
1255
-    public function get_pretty($field_name, $extra_cache_ref = null)
1256
-    {
1257
-        return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1258
-    }
1259
-
1260
-
1261
-
1262
-    /**
1263
-     * This simply returns the datetime for the given field name
1264
-     * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1265
-     * (and the equivalent e_date, e_time, e_datetime).
1266
-     *
1267
-     * @access   protected
1268
-     * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1269
-     * @param string   $dt_frmt      valid datetime format used for date
1270
-     *                               (if '' then we just use the default on the field,
1271
-     *                               if NULL we use the last-used format)
1272
-     * @param string   $tm_frmt      Same as above except this is for time format
1273
-     * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1274
-     * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1275
-     * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1276
-     *                               if field is not a valid dtt field, or void if echoing
1277
-     * @throws EE_Error
1278
-     */
1279
-    protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1280
-    {
1281
-        // clear cached property
1282
-        $this->_clear_cached_property($field_name);
1283
-        //reset format properties because they are used in get()
1284
-        $this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1285
-        $this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1286
-        if ($echo) {
1287
-            $this->e($field_name, $date_or_time);
1288
-            return '';
1289
-        }
1290
-        return $this->get($field_name, $date_or_time);
1291
-    }
1292
-
1293
-
1294
-
1295
-    /**
1296
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1297
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1298
-     * other echoes the pretty value for dtt)
1299
-     *
1300
-     * @param  string $field_name name of model object datetime field holding the value
1301
-     * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1302
-     * @return string            datetime value formatted
1303
-     * @throws EE_Error
1304
-     */
1305
-    public function get_date($field_name, $format = '')
1306
-    {
1307
-        return $this->_get_datetime($field_name, $format, null, 'D');
1308
-    }
1309
-
1310
-
1311
-
1312
-    /**
1313
-     * @param      $field_name
1314
-     * @param string $format
1315
-     * @throws EE_Error
1316
-     */
1317
-    public function e_date($field_name, $format = '')
1318
-    {
1319
-        $this->_get_datetime($field_name, $format, null, 'D', true);
1320
-    }
1321
-
1322
-
1323
-
1324
-    /**
1325
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1326
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1327
-     * other echoes the pretty value for dtt)
1328
-     *
1329
-     * @param  string $field_name name of model object datetime field holding the value
1330
-     * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1331
-     * @return string             datetime value formatted
1332
-     * @throws EE_Error
1333
-     */
1334
-    public function get_time($field_name, $format = '')
1335
-    {
1336
-        return $this->_get_datetime($field_name, null, $format, 'T');
1337
-    }
1338
-
1339
-
1340
-
1341
-    /**
1342
-     * @param      $field_name
1343
-     * @param string $format
1344
-     * @throws EE_Error
1345
-     */
1346
-    public function e_time($field_name, $format = '')
1347
-    {
1348
-        $this->_get_datetime($field_name, null, $format, 'T', true);
1349
-    }
1350
-
1351
-
1352
-
1353
-    /**
1354
-     * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1355
-     * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1356
-     * other echoes the pretty value for dtt)
1357
-     *
1358
-     * @param  string $field_name name of model object datetime field holding the value
1359
-     * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1360
-     * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1361
-     * @return string             datetime value formatted
1362
-     * @throws EE_Error
1363
-     */
1364
-    public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1365
-    {
1366
-        return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1367
-    }
1368
-
1369
-
1370
-
1371
-    /**
1372
-     * @param string $field_name
1373
-     * @param string $dt_frmt
1374
-     * @param string $tm_frmt
1375
-     * @throws EE_Error
1376
-     */
1377
-    public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1378
-    {
1379
-        $this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1380
-    }
1381
-
1382
-
1383
-    /**
1384
-     * Get the i8ln value for a date using the WordPress @see date_i18n function.
1385
-     *
1386
-     * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1387
-     * @param string $format PHP valid date/time string format.  If none is provided then the internal set format
1388
-     *                           on the object will be used.
1389
-     * @return string Date and time string in set locale or false if no field exists for the given
1390
-     * @throws InvalidArgumentException
1391
-     * @throws InvalidInterfaceException
1392
-     * @throws InvalidDataTypeException
1393
-     * @throws EE_Error
1394
-     *                           field name.
1395
-     */
1396
-    public function get_i18n_datetime($field_name, $format = '')
1397
-    {
1398
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1399
-        return date_i18n(
1400
-            $format,
1401
-            EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
1402
-        );
1403
-    }
1404
-
1405
-
1406
-
1407
-    /**
1408
-     * This method validates whether the given field name is a valid field on the model object as well as it is of a
1409
-     * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1410
-     * thrown.
1411
-     *
1412
-     * @param  string $field_name The field name being checked
1413
-     * @throws EE_Error
1414
-     * @return EE_Datetime_Field
1415
-     */
1416
-    protected function _get_dtt_field_settings($field_name)
1417
-    {
1418
-        $field = $this->get_model()->field_settings_for($field_name);
1419
-        //check if field is dtt
1420
-        if ($field instanceof EE_Datetime_Field) {
1421
-            return $field;
1422
-        } else {
1423
-            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',
1424
-                'event_espresso'), $field_name, self::_get_model_classname(get_class($this))));
1425
-        }
1426
-    }
1427
-
1428
-
1429
-
1430
-
1431
-    /**
1432
-     * NOTE ABOUT BELOW:
1433
-     * These convenience date and time setters are for setting date and time independently.  In other words you might
1434
-     * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1435
-     * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1436
-     * method and make sure you send the entire datetime value for setting.
1437
-     */
1438
-    /**
1439
-     * sets the time on a datetime property
1440
-     *
1441
-     * @access protected
1442
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1443
-     * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1444
-     * @throws EE_Error
1445
-     */
1446
-    protected function _set_time_for($time, $fieldname)
1447
-    {
1448
-        $this->_set_date_time('T', $time, $fieldname);
1449
-    }
1450
-
1451
-
1452
-
1453
-    /**
1454
-     * sets the date on a datetime property
1455
-     *
1456
-     * @access protected
1457
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1458
-     * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1459
-     * @throws EE_Error
1460
-     */
1461
-    protected function _set_date_for($date, $fieldname)
1462
-    {
1463
-        $this->_set_date_time('D', $date, $fieldname);
1464
-    }
1465
-
1466
-
1467
-    /**
1468
-     * This takes care of setting a date or time independently on a given model object property. This method also
1469
-     * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1470
-     *
1471
-     * @access protected
1472
-     * @param string $what "T" for time, 'B' for both, 'D' for Date.
1473
-     * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1474
-     * @param string $fieldname the name of the field the date OR time is being set on (must match a
1475
-     *                                        EE_Datetime_Field property)
1476
-     * @throws InvalidArgumentException
1477
-     * @throws InvalidInterfaceException
1478
-     * @throws InvalidDataTypeException
1479
-     * @throws EE_Error
1480
-     */
1481
-    protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1482
-    {
1483
-        $field = $this->_get_dtt_field_settings($fieldname);
1484
-        $field->set_timezone($this->_timezone);
1485
-        $field->set_date_format($this->_dt_frmt);
1486
-        $field->set_time_format($this->_tm_frmt);
1487
-        switch ($what) {
1488
-            case 'T' :
1489
-                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1490
-                    $datetime_value,
1491
-                    $this->_fields[$fieldname]
1492
-                );
1493
-                break;
1494
-            case 'D' :
1495
-                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1496
-                    $datetime_value,
1497
-                    $this->_fields[$fieldname]
1498
-                );
1499
-                break;
1500
-            case 'B' :
1501
-                $this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1502
-                break;
1503
-        }
1504
-        $this->_clear_cached_property($fieldname);
1505
-    }
1506
-
1507
-
1508
-    /**
1509
-     * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1510
-     * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1511
-     * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1512
-     * that could lead to some unexpected results!
1513
-     *
1514
-     * @access public
1515
-     * @param string $field_name This is the name of the field on the object that contains the date/time
1516
-     *                                         value being returned.
1517
-     * @param string $callback must match a valid method in this class (defaults to get_datetime)
1518
-     * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1519
-     * @param string $prepend You can include something to prepend on the timestamp
1520
-     * @param string $append You can include something to append on the timestamp
1521
-     * @throws InvalidArgumentException
1522
-     * @throws InvalidInterfaceException
1523
-     * @throws InvalidDataTypeException
1524
-     * @throws EE_Error
1525
-     * @return string timestamp
1526
-     */
1527
-    public function display_in_my_timezone(
1528
-        $field_name,
1529
-        $callback = 'get_datetime',
1530
-        $args = null,
1531
-        $prepend = '',
1532
-        $append = ''
1533
-    ) {
1534
-        $timezone = EEH_DTT_Helper::get_timezone();
1535
-        if ($timezone === $this->_timezone) {
1536
-            return '';
1537
-        }
1538
-        $original_timezone = $this->_timezone;
1539
-        $this->set_timezone($timezone);
1540
-        $fn = (array)$field_name;
1541
-        $args = array_merge($fn, (array)$args);
1542
-        if ( ! method_exists($this, $callback)) {
1543
-            throw new EE_Error(
1544
-                sprintf(
1545
-                    __(
1546
-                        'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1547
-                        'event_espresso'
1548
-                    ),
1549
-                    $callback
1550
-                )
1551
-            );
1552
-        }
1553
-        $args = (array)$args;
1554
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1555
-        $this->set_timezone($original_timezone);
1556
-        return $return;
1557
-    }
1558
-
1559
-
1560
-
1561
-    /**
1562
-     * Deletes this model object.
1563
-     * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1564
-     * override
1565
-     * `EE_Base_Class::_delete` NOT this class.
1566
-     *
1567
-     * @return boolean | int
1568
-     * @throws EE_Error
1569
-     */
1570
-    public function delete()
1571
-    {
1572
-        /**
1573
-         * Called just before the `EE_Base_Class::_delete` method call.
1574
-         * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1575
-         * should be aware that `_delete` may not always result in a permanent delete.  For example, `EE_Soft_Delete_Base_Class::_delete`
1576
-         * soft deletes (trash) the object and does not permanently delete it.
1577
-         *
1578
-         * @param EE_Base_Class $model_object about to be 'deleted'
1579
-         */
1580
-        do_action('AHEE__EE_Base_Class__delete__before', $this);
1581
-        $result = $this->_delete();
1582
-        /**
1583
-         * Called just after the `EE_Base_Class::_delete` method call.
1584
-         * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1585
-         * should be aware that `_delete` may not always result in a permanent delete.  For example `EE_Soft_Base_Class::_delete`
1586
-         * soft deletes (trash) the object and does not permanently delete it.
1587
-         *
1588
-         * @param EE_Base_Class $model_object that was just 'deleted'
1589
-         * @param boolean       $result
1590
-         */
1591
-        do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1592
-        return $result;
1593
-    }
1594
-
1595
-
1596
-
1597
-    /**
1598
-     * Calls the specific delete method for the instantiated class.
1599
-     * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1600
-     * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1601
-     * `EE_Base_Class::delete`
1602
-     *
1603
-     * @return bool|int
1604
-     * @throws EE_Error
1605
-     */
1606
-    protected function _delete()
1607
-    {
1608
-        return $this->delete_permanently();
1609
-    }
1610
-
1611
-
1612
-
1613
-    /**
1614
-     * Deletes this model object permanently from db (but keep in mind related models my block the delete and return an
1615
-     * error)
1616
-     *
1617
-     * @return bool | int
1618
-     * @throws EE_Error
1619
-     */
1620
-    public function delete_permanently()
1621
-    {
1622
-        /**
1623
-         * Called just before HARD deleting a model object
1624
-         *
1625
-         * @param EE_Base_Class $model_object about to be 'deleted'
1626
-         */
1627
-        do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1628
-        $model = $this->get_model();
1629
-        $result = $model->delete_permanently_by_ID($this->ID());
1630
-        $this->refresh_cache_of_related_objects();
1631
-        /**
1632
-         * Called just after HARD deleting a model object
1633
-         *
1634
-         * @param EE_Base_Class $model_object that was just 'deleted'
1635
-         * @param boolean       $result
1636
-         */
1637
-        do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1638
-        return $result;
1639
-    }
1640
-
1641
-
1642
-
1643
-    /**
1644
-     * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1645
-     * related model objects
1646
-     *
1647
-     * @throws EE_Error
1648
-     */
1649
-    public function refresh_cache_of_related_objects()
1650
-    {
1651
-        $model = $this->get_model();
1652
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1653
-            if ( ! empty($this->_model_relations[$relation_name])) {
1654
-                $related_objects = $this->_model_relations[$relation_name];
1655
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
1656
-                    //this relation only stores a single model object, not an array
1657
-                    //but let's make it consistent
1658
-                    $related_objects = array($related_objects);
1659
-                }
1660
-                foreach ($related_objects as $related_object) {
1661
-                    //only refresh their cache if they're in memory
1662
-                    if ($related_object instanceof EE_Base_Class) {
1663
-                        $related_object->clear_cache($model->get_this_model_name(), $this);
1664
-                    }
1665
-                }
1666
-            }
1667
-        }
1668
-    }
1669
-
1670
-
1671
-
1672
-    /**
1673
-     *        Saves this object to the database. An array may be supplied to set some values on this
1674
-     * object just before saving.
1675
-     *
1676
-     * @access public
1677
-     * @param array $set_cols_n_values keys are field names, values are their new values,
1678
-     *                                 if provided during the save() method (often client code will change the fields'
1679
-     *                                 values before calling save)
1680
-     * @throws EE_Error
1681
-     * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1682
-     *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1683
-     */
1684
-    public function save($set_cols_n_values = array())
1685
-    {
1686
-        $model = $this->get_model();
1687
-        /**
1688
-         * Filters the fields we're about to save on the model object
1689
-         *
1690
-         * @param array         $set_cols_n_values
1691
-         * @param EE_Base_Class $model_object
1692
-         */
1693
-        $set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1694
-            $this);
1695
-        //set attributes as provided in $set_cols_n_values
1696
-        foreach ($set_cols_n_values as $column => $value) {
1697
-            $this->set($column, $value);
1698
-        }
1699
-        // no changes ? then don't do anything
1700
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1701
-            return 0;
1702
-        }
1703
-        /**
1704
-         * Saving a model object.
1705
-         * Before we perform a save, this action is fired.
1706
-         *
1707
-         * @param EE_Base_Class $model_object the model object about to be saved.
1708
-         */
1709
-        do_action('AHEE__EE_Base_Class__save__begin', $this);
1710
-        if ( ! $this->allow_persist()) {
1711
-            return 0;
1712
-        }
1713
-        //now get current attribute values
1714
-        $save_cols_n_values = $this->_fields;
1715
-        //if the object already has an ID, update it. Otherwise, insert it
1716
-        //also: change the assumption about values passed to the model NOT being prepare dby the model object. They have been
1717
-        $old_assumption_concerning_value_preparation = $model
1718
-                                                            ->get_assumption_concerning_values_already_prepared_by_model_object();
1719
-        $model->assume_values_already_prepared_by_model_object(true);
1720
-        //does this model have an autoincrement PK?
1721
-        if ($model->has_primary_key_field()) {
1722
-            if ($model->get_primary_key_field()->is_auto_increment()) {
1723
-                //ok check if it's set, if so: update; if not, insert
1724
-                if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1725
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1726
-                } else {
1727
-                    unset($save_cols_n_values[$model->primary_key_name()]);
1728
-                    $results = $model->insert($save_cols_n_values);
1729
-                    if ($results) {
1730
-                        //if successful, set the primary key
1731
-                        //but don't use the normal SET method, because it will check if
1732
-                        //an item with the same ID exists in the mapper & db, then
1733
-                        //will find it in the db (because we just added it) and THAT object
1734
-                        //will get added to the mapper before we can add this one!
1735
-                        //but if we just avoid using the SET method, all that headache can be avoided
1736
-                        $pk_field_name = $model->primary_key_name();
1737
-                        $this->_fields[$pk_field_name] = $results;
1738
-                        $this->_clear_cached_property($pk_field_name);
1739
-                        $model->add_to_entity_map($this);
1740
-                        $this->_update_cached_related_model_objs_fks();
1741
-                    }
1742
-                }
1743
-            } else {//PK is NOT auto-increment
1744
-                //so check if one like it already exists in the db
1745
-                if ($model->exists_by_ID($this->ID())) {
1746
-                    if (WP_DEBUG && ! $this->in_entity_map()) {
1747
-                        throw new EE_Error(
1748
-                            sprintf(
1749
-                                __('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',
1750
-                                    'event_espresso'),
1751
-                                get_class($this),
1752
-                                get_class($model) . '::instance()->add_to_entity_map()',
1753
-                                get_class($model) . '::instance()->get_one_by_ID()',
1754
-                                '<br />'
1755
-                            )
1756
-                        );
1757
-                    }
1758
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1759
-                } else {
1760
-                    $results = $model->insert($save_cols_n_values);
1761
-                    $this->_update_cached_related_model_objs_fks();
1762
-                }
1763
-            }
1764
-        } else {//there is NO primary key
1765
-            $already_in_db = false;
1766
-            foreach ($model->unique_indexes() as $index) {
1767
-                $uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1768
-                if ($model->exists(array($uniqueness_where_params))) {
1769
-                    $already_in_db = true;
1770
-                }
1771
-            }
1772
-            if ($already_in_db) {
1773
-                $combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1774
-                    $model->get_combined_primary_key_fields());
1775
-                $results = $model->update($save_cols_n_values, $combined_pk_fields_n_values);
1776
-            } else {
1777
-                $results = $model->insert($save_cols_n_values);
1778
-            }
1779
-        }
1780
-        //restore the old assumption about values being prepared by the model object
1781
-        $model
1782
-             ->assume_values_already_prepared_by_model_object($old_assumption_concerning_value_preparation);
1783
-        /**
1784
-         * After saving the model object this action is called
1785
-         *
1786
-         * @param EE_Base_Class $model_object which was just saved
1787
-         * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1788
-         *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1789
-         */
1790
-        do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1791
-        $this->_has_changes = false;
1792
-        return $results;
1793
-    }
1794
-
1795
-
1796
-
1797
-    /**
1798
-     * Updates the foreign key on related models objects pointing to this to have this model object's ID
1799
-     * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1800
-     * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1801
-     * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1802
-     * 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
1803
-     * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1804
-     * or not they exist in the DB (if they do, their DB records will be automatically updated)
1805
-     *
1806
-     * @return void
1807
-     * @throws EE_Error
1808
-     */
1809
-    protected function _update_cached_related_model_objs_fks()
1810
-    {
1811
-        $model = $this->get_model();
1812
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1813
-            if ($relation_obj instanceof EE_Has_Many_Relation) {
1814
-                foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1815
-                    $fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1816
-                        $model->get_this_model_name()
1817
-                    );
1818
-                    $related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1819
-                    if ($related_model_obj_in_cache->ID()) {
1820
-                        $related_model_obj_in_cache->save();
1821
-                    }
1822
-                }
1823
-            }
1824
-        }
1825
-    }
1826
-
1827
-
1828
-
1829
-    /**
1830
-     * Saves this model object and its NEW cached relations to the database.
1831
-     * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1832
-     * In order for that to work, we would need to mark model objects as dirty/clean...
1833
-     * because otherwise, there's a potential for infinite looping of saving
1834
-     * Saves the cached related model objects, and ensures the relation between them
1835
-     * and this object and properly setup
1836
-     *
1837
-     * @return int ID of new model object on save; 0 on failure+
1838
-     * @throws EE_Error
1839
-     */
1840
-    public function save_new_cached_related_model_objs()
1841
-    {
1842
-        //make sure this has been saved
1843
-        if ( ! $this->ID()) {
1844
-            $id = $this->save();
1845
-        } else {
1846
-            $id = $this->ID();
1847
-        }
1848
-        //now save all the NEW cached model objects  (ie they don't exist in the DB)
1849
-        foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1850
-            if ($this->_model_relations[$relationName]) {
1851
-                //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1852
-                //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1853
-                if ($relationObj instanceof EE_Belongs_To_Relation) {
1854
-                    //add a relation to that relation type (which saves the appropriate thing in the process)
1855
-                    //but ONLY if it DOES NOT exist in the DB
1856
-                    /* @var $related_model_obj EE_Base_Class */
1857
-                    $related_model_obj = $this->_model_relations[$relationName];
1858
-                    //					if( ! $related_model_obj->ID()){
1859
-                    $this->_add_relation_to($related_model_obj, $relationName);
1860
-                    $related_model_obj->save_new_cached_related_model_objs();
1861
-                    //					}
1862
-                } else {
1863
-                    foreach ($this->_model_relations[$relationName] as $related_model_obj) {
1864
-                        //add a relation to that relation type (which saves the appropriate thing in the process)
1865
-                        //but ONLY if it DOES NOT exist in the DB
1866
-                        //						if( ! $related_model_obj->ID()){
1867
-                        $this->_add_relation_to($related_model_obj, $relationName);
1868
-                        $related_model_obj->save_new_cached_related_model_objs();
1869
-                        //						}
1870
-                    }
1871
-                }
1872
-            }
1873
-        }
1874
-        return $id;
1875
-    }
1876
-
1877
-
1878
-
1879
-    /**
1880
-     * for getting a model while instantiated.
1881
-     *
1882
-     * @return EEM_Base | EEM_CPT_Base
1883
-     */
1884
-    public function get_model()
1885
-    {
1886
-        if( ! $this->_model){
1887
-            $modelName = self::_get_model_classname(get_class($this));
1888
-            $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1889
-        } else {
1890
-            $this->_model->set_timezone($this->_timezone);
1891
-        }
1892
-
1893
-        return $this->_model;
1894
-    }
1895
-
1896
-
1897
-
1898
-    /**
1899
-     * @param $props_n_values
1900
-     * @param $classname
1901
-     * @return mixed bool|EE_Base_Class|EEM_CPT_Base
1902
-     * @throws EE_Error
1903
-     */
1904
-    protected static function _get_object_from_entity_mapper($props_n_values, $classname)
1905
-    {
1906
-        //TODO: will not work for Term_Relationships because they have no PK!
1907
-        $primary_id_ref = self::_get_primary_key_name($classname);
1908
-        if (array_key_exists($primary_id_ref, $props_n_values) && ! empty($props_n_values[$primary_id_ref])) {
1909
-            $id = $props_n_values[$primary_id_ref];
1910
-            return self::_get_model($classname)->get_from_entity_map($id);
1911
-        }
1912
-        return false;
1913
-    }
1914
-
1915
-
1916
-
1917
-    /**
1918
-     * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
1919
-     * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
1920
-     * 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
1921
-     * we return false.
1922
-     *
1923
-     * @param  array  $props_n_values   incoming array of properties and their values
1924
-     * @param  string $classname        the classname of the child class
1925
-     * @param null    $timezone
1926
-     * @param array   $date_formats     incoming date_formats in an array where the first value is the
1927
-     *                                  date_format and the second value is the time format
1928
-     * @return mixed (EE_Base_Class|bool)
1929
-     * @throws EE_Error
1930
-     */
1931
-    protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
1932
-    {
1933
-        $existing = null;
1934
-        $model = self::_get_model($classname, $timezone);
1935
-        if ($model->has_primary_key_field()) {
1936
-            $primary_id_ref = self::_get_primary_key_name($classname);
1937
-            if (array_key_exists($primary_id_ref, $props_n_values)
1938
-                && ! empty($props_n_values[$primary_id_ref])
1939
-            ) {
1940
-                $existing = $model->get_one_by_ID(
1941
-                    $props_n_values[$primary_id_ref]
1942
-                );
1943
-            }
1944
-        } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
1945
-            //no primary key on this model, but there's still a matching item in the DB
1946
-            $existing = self::_get_model($classname, $timezone)->get_one_by_ID(
1947
-                self::_get_model($classname, $timezone)->get_index_primary_key_string($props_n_values)
1948
-            );
1949
-        }
1950
-        if ($existing) {
1951
-            //set date formats if present before setting values
1952
-            if ( ! empty($date_formats) && is_array($date_formats)) {
1953
-                $existing->set_date_format($date_formats[0]);
1954
-                $existing->set_time_format($date_formats[1]);
1955
-            } else {
1956
-                //set default formats for date and time
1957
-                $existing->set_date_format(get_option('date_format'));
1958
-                $existing->set_time_format(get_option('time_format'));
1959
-            }
1960
-            foreach ($props_n_values as $property => $field_value) {
1961
-                $existing->set($property, $field_value);
1962
-            }
1963
-            return $existing;
1964
-        } else {
1965
-            return false;
1966
-        }
1967
-    }
1968
-
1969
-
1970
-
1971
-    /**
1972
-     * Gets the EEM_*_Model for this class
1973
-     *
1974
-     * @access public now, as this is more convenient
1975
-     * @param      $classname
1976
-     * @param null $timezone
1977
-     * @throws EE_Error
1978
-     * @return EEM_Base
1979
-     */
1980
-    protected static function _get_model($classname, $timezone = null)
1981
-    {
1982
-        //find model for this class
1983
-        if ( ! $classname) {
1984
-            throw new EE_Error(
1985
-                sprintf(
1986
-                    __(
1987
-                        "What were you thinking calling _get_model(%s)?? You need to specify the class name",
1988
-                        "event_espresso"
1989
-                    ),
1990
-                    $classname
1991
-                )
1992
-            );
1993
-        }
1994
-        $modelName = self::_get_model_classname($classname);
1995
-        return self::_get_model_instance_with_name($modelName, $timezone);
1996
-    }
1997
-
1998
-
1999
-    /**
2000
-     * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2001
-     *
2002
-     * @param string $model_classname
2003
-     * @param null $timezone
2004
-     * @return EEM_Base
2005
-     * @throws \ReflectionException
2006
-     * @throws InvalidArgumentException
2007
-     * @throws InvalidInterfaceException
2008
-     * @throws InvalidDataTypeException
2009
-     * @throws EE_Error
2010
-     */
2011
-    protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2012
-    {
2013
-        $model_classname = str_replace('EEM_', '', $model_classname);
2014
-        $model = EE_Registry::instance()->load_model($model_classname);
2015
-        $model->set_timezone($timezone);
2016
-        return $model;
2017
-    }
2018
-
2019
-
2020
-
2021
-    /**
2022
-     * If a model name is provided (eg Registration), gets the model classname for that model.
2023
-     * Also works if a model class's classname is provided (eg EE_Registration).
2024
-     *
2025
-     * @param null $model_name
2026
-     * @return string like EEM_Attendee
2027
-     */
2028
-    private static function _get_model_classname($model_name = null)
2029
-    {
2030
-        if (strpos($model_name, "EE_") === 0) {
2031
-            $model_classname = str_replace("EE_", "EEM_", $model_name);
2032
-        } else {
2033
-            $model_classname = "EEM_" . $model_name;
2034
-        }
2035
-        return $model_classname;
2036
-    }
2037
-
2038
-
2039
-
2040
-    /**
2041
-     * returns the name of the primary key attribute
2042
-     *
2043
-     * @param null $classname
2044
-     * @throws EE_Error
2045
-     * @return string
2046
-     */
2047
-    protected static function _get_primary_key_name($classname = null)
2048
-    {
2049
-        if ( ! $classname) {
2050
-            throw new EE_Error(
2051
-                sprintf(
2052
-                    __("What were you thinking calling _get_primary_key_name(%s)", "event_espresso"),
2053
-                    $classname
2054
-                )
2055
-            );
2056
-        }
2057
-        return self::_get_model($classname)->get_primary_key_field()->get_name();
2058
-    }
2059
-
2060
-
2061
-
2062
-    /**
2063
-     * Gets the value of the primary key.
2064
-     * If the object hasn't yet been saved, it should be whatever the model field's default was
2065
-     * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2066
-     * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2067
-     *
2068
-     * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2069
-     * @throws EE_Error
2070
-     */
2071
-    public function ID()
2072
-    {
2073
-        $model = $this->get_model();
2074
-        //now that we know the name of the variable, use a variable variable to get its value and return its
2075
-        if ($model->has_primary_key_field()) {
2076
-            return $this->_fields[$model->primary_key_name()];
2077
-        } else {
2078
-            return $model->get_index_primary_key_string($this->_fields);
2079
-        }
2080
-    }
2081
-
2082
-
2083
-
2084
-    /**
2085
-     * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2086
-     * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2087
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2088
-     *
2089
-     * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2090
-     * @param string $relationName                     eg 'Events','Question',etc.
2091
-     *                                                 an attendee to a group, you also want to specify which role they
2092
-     *                                                 will have in that group. So you would use this parameter to
2093
-     *                                                 specify array('role-column-name'=>'role-id')
2094
-     * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2095
-     *                                                 allow you to further constrict the relation to being added.
2096
-     *                                                 However, keep in mind that the columns (keys) given must match a
2097
-     *                                                 column on the JOIN table and currently only the HABTM models
2098
-     *                                                 accept these additional conditions.  Also remember that if an
2099
-     *                                                 exact match isn't found for these extra cols/val pairs, then a
2100
-     *                                                 NEW row is created in the join table.
2101
-     * @param null   $cache_id
2102
-     * @throws EE_Error
2103
-     * @return EE_Base_Class the object the relation was added to
2104
-     */
2105
-    public function _add_relation_to(
2106
-        $otherObjectModelObjectOrID,
2107
-        $relationName,
2108
-        $extra_join_model_fields_n_values = array(),
2109
-        $cache_id = null
2110
-    ) {
2111
-        $model = $this->get_model();
2112
-        //if this thing exists in the DB, save the relation to the DB
2113
-        if ($this->ID()) {
2114
-            $otherObject = $model
2115
-                                ->add_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2116
-                                    $extra_join_model_fields_n_values);
2117
-            //clear cache so future get_many_related and get_first_related() return new results.
2118
-            $this->clear_cache($relationName, $otherObject, true);
2119
-            if ($otherObject instanceof EE_Base_Class) {
2120
-                $otherObject->clear_cache($model->get_this_model_name(), $this);
2121
-            }
2122
-        } else {
2123
-            //this thing doesn't exist in the DB,  so just cache it
2124
-            if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2125
-                throw new EE_Error(sprintf(
2126
-                    __('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',
2127
-                        'event_espresso'),
2128
-                    $otherObjectModelObjectOrID,
2129
-                    get_class($this)
2130
-                ));
2131
-            } else {
2132
-                $otherObject = $otherObjectModelObjectOrID;
2133
-            }
2134
-            $this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2135
-        }
2136
-        if ($otherObject instanceof EE_Base_Class) {
2137
-            //fix the reciprocal relation too
2138
-            if ($otherObject->ID()) {
2139
-                //its saved so assumed relations exist in the DB, so we can just
2140
-                //clear the cache so future queries use the updated info in the DB
2141
-                $otherObject->clear_cache($model->get_this_model_name(), null, true);
2142
-            } else {
2143
-                //it's not saved, so it caches relations like this
2144
-                $otherObject->cache($model->get_this_model_name(), $this);
2145
-            }
2146
-        }
2147
-        return $otherObject;
2148
-    }
2149
-
2150
-
2151
-
2152
-    /**
2153
-     * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2154
-     * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2155
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2156
-     * from the cache
2157
-     *
2158
-     * @param mixed  $otherObjectModelObjectOrID
2159
-     *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2160
-     *                to the DB yet
2161
-     * @param string $relationName
2162
-     * @param array  $where_query
2163
-     *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2164
-     *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2165
-     *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2166
-     *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2167
-     *                created in the join table.
2168
-     * @return EE_Base_Class the relation was removed from
2169
-     * @throws EE_Error
2170
-     */
2171
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2172
-    {
2173
-        if ($this->ID()) {
2174
-            //if this exists in the DB, save the relation change to the DB too
2175
-            $otherObject = $this->get_model()
2176
-                                ->remove_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2177
-                                    $where_query);
2178
-            $this->clear_cache($relationName, $otherObject);
2179
-        } else {
2180
-            //this doesn't exist in the DB, just remove it from the cache
2181
-            $otherObject = $this->clear_cache($relationName, $otherObjectModelObjectOrID);
2182
-        }
2183
-        if ($otherObject instanceof EE_Base_Class) {
2184
-            $otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2185
-        }
2186
-        return $otherObject;
2187
-    }
2188
-
2189
-
2190
-
2191
-    /**
2192
-     * Removes ALL the related things for the $relationName.
2193
-     *
2194
-     * @param string $relationName
2195
-     * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2196
-     * @return EE_Base_Class
2197
-     * @throws EE_Error
2198
-     */
2199
-    public function _remove_relations($relationName, $where_query_params = array())
2200
-    {
2201
-        if ($this->ID()) {
2202
-            //if this exists in the DB, save the relation change to the DB too
2203
-            $otherObjects = $this->get_model()->remove_relations($this, $relationName, $where_query_params);
2204
-            $this->clear_cache($relationName, null, true);
2205
-        } else {
2206
-            //this doesn't exist in the DB, just remove it from the cache
2207
-            $otherObjects = $this->clear_cache($relationName, null, true);
2208
-        }
2209
-        if (is_array($otherObjects)) {
2210
-            foreach ($otherObjects as $otherObject) {
2211
-                $otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2212
-            }
2213
-        }
2214
-        return $otherObjects;
2215
-    }
2216
-
2217
-
2218
-
2219
-    /**
2220
-     * Gets all the related model objects of the specified type. Eg, if the current class if
2221
-     * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2222
-     * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2223
-     * because we want to get even deleted items etc.
2224
-     *
2225
-     * @param string $relationName key in the model's _model_relations array
2226
-     * @param array  $query_params like EEM_Base::get_all
2227
-     * @return EE_Base_Class[] Results not necessarily indexed by IDs, because some results might not have primary keys
2228
-     * @throws EE_Error
2229
-     *                             or might not be saved yet. Consider using EEM_Base::get_IDs() on these results if
2230
-     *                             you want IDs
2231
-     */
2232
-    public function get_many_related($relationName, $query_params = array())
2233
-    {
2234
-        if ($this->ID()) {
2235
-            //this exists in the DB, so get the related things from either the cache or the DB
2236
-            //if there are query parameters, forget about caching the related model objects.
2237
-            if ($query_params) {
2238
-                $related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2239
-            } else {
2240
-                //did we already cache the result of this query?
2241
-                $cached_results = $this->get_all_from_cache($relationName);
2242
-                if ( ! $cached_results) {
2243
-                    $related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2244
-                    //if no query parameters were passed, then we got all the related model objects
2245
-                    //for that relation. We can cache them then.
2246
-                    foreach ($related_model_objects as $related_model_object) {
2247
-                        $this->cache($relationName, $related_model_object);
2248
-                    }
2249
-                } else {
2250
-                    $related_model_objects = $cached_results;
2251
-                }
2252
-            }
2253
-        } else {
2254
-            //this doesn't exist in the DB, so just get the related things from the cache
2255
-            $related_model_objects = $this->get_all_from_cache($relationName);
2256
-        }
2257
-        return $related_model_objects;
2258
-    }
2259
-
2260
-
2261
-    /**
2262
-     * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2263
-     * unless otherwise specified in the $query_params
2264
-     *
2265
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2266
-     * @param array $query_params like EEM_Base::get_all's
2267
-     * @param string $field_to_count name of field to count by. By default, uses primary key
2268
-     * @param bool $distinct if we want to only count the distinct values for the column then you can trigger
2269
-     *                               that by the setting $distinct to TRUE;
2270
-     * @return int
2271
-     * @throws EE_Error
2272
-     */
2273
-    public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2274
-    {
2275
-        return $this->get_model()->count_related($this, $relation_name, $query_params, $field_to_count, $distinct);
2276
-    }
2277
-
2278
-
2279
-    /**
2280
-     * Instead of getting the related model objects, simply sums up the values of the specified field.
2281
-     * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2282
-     *
2283
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2284
-     * @param array $query_params like EEM_Base::get_all's
2285
-     * @param string $field_to_sum name of field to count by.
2286
-     *                              By default, uses primary key (which doesn't make much sense, so you should probably
2287
-     *                              change it)
2288
-     * @return int
2289
-     * @throws EE_Error
2290
-     */
2291
-    public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2292
-    {
2293
-        return $this->get_model()->sum_related($this, $relation_name, $query_params, $field_to_sum);
2294
-    }
2295
-
2296
-
2297
-
2298
-    /**
2299
-     * Gets the first (ie, one) related model object of the specified type.
2300
-     *
2301
-     * @param string $relationName key in the model's _model_relations array
2302
-     * @param array  $query_params like EEM_Base::get_all
2303
-     * @return EE_Base_Class (not an array, a single object)
2304
-     * @throws EE_Error
2305
-     */
2306
-    public function get_first_related($relationName, $query_params = array())
2307
-    {
2308
-        $model = $this->get_model();
2309
-        if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2310
-            //if they've provided some query parameters, don't bother trying to cache the result
2311
-            //also make sure we're not caching the result of get_first_related
2312
-            //on a relation which should have an array of objects (because the cache might have an array of objects)
2313
-            if ($query_params
2314
-                || ! $model->related_settings_for($relationName)
2315
-                     instanceof
2316
-                     EE_Belongs_To_Relation
2317
-            ) {
2318
-                $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2319
-            } else {
2320
-                //first, check if we've already cached the result of this query
2321
-                $cached_result = $this->get_one_from_cache($relationName);
2322
-                if ( ! $cached_result) {
2323
-                    $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2324
-                    $this->cache($relationName, $related_model_object);
2325
-                } else {
2326
-                    $related_model_object = $cached_result;
2327
-                }
2328
-            }
2329
-        } else {
2330
-            $related_model_object = null;
2331
-            //this doesn't exist in the Db, but maybe the relation is of type belongs to, and so the related thing might
2332
-            if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2333
-                $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2334
-            }
2335
-            //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
2336
-            if ( ! $related_model_object) {
2337
-                $related_model_object = $this->get_one_from_cache($relationName);
2338
-            }
2339
-        }
2340
-        return $related_model_object;
2341
-    }
2342
-
2343
-
2344
-
2345
-    /**
2346
-     * Does a delete on all related objects of type $relationName and removes
2347
-     * the current model object's relation to them. If they can't be deleted (because
2348
-     * of blocking related model objects) does nothing. If the related model objects are
2349
-     * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2350
-     * If this model object doesn't exist yet in the DB, just removes its related things
2351
-     *
2352
-     * @param string $relationName
2353
-     * @param array  $query_params like EEM_Base::get_all's
2354
-     * @return int how many deleted
2355
-     * @throws EE_Error
2356
-     */
2357
-    public function delete_related($relationName, $query_params = array())
2358
-    {
2359
-        if ($this->ID()) {
2360
-            $count = $this->get_model()->delete_related($this, $relationName, $query_params);
2361
-        } else {
2362
-            $count = count($this->get_all_from_cache($relationName));
2363
-            $this->clear_cache($relationName, null, true);
2364
-        }
2365
-        return $count;
2366
-    }
2367
-
2368
-
2369
-
2370
-    /**
2371
-     * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2372
-     * the current model object's relation to them. If they can't be deleted (because
2373
-     * of blocking related model objects) just does a soft delete on it instead, if possible.
2374
-     * If the related thing isn't a soft-deletable model object, this function is identical
2375
-     * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2376
-     *
2377
-     * @param string $relationName
2378
-     * @param array  $query_params like EEM_Base::get_all's
2379
-     * @return int how many deleted (including those soft deleted)
2380
-     * @throws EE_Error
2381
-     */
2382
-    public function delete_related_permanently($relationName, $query_params = array())
2383
-    {
2384
-        if ($this->ID()) {
2385
-            $count = $this->get_model()->delete_related_permanently($this, $relationName, $query_params);
2386
-        } else {
2387
-            $count = count($this->get_all_from_cache($relationName));
2388
-        }
2389
-        $this->clear_cache($relationName, null, true);
2390
-        return $count;
2391
-    }
2392
-
2393
-
2394
-
2395
-    /**
2396
-     * is_set
2397
-     * Just a simple utility function children can use for checking if property exists
2398
-     *
2399
-     * @access  public
2400
-     * @param  string $field_name property to check
2401
-     * @return bool                              TRUE if existing,FALSE if not.
2402
-     */
2403
-    public function is_set($field_name)
2404
-    {
2405
-        return isset($this->_fields[$field_name]);
2406
-    }
2407
-
2408
-
2409
-
2410
-    /**
2411
-     * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2412
-     * EE_Error exception if they don't
2413
-     *
2414
-     * @param  mixed (string|array) $properties properties to check
2415
-     * @throws EE_Error
2416
-     * @return bool                              TRUE if existing, throw EE_Error if not.
2417
-     */
2418
-    protected function _property_exists($properties)
2419
-    {
2420
-        foreach ((array)$properties as $property_name) {
2421
-            //first make sure this property exists
2422
-            if ( ! $this->_fields[$property_name]) {
2423
-                throw new EE_Error(
2424
-                    sprintf(
2425
-                        __(
2426
-                            'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2427
-                            'event_espresso'
2428
-                        ),
2429
-                        $property_name
2430
-                    )
2431
-                );
2432
-            }
2433
-        }
2434
-        return true;
2435
-    }
2436
-
2437
-
2438
-
2439
-    /**
2440
-     * This simply returns an array of model fields for this object
2441
-     *
2442
-     * @return array
2443
-     * @throws EE_Error
2444
-     */
2445
-    public function model_field_array()
2446
-    {
2447
-        $fields = $this->get_model()->field_settings(false);
2448
-        $properties = array();
2449
-        //remove prepended underscore
2450
-        foreach ($fields as $field_name => $settings) {
2451
-            $properties[$field_name] = $this->get($field_name);
2452
-        }
2453
-        return $properties;
2454
-    }
2455
-
2456
-
2457
-
2458
-    /**
2459
-     * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2460
-     * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2461
-     * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
2462
-     * requiring a plugin to extend the EE_Base_Class (which works fine is there's only 1 plugin, but when will that
2463
-     * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
2464
-     * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
2465
-     * was called, and an array of the original arguments passed to the function. Whatever their callback function
2466
-     * returns will be returned by this function. Example: in functions.php (or in a plugin):
2467
-     * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
2468
-     * my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2469
-     * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2470
-     *        return $previousReturnValue.$returnString;
2471
-     * }
2472
-     * require('EE_Answer.class.php');
2473
-     * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2474
-     * echo $answer->my_callback('monkeys',100);
2475
-     * //will output "you called my_callback! and passed args:monkeys,100"
2476
-     *
2477
-     * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2478
-     * @param array  $args       array of original arguments passed to the function
2479
-     * @throws EE_Error
2480
-     * @return mixed whatever the plugin which calls add_filter decides
2481
-     */
2482
-    public function __call($methodName, $args)
2483
-    {
2484
-        $className = get_class($this);
2485
-        $tagName = "FHEE__{$className}__{$methodName}";
2486
-        if ( ! has_filter($tagName)) {
2487
-            throw new EE_Error(
2488
-                sprintf(
2489
-                    __(
2490
-                        "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;}",
2491
-                        "event_espresso"
2492
-                    ),
2493
-                    $methodName,
2494
-                    $className,
2495
-                    $tagName
2496
-                )
2497
-            );
2498
-        }
2499
-        return apply_filters($tagName, null, $this, $args);
2500
-    }
2501
-
2502
-
2503
-    /**
2504
-     * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2505
-     * A $previous_value can be specified in case there are many meta rows with the same key
2506
-     *
2507
-     * @param string $meta_key
2508
-     * @param mixed $meta_value
2509
-     * @param mixed $previous_value
2510
-     * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2511
-     * @throws InvalidArgumentException
2512
-     * @throws InvalidInterfaceException
2513
-     * @throws InvalidDataTypeException
2514
-     * @throws EE_Error
2515
-     * NOTE: if the values haven't changed, returns 0
2516
-     */
2517
-    public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2518
-    {
2519
-        $query_params = array(
2520
-            array(
2521
-                'EXM_key'  => $meta_key,
2522
-                'OBJ_ID'   => $this->ID(),
2523
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2524
-            ),
2525
-        );
2526
-        if ($previous_value !== null) {
2527
-            $query_params[0]['EXM_value'] = $meta_value;
2528
-        }
2529
-        $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2530
-        if ( ! $existing_rows_like_that) {
2531
-            return $this->add_extra_meta($meta_key, $meta_value);
2532
-        }
2533
-        foreach ($existing_rows_like_that as $existing_row) {
2534
-            $existing_row->save(array('EXM_value' => $meta_value));
2535
-        }
2536
-        return count($existing_rows_like_that);
2537
-    }
2538
-
2539
-
2540
-    /**
2541
-     * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2542
-     * no other extra meta for this model object have the same key. Returns TRUE if the
2543
-     * extra meta row was entered, false if not
2544
-     *
2545
-     * @param string $meta_key
2546
-     * @param mixed $meta_value
2547
-     * @param boolean $unique
2548
-     * @return boolean
2549
-     * @throws InvalidArgumentException
2550
-     * @throws InvalidInterfaceException
2551
-     * @throws InvalidDataTypeException
2552
-     * @throws EE_Error
2553
-     */
2554
-    public function add_extra_meta($meta_key, $meta_value, $unique = false)
2555
-    {
2556
-        if ($unique) {
2557
-            $existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2558
-                array(
2559
-                    array(
2560
-                        'EXM_key'  => $meta_key,
2561
-                        'OBJ_ID'   => $this->ID(),
2562
-                        'EXM_type' => $this->get_model()->get_this_model_name(),
2563
-                    ),
2564
-                )
2565
-            );
2566
-            if ($existing_extra_meta) {
2567
-                return false;
2568
-            }
2569
-        }
2570
-        $new_extra_meta = EE_Extra_Meta::new_instance(
2571
-            array(
2572
-                'EXM_key'   => $meta_key,
2573
-                'EXM_value' => $meta_value,
2574
-                'OBJ_ID'    => $this->ID(),
2575
-                'EXM_type'  => $this->get_model()->get_this_model_name(),
2576
-            )
2577
-        );
2578
-        $new_extra_meta->save();
2579
-        return true;
2580
-    }
2581
-
2582
-
2583
-    /**
2584
-     * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2585
-     * is specified, only deletes extra meta records with that value.
2586
-     *
2587
-     * @param string $meta_key
2588
-     * @param mixed $meta_value
2589
-     * @return int number of extra meta rows deleted
2590
-     * @throws InvalidArgumentException
2591
-     * @throws InvalidInterfaceException
2592
-     * @throws InvalidDataTypeException
2593
-     * @throws EE_Error
2594
-     */
2595
-    public function delete_extra_meta($meta_key, $meta_value = null)
2596
-    {
2597
-        $query_params = array(
2598
-            array(
2599
-                'EXM_key'  => $meta_key,
2600
-                'OBJ_ID'   => $this->ID(),
2601
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2602
-            ),
2603
-        );
2604
-        if ($meta_value !== null) {
2605
-            $query_params[0]['EXM_value'] = $meta_value;
2606
-        }
2607
-        return EEM_Extra_Meta::instance()->delete($query_params);
2608
-    }
2609
-
2610
-
2611
-
2612
-    /**
2613
-     * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2614
-     * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2615
-     * You can specify $default is case you haven't found the extra meta
2616
-     *
2617
-     * @param string  $meta_key
2618
-     * @param boolean $single
2619
-     * @param mixed   $default if we don't find anything, what should we return?
2620
-     * @return mixed single value if $single; array if ! $single
2621
-     * @throws EE_Error
2622
-     */
2623
-    public function get_extra_meta($meta_key, $single = false, $default = null)
2624
-    {
2625
-        if ($single) {
2626
-            $result = $this->get_first_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2627
-            if ($result instanceof EE_Extra_Meta) {
2628
-                return $result->value();
2629
-            }
2630
-        } else {
2631
-            $results = $this->get_many_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2632
-            if ($results) {
2633
-                $values = array();
2634
-                foreach ($results as $result) {
2635
-                    if ($result instanceof EE_Extra_Meta) {
2636
-                        $values[$result->ID()] = $result->value();
2637
-                    }
2638
-                }
2639
-                return $values;
2640
-            }
2641
-        }
2642
-        //if nothing discovered yet return default.
2643
-        return apply_filters(
2644
-            'FHEE__EE_Base_Class__get_extra_meta__default_value',
2645
-            $default,
2646
-            $meta_key,
2647
-            $single,
2648
-            $this
2649
-            );
2650
-    }
2651
-
2652
-
2653
-
2654
-    /**
2655
-     * Returns a simple array of all the extra meta associated with this model object.
2656
-     * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2657
-     * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2658
-     * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2659
-     * If $one_of_each_key is false, it will return an array with the top-level keys being
2660
-     * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2661
-     * finally the extra meta's value as each sub-value. (eg
2662
-     * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2663
-     *
2664
-     * @param boolean $one_of_each_key
2665
-     * @return array
2666
-     * @throws EE_Error
2667
-     */
2668
-    public function all_extra_meta_array($one_of_each_key = true)
2669
-    {
2670
-        $return_array = array();
2671
-        if ($one_of_each_key) {
2672
-            $extra_meta_objs = $this->get_many_related('Extra_Meta', array('group_by' => 'EXM_key'));
2673
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2674
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2675
-                    $return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2676
-                }
2677
-            }
2678
-        } else {
2679
-            $extra_meta_objs = $this->get_many_related('Extra_Meta');
2680
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2681
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2682
-                    if ( ! isset($return_array[$extra_meta_obj->key()])) {
2683
-                        $return_array[$extra_meta_obj->key()] = array();
2684
-                    }
2685
-                    $return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2686
-                }
2687
-            }
2688
-        }
2689
-        return $return_array;
2690
-    }
2691
-
2692
-
2693
-
2694
-    /**
2695
-     * Gets a pretty nice displayable nice for this model object. Often overridden
2696
-     *
2697
-     * @return string
2698
-     * @throws EE_Error
2699
-     */
2700
-    public function name()
2701
-    {
2702
-        //find a field that's not a text field
2703
-        $field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2704
-        if ($field_we_can_use) {
2705
-            return $this->get($field_we_can_use->get_name());
2706
-        } else {
2707
-            $first_few_properties = $this->model_field_array();
2708
-            $first_few_properties = array_slice($first_few_properties, 0, 3);
2709
-            $name_parts = array();
2710
-            foreach ($first_few_properties as $name => $value) {
2711
-                $name_parts[] = "$name:$value";
2712
-            }
2713
-            return implode(",", $name_parts);
2714
-        }
2715
-    }
2716
-
2717
-
2718
-
2719
-    /**
2720
-     * in_entity_map
2721
-     * Checks if this model object has been proven to already be in the entity map
2722
-     *
2723
-     * @return boolean
2724
-     * @throws EE_Error
2725
-     */
2726
-    public function in_entity_map()
2727
-    {
2728
-        if ($this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this) {
2729
-            //well, if we looked, did we find it in the entity map?
2730
-            return true;
2731
-        } else {
2732
-            return false;
2733
-        }
2734
-    }
2735
-
2736
-
2737
-
2738
-    /**
2739
-     * refresh_from_db
2740
-     * Makes sure the fields and values on this model object are in-sync with what's in the database.
2741
-     *
2742
-     * @throws EE_Error if this model object isn't in the entity mapper (because then you should
2743
-     * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
2744
-     */
2745
-    public function refresh_from_db()
2746
-    {
2747
-        if ($this->ID() && $this->in_entity_map()) {
2748
-            $this->get_model()->refresh_entity_map_from_db($this->ID());
2749
-        } else {
2750
-            //if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
2751
-            //if it has an ID but it's not in the map, and you're asking me to refresh it
2752
-            //that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
2753
-            //absolutely nothing in it for this ID
2754
-            if (WP_DEBUG) {
2755
-                throw new EE_Error(
2756
-                    sprintf(
2757
-                        __('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.',
2758
-                            'event_espresso'),
2759
-                        $this->ID(),
2760
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2761
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2762
-                    )
2763
-                );
2764
-            }
2765
-        }
2766
-    }
2767
-
2768
-    /**
2769
-     * Gets the money field's amount in subunits (and if the currency has no subunits, gets it in the main units)
2770
-     * @param string $money_field_name
2771
-     * @return int
2772
-     * @throws InvalidEntityException
2773
-     * @throws EE_Error
2774
-     */
2775
-    public function moneyInSubunits($money_field_name)
2776
-    {
2777
-        return $this->getMoneyObject($money_field_name)->amountInSubunits();
2778
-    }
2779
-
2780
-    /**
2781
-     * Sets the money field's amount based on the incoming monetary subunits (eg pennies). If the currency has no subunits,
2782
-     * the amount is actually assumed to be in the currency's main units
2783
-     * @param string $money_field_name
2784
-     * @param int $amount_in_subunits
2785
-     * @throws InvalidArgumentException
2786
-     * @throws InvalidInterfaceException
2787
-     * @throws InvalidIdentifierException
2788
-     * @throws InvalidDataTypeException
2789
-     * @throws EE_Error
2790
-     */
2791
-    public function setMoneySubunits($money_field_name,$amount_in_subunits)
2792
-    {
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
-    /**
2803
-     * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
2804
-     * (probably a bad assumption they have made, oh well)
2805
-     *
2806
-     * @return string
2807
-     */
2808
-    public function __toString()
2809
-    {
2810
-        try {
2811
-            return sprintf('%s (%s)', $this->name(), $this->ID());
2812
-        } catch (Exception $e) {
2813
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
2814
-            return '';
2815
-        }
2816
-    }
2817
-
2818
-
2819
-
2820
-    /**
2821
-     * Clear related model objects if they're already in the DB, because otherwise when we
2822
-     * UN-serialize this model object we'll need to be careful to add them to the entity map.
2823
-     * This means if we have made changes to those related model objects, and want to unserialize
2824
-     * the this model object on a subsequent request, changes to those related model objects will be lost.
2825
-     * Instead, those related model objects should be directly serialized and stored.
2826
-     * Eg, the following won't work:
2827
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2828
-     * $att = $reg->attendee();
2829
-     * $att->set( 'ATT_fname', 'Dirk' );
2830
-     * update_option( 'my_option', serialize( $reg ) );
2831
-     * //END REQUEST
2832
-     * //START NEXT REQUEST
2833
-     * $reg = get_option( 'my_option' );
2834
-     * $reg->attendee()->save();
2835
-     * And would need to be replace with:
2836
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2837
-     * $att = $reg->attendee();
2838
-     * $att->set( 'ATT_fname', 'Dirk' );
2839
-     * update_option( 'my_option', serialize( $reg ) );
2840
-     * //END REQUEST
2841
-     * //START NEXT REQUEST
2842
-     * $att = get_option( 'my_option' );
2843
-     * $att->save();
2844
-     *
2845
-     * @return array
2846
-     * @throws EE_Error
2847
-     */
2848
-    public function __sleep()
2849
-    {
2850
-        $model = $this->get_model();
2851
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2852
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
2853
-                $classname = 'EE_' . $model->get_this_model_name();
2854
-                if (
2855
-                    $this->get_one_from_cache($relation_name) instanceof $classname
2856
-                    && $this->get_one_from_cache($relation_name)->ID()
2857
-                ) {
2858
-                    $this->clear_cache($relation_name, $this->get_one_from_cache($relation_name)->ID());
2859
-                }
2860
-            }
2861
-        }
2862
-        $this->_props_n_values_provided_in_constructor = array();
2863
-        $properties_to_serialize = get_object_vars($this);
2864
-        //don't serialize the model. It's big and that risks recursion
2865
-        unset($properties_to_serialize['_model']);
2866
-        return array_keys($properties_to_serialize);
2867
-    }
2868
-
2869
-
2870
-
2871
-    /**
2872
-     * restore _props_n_values_provided_in_constructor
2873
-     * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
2874
-     * and therefore should NOT be used to determine if state change has occurred since initial construction.
2875
-     * At best, you would only be able to detect if state change has occurred during THIS request.
2876
-     */
2877
-    public function __wakeup()
2878
-    {
2879
-        $this->_props_n_values_provided_in_constructor = $this->_fields;
2880
-    }
39
+	/**
40
+	 * This is an array of the original properties and values provided during construction
41
+	 * of this model object. (keys are model field names, values are their values).
42
+	 * This list is important to remember so that when we are merging data from the db, we know
43
+	 * which values to override and which to not override.
44
+	 *
45
+	 * @var array
46
+	 */
47
+	protected $_props_n_values_provided_in_constructor;
48
+
49
+	/**
50
+	 * Timezone
51
+	 * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
52
+	 * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
53
+	 * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
54
+	 * access to it.
55
+	 *
56
+	 * @var string
57
+	 */
58
+	protected $_timezone;
59
+
60
+
61
+
62
+	/**
63
+	 * date format
64
+	 * pattern or format for displaying dates
65
+	 *
66
+	 * @var string $_dt_frmt
67
+	 */
68
+	protected $_dt_frmt;
69
+
70
+
71
+
72
+	/**
73
+	 * time format
74
+	 * pattern or format for displaying time
75
+	 *
76
+	 * @var string $_tm_frmt
77
+	 */
78
+	protected $_tm_frmt;
79
+
80
+
81
+
82
+	/**
83
+	 * This property is for holding a cached array of object properties indexed by property name as the key.
84
+	 * The purpose of this is for setting a cache on properties that may have calculated values after a
85
+	 * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
86
+	 * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
87
+	 *
88
+	 * @var array
89
+	 */
90
+	protected $_cached_properties = array();
91
+
92
+	/**
93
+	 * An array containing keys of the related model, and values are either an array of related mode objects or a
94
+	 * single
95
+	 * related model object. see the model's _model_relations. The keys should match those specified. And if the
96
+	 * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
97
+	 * all others have an array)
98
+	 *
99
+	 * @var array
100
+	 */
101
+	protected $_model_relations = array();
102
+
103
+	/**
104
+	 * Array where keys are field names (see the model's _fields property) and values are their values. To see what
105
+	 * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
106
+	 *
107
+	 * @var array
108
+	 */
109
+	protected $_fields = array();
110
+
111
+	/**
112
+	 * @var boolean indicating whether or not this model object is intended to ever be saved
113
+	 * For example, we might create model objects intended to only be used for the duration
114
+	 * of this request and to be thrown away, and if they were accidentally saved
115
+	 * it would be a bug.
116
+	 */
117
+	protected $_allow_persist = true;
118
+
119
+	/**
120
+	 * @var boolean indicating whether or not this model object's properties have changed since construction
121
+	 */
122
+	protected $_has_changes = false;
123
+
124
+	/**
125
+	 * @var EEM_Base
126
+	 */
127
+	protected $_model;
128
+
129
+	/**
130
+	 * @var MoneyFactory
131
+	 */
132
+	protected $money_factory;
133
+
134
+
135
+	/**
136
+	 * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
137
+	 * play nice
138
+	 *
139
+	 * @param array $fieldValues where each key is a field (ie, array key in the 2nd
140
+	 *                                                         layer of the model's _fields array, (eg, EVT_ID,
141
+	 *                                                         TXN_amount, QST_name, etc) and values are their values
142
+	 * @param boolean $bydb a flag for setting if the class is instantiated by the
143
+	 *                                                         corresponding db model or not.
144
+	 * @param string $timezone indicate what timezone you want any datetime fields to
145
+	 *                                                         be in when instantiating a EE_Base_Class object.
146
+	 * @param array $date_formats An array of date formats to set on construct where first
147
+	 *                                                         value is the date_format and second value is the time
148
+	 *                                                         format.
149
+	 * @param MoneyFactory|null $money_factory
150
+	 * @throws InvalidArgumentException
151
+	 * @throws InvalidInterfaceException
152
+	 * @throws InvalidDataTypeException
153
+	 * @throws EE_Error
154
+	 */
155
+	protected function __construct(
156
+		$fieldValues = array(),
157
+		$bydb = false,
158
+		$timezone = '',
159
+		$date_formats = array(),
160
+		MoneyFactory $money_factory = null
161
+	) {
162
+		if (! $money_factory instanceof MoneyFactory) {
163
+			$money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
164
+		}
165
+		$this->money_factory = $money_factory;
166
+		$className = get_class($this);
167
+		do_action("AHEE__{$className}__construct", $this, $fieldValues);
168
+		$model = $this->get_model();
169
+		$model_fields = $model->field_settings(false);
170
+		// ensure $fieldValues is an array
171
+		$fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
172
+		// EEH_Debug_Tools::printr( $fieldValues, '$fieldValues  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
173
+		// verify client code has not passed any invalid field names
174
+		foreach ($fieldValues as $field_name => $field_value) {
175
+			if ( ! isset($model_fields[$field_name])) {
176
+				throw new EE_Error(sprintf(__("Invalid field (%s) passed to constructor of %s. Allowed fields are :%s",
177
+					"event_espresso"), $field_name, get_class($this), implode(", ", array_keys($model_fields))));
178
+			}
179
+		}
180
+		// EEH_Debug_Tools::printr( $model_fields, '$model_fields  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
181
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
182
+		if ( ! empty($date_formats) && is_array($date_formats)) {
183
+			list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
184
+		} else {
185
+			//set default formats for date and time
186
+			$this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
187
+			$this->_tm_frmt = (string)get_option('time_format', 'g:i a');
188
+		}
189
+		//if db model is instantiating
190
+		if ($bydb) {
191
+			//client code has indicated these field values are from the database
192
+			foreach ($model_fields as $fieldName => $field) {
193
+				$this->set_from_db($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null);
194
+			}
195
+		} else {
196
+			//we're constructing a brand
197
+			//new instance of the model object. Generally, this means we'll need to do more field validation
198
+			foreach ($model_fields as $fieldName => $field) {
199
+				$this->set($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true);
200
+			}
201
+		}
202
+		//remember what values were passed to this constructor
203
+		$this->_props_n_values_provided_in_constructor = $fieldValues;
204
+		//remember in entity mapper
205
+		if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
206
+			$model->add_to_entity_map($this);
207
+		}
208
+		//setup all the relations
209
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
210
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
211
+				$this->_model_relations[$relation_name] = null;
212
+			} else {
213
+				$this->_model_relations[$relation_name] = array();
214
+			}
215
+		}
216
+		/**
217
+		 * Action done at the end of each model object construction
218
+		 *
219
+		 * @param EE_Base_Class $this the model object just created
220
+		 */
221
+		do_action('AHEE__EE_Base_Class__construct__finished', $this);
222
+	}
223
+
224
+
225
+
226
+	/**
227
+	 * Gets whether or not this model object is allowed to persist/be saved to the database.
228
+	 *
229
+	 * @return boolean
230
+	 */
231
+	public function allow_persist()
232
+	{
233
+		return $this->_allow_persist;
234
+	}
235
+
236
+
237
+
238
+	/**
239
+	 * Sets whether or not this model object should be allowed to be saved to the DB.
240
+	 * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
241
+	 * you got new information that somehow made you change your mind.
242
+	 *
243
+	 * @param boolean $allow_persist
244
+	 * @return boolean
245
+	 */
246
+	public function set_allow_persist($allow_persist)
247
+	{
248
+		return $this->_allow_persist = $allow_persist;
249
+	}
250
+
251
+
252
+
253
+	/**
254
+	 * Gets the field's original value when this object was constructed during this request.
255
+	 * This can be helpful when determining if a model object has changed or not
256
+	 *
257
+	 * @param string $field_name
258
+	 * @return mixed|null
259
+	 * @throws EE_Error
260
+	 */
261
+	public function get_original($field_name)
262
+	{
263
+		if (isset($this->_props_n_values_provided_in_constructor[$field_name])
264
+			&& $field_settings = $this->get_model()->field_settings_for($field_name)
265
+		) {
266
+			return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
267
+		} else {
268
+			return null;
269
+		}
270
+	}
271
+
272
+
273
+
274
+	/**
275
+	 * @param EE_Base_Class $obj
276
+	 * @return string
277
+	 */
278
+	public function get_class($obj)
279
+	{
280
+		return get_class($obj);
281
+	}
282
+
283
+
284
+	/**
285
+	 * Overrides parent because parent expects old models.
286
+	 * This also doesn't do any validation, and won't work for serialized arrays
287
+	 *
288
+	 * @param    string $field_name
289
+	 * @param    mixed $field_value
290
+	 * @param bool $use_default
291
+	 * @throws InvalidArgumentException
292
+	 * @throws InvalidInterfaceException
293
+	 * @throws InvalidDataTypeException
294
+	 * @throws EE_Error
295
+	 */
296
+	public function set($field_name, $field_value, $use_default = false)
297
+	{
298
+		// if not using default and nothing has changed, and object has already been setup (has ID),
299
+		// then don't do anything
300
+		if (
301
+			! $use_default
302
+			&& $this->_fields[$field_name] === $field_value
303
+			&& $this->ID()
304
+		) {
305
+			return;
306
+		}
307
+		$model = $this->get_model();
308
+		$this->_has_changes = true;
309
+		$field_obj = $model->field_settings_for($field_name);
310
+		if ($field_obj instanceof EE_Model_Field_Base) {
311
+			//			if ( method_exists( $field_obj, 'set_timezone' )) {
312
+			if ($field_obj instanceof EE_Datetime_Field) {
313
+				$field_obj->set_timezone($this->_timezone);
314
+				$field_obj->set_date_format($this->_dt_frmt);
315
+				$field_obj->set_time_format($this->_tm_frmt);
316
+			}
317
+			$holder_of_value = $field_obj->prepare_for_set($field_value);
318
+			//should the value be null?
319
+			if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
320
+				$this->_fields[$field_name] = $field_obj->get_default_value();
321
+				/**
322
+				 * To save having to refactor all the models, if a default value is used for a
323
+				 * EE_Datetime_Field, and that value is not null nor is it a DateTime
324
+				 * object.  Then let's do a set again to ensure that it becomes a DateTime
325
+				 * object.
326
+				 *
327
+				 * @since 4.6.10+
328
+				 */
329
+				if (
330
+					$field_obj instanceof EE_Datetime_Field
331
+					&& $this->_fields[$field_name] !== null
332
+					&& ! $this->_fields[$field_name] instanceof DateTime
333
+				) {
334
+					empty($this->_fields[$field_name])
335
+						? $this->set($field_name, time())
336
+						: $this->set($field_name, $this->_fields[$field_name]);
337
+				}
338
+			} else {
339
+				$this->_fields[$field_name] = $holder_of_value;
340
+			}
341
+			//if we're not in the constructor...
342
+			//now check if what we set was a primary key
343
+			if (
344
+				//note: props_n_values_provided_in_constructor is only set at the END of the constructor
345
+				$this->_props_n_values_provided_in_constructor
346
+				&& $field_value
347
+				&& $field_name === $model->primary_key_name()
348
+			) {
349
+				//if so, we want all this object's fields to be filled either with
350
+				//what we've explicitly set on this model
351
+				//or what we have in the db
352
+				// echo "setting primary key!";
353
+				$fields_on_model = self::_get_model(get_class($this))->field_settings();
354
+				$obj_in_db = self::_get_model(get_class($this))->get_one_by_ID($field_value);
355
+				foreach ($fields_on_model as $field_obj) {
356
+					if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
357
+						 && $field_obj->get_name() !== $field_name
358
+					) {
359
+						$this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
360
+					}
361
+				}
362
+				//oh this model object has an ID? well make sure its in the entity mapper
363
+				$model->add_to_entity_map($this);
364
+			}
365
+			//let's unset any cache for this field_name from the $_cached_properties property.
366
+			$this->_clear_cached_property($field_name);
367
+		} else {
368
+			throw new EE_Error(sprintf(__("A valid EE_Model_Field_Base could not be found for the given field name: %s",
369
+				"event_espresso"), $field_name));
370
+		}
371
+	}
372
+
373
+
374
+
375
+	/**
376
+	 * This sets the field value on the db column if it exists for the given $column_name or
377
+	 * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
378
+	 *
379
+	 * @see EE_message::get_column_value for related documentation on the necessity of this method.
380
+	 * @param string $field_name  Must be the exact column name.
381
+	 * @param mixed  $field_value The value to set.
382
+	 * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
383
+	 * @throws EE_Error
384
+	 */
385
+	public function set_field_or_extra_meta($field_name, $field_value)
386
+	{
387
+		if ($this->get_model()->has_field($field_name)) {
388
+			$this->set($field_name, $field_value);
389
+			return true;
390
+		} else {
391
+			//ensure this object is saved first so that extra meta can be properly related.
392
+			$this->save();
393
+			return $this->update_extra_meta($field_name, $field_value);
394
+		}
395
+	}
396
+
397
+
398
+
399
+	/**
400
+	 * This retrieves the value of the db column set on this class or if that's not present
401
+	 * it will attempt to retrieve from extra_meta if found.
402
+	 * Example Usage:
403
+	 * Via EE_Message child class:
404
+	 * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
405
+	 * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
406
+	 * also have additional main fields specific to the messenger.  The system accommodates those extra
407
+	 * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
408
+	 * value for those extra fields dynamically via the EE_message object.
409
+	 *
410
+	 * @param  string $field_name expecting the fully qualified field name.
411
+	 * @return mixed|null  value for the field if found.  null if not found.
412
+	 * @throws EE_Error
413
+	 */
414
+	public function get_field_or_extra_meta($field_name)
415
+	{
416
+		if ($this->get_model()->has_field($field_name)) {
417
+			$column_value = $this->get($field_name);
418
+		} else {
419
+			//This isn't a column in the main table, let's see if it is in the extra meta.
420
+			$column_value = $this->get_extra_meta($field_name, true, null);
421
+		}
422
+		return $column_value;
423
+	}
424
+
425
+
426
+	/**
427
+	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
428
+	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
429
+	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
430
+	 * available to all child classes that may be using the EE_Datetime_Field for a field data type.
431
+	 *
432
+	 * @access public
433
+	 * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
434
+	 * @return void
435
+	 * @throws InvalidArgumentException
436
+	 * @throws InvalidInterfaceException
437
+	 * @throws InvalidDataTypeException
438
+	 * @throws EE_Error
439
+	 */
440
+	public function set_timezone($timezone = '')
441
+	{
442
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
443
+		//make sure we clear all cached properties because they won't be relevant now
444
+		$this->_clear_cached_properties();
445
+		//make sure we update field settings and the date for all EE_Datetime_Fields
446
+		$model_fields = $this->get_model()->field_settings(false);
447
+		foreach ($model_fields as $field_name => $field_obj) {
448
+			if ($field_obj instanceof EE_Datetime_Field) {
449
+				$field_obj->set_timezone($this->_timezone);
450
+				if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
451
+					$this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
452
+				}
453
+			}
454
+		}
455
+	}
456
+
457
+
458
+
459
+	/**
460
+	 * This just returns whatever is set for the current timezone.
461
+	 *
462
+	 * @access public
463
+	 * @return string timezone string
464
+	 */
465
+	public function get_timezone()
466
+	{
467
+		return $this->_timezone;
468
+	}
469
+
470
+
471
+
472
+	/**
473
+	 * This sets the internal date format to what is sent in to be used as the new default for the class
474
+	 * internally instead of wp set date format options
475
+	 *
476
+	 * @since 4.6
477
+	 * @param string $format should be a format recognizable by PHP date() functions.
478
+	 */
479
+	public function set_date_format($format)
480
+	{
481
+		$this->_dt_frmt = $format;
482
+		//clear cached_properties because they won't be relevant now.
483
+		$this->_clear_cached_properties();
484
+	}
485
+
486
+
487
+
488
+	/**
489
+	 * This sets the internal time format string to what is sent in to be used as the new default for the
490
+	 * class internally instead of wp set time format options.
491
+	 *
492
+	 * @since 4.6
493
+	 * @param string $format should be a format recognizable by PHP date() functions.
494
+	 */
495
+	public function set_time_format($format)
496
+	{
497
+		$this->_tm_frmt = $format;
498
+		//clear cached_properties because they won't be relevant now.
499
+		$this->_clear_cached_properties();
500
+	}
501
+
502
+
503
+
504
+	/**
505
+	 * This returns the current internal set format for the date and time formats.
506
+	 *
507
+	 * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
508
+	 *                             where the first value is the date format and the second value is the time format.
509
+	 * @return mixed string|array
510
+	 */
511
+	public function get_format($full = true)
512
+	{
513
+		return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
514
+	}
515
+
516
+
517
+
518
+	/**
519
+	 * cache
520
+	 * stores the passed model object on the current model object.
521
+	 * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
522
+	 *
523
+	 * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
524
+	 *                                       'Registration' associated with this model object
525
+	 * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
526
+	 *                                       that could be a payment or a registration)
527
+	 * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
528
+	 *                                       items which will be stored in an array on this object
529
+	 * @throws EE_Error
530
+	 * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
531
+	 *                  related thing, no array)
532
+	 */
533
+	public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
534
+	{
535
+		// its entirely possible that there IS no related object yet in which case there is nothing to cache.
536
+		if ( ! $object_to_cache instanceof EE_Base_Class) {
537
+			return false;
538
+		}
539
+		// also get "how" the object is related, or throw an error
540
+		if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
541
+			throw new EE_Error(sprintf(__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
542
+				$relationName, get_class($this)));
543
+		}
544
+		// how many things are related ?
545
+		if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
546
+			// 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
547
+			// so for these model objects just set it to be cached
548
+			$this->_model_relations[$relationName] = $object_to_cache;
549
+			$return = true;
550
+		} else {
551
+			// 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.
552
+			// eg: if this is an event, there are many registrations for that event, so we cache the registrations in an array
553
+			if ( ! is_array($this->_model_relations[$relationName])) {
554
+				// if for some reason, the cached item is a model object, then stick that in the array, otherwise start with an empty array
555
+				$this->_model_relations[$relationName] = $this->_model_relations[$relationName] instanceof EE_Base_Class
556
+					? array($this->_model_relations[$relationName]) : array();
557
+			}
558
+			// first check for a cache_id which is normally empty
559
+			if ( ! empty($cache_id)) {
560
+				// 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
561
+				$this->_model_relations[$relationName][$cache_id] = $object_to_cache;
562
+				$return = $cache_id;
563
+			} elseif ($object_to_cache->ID()) {
564
+				// OR the cached object originally came from the db, so let's just use it's PK for an ID
565
+				$this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
566
+				$return = $object_to_cache->ID();
567
+			} else {
568
+				// OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
569
+				$this->_model_relations[$relationName][] = $object_to_cache;
570
+				// move the internal pointer to the end of the array
571
+				end($this->_model_relations[$relationName]);
572
+				// and grab the key so that we can return it
573
+				$return = key($this->_model_relations[$relationName]);
574
+			}
575
+		}
576
+		return $return;
577
+	}
578
+
579
+
580
+
581
+	/**
582
+	 * For adding an item to the cached_properties property.
583
+	 *
584
+	 * @access protected
585
+	 * @param string      $fieldname the property item the corresponding value is for.
586
+	 * @param mixed       $value     The value we are caching.
587
+	 * @param string|null $cache_type
588
+	 * @return void
589
+	 * @throws EE_Error
590
+	 */
591
+	protected function _set_cached_property($fieldname, $value, $cache_type = null)
592
+	{
593
+		//first make sure this property exists
594
+		$this->get_model()->field_settings_for($fieldname);
595
+		$cache_type = empty($cache_type) ? 'standard' : $cache_type;
596
+		$this->_cached_properties[$fieldname][$cache_type] = $value;
597
+	}
598
+
599
+
600
+
601
+	/**
602
+	 * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
603
+	 * This also SETS the cache if we return the actual property!
604
+	 *
605
+	 * @param string $fieldname        the name of the property we're trying to retrieve
606
+	 * @param bool   $pretty
607
+	 * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
608
+	 *                                 (in cases where the same property may be used for different outputs
609
+	 *                                 - i.e. datetime, money etc.)
610
+	 *                                 It can also accept certain pre-defined "schema" strings
611
+	 *                                 to define how to output the property.
612
+	 *                                 see the field's prepare_for_pretty_echoing for what strings can be used
613
+	 * @return mixed                   whatever the value for the property is we're retrieving
614
+	 * @throws EE_Error
615
+	 */
616
+	protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
617
+	{
618
+		//verify the field exists
619
+		$model = $this->get_model();
620
+		$model->field_settings_for($fieldname);
621
+		$cache_type = $pretty ? 'pretty' : 'standard';
622
+		$cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
623
+		if (isset($this->_cached_properties[$fieldname][$cache_type])) {
624
+			return $this->_cached_properties[$fieldname][$cache_type];
625
+		}
626
+		$value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
627
+		$this->_set_cached_property($fieldname, $value, $cache_type);
628
+		return $value;
629
+	}
630
+
631
+
632
+	/**
633
+	 * If the cache didn't fetch the needed item, this fetches it.
634
+	 * @param string $fieldname
635
+	 * @param bool $pretty
636
+	 * @param string $extra_cache_ref
637
+	 * @return mixed
638
+	 * @throws EE_Error
639
+	 */
640
+	protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
641
+	{
642
+		$field_obj = $this->get_model()->field_settings_for($fieldname);
643
+		// If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
644
+		if ($field_obj instanceof EE_Datetime_Field) {
645
+			$this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
646
+		}
647
+		if ( ! isset($this->_fields[$fieldname])) {
648
+			$this->_fields[$fieldname] = null;
649
+		}
650
+		$value = $pretty
651
+			? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
652
+			: $field_obj->prepare_for_get($this->_fields[$fieldname]);
653
+		return $value;
654
+	}
655
+
656
+
657
+	/**
658
+	 * set timezone, formats, and output for EE_Datetime_Field objects
659
+	 *
660
+	 * @param \EE_Datetime_Field $datetime_field
661
+	 * @param bool $pretty
662
+	 * @param null $date_or_time
663
+	 * @return void
664
+	 * @throws InvalidArgumentException
665
+	 * @throws InvalidInterfaceException
666
+	 * @throws InvalidDataTypeException
667
+	 * @throws EE_Error
668
+	 */
669
+	protected function _prepare_datetime_field(
670
+		EE_Datetime_Field $datetime_field,
671
+		$pretty = false,
672
+		$date_or_time = null
673
+	) {
674
+		$datetime_field->set_timezone($this->_timezone);
675
+		$datetime_field->set_date_format($this->_dt_frmt, $pretty);
676
+		$datetime_field->set_time_format($this->_tm_frmt, $pretty);
677
+		//set the output returned
678
+		switch ($date_or_time) {
679
+			case 'D' :
680
+				$datetime_field->set_date_time_output('date');
681
+				break;
682
+			case 'T' :
683
+				$datetime_field->set_date_time_output('time');
684
+				break;
685
+			default :
686
+				$datetime_field->set_date_time_output();
687
+		}
688
+	}
689
+
690
+
691
+
692
+	/**
693
+	 * This just takes care of clearing out the cached_properties
694
+	 *
695
+	 * @return void
696
+	 */
697
+	protected function _clear_cached_properties()
698
+	{
699
+		$this->_cached_properties = array();
700
+	}
701
+
702
+
703
+
704
+	/**
705
+	 * This just clears out ONE property if it exists in the cache
706
+	 *
707
+	 * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
708
+	 * @return void
709
+	 */
710
+	protected function _clear_cached_property($property_name)
711
+	{
712
+		if (isset($this->_cached_properties[$property_name])) {
713
+			unset($this->_cached_properties[$property_name]);
714
+		}
715
+	}
716
+
717
+
718
+
719
+	/**
720
+	 * Ensures that this related thing is a model object.
721
+	 *
722
+	 * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
723
+	 * @param string $model_name   name of the related thing, eg 'Attendee',
724
+	 * @return EE_Base_Class
725
+	 * @throws EE_Error
726
+	 */
727
+	protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
728
+	{
729
+		$other_model_instance = self::_get_model_instance_with_name(
730
+			self::_get_model_classname($model_name),
731
+			$this->_timezone
732
+		);
733
+		return $other_model_instance->ensure_is_obj($object_or_id);
734
+	}
735
+
736
+
737
+
738
+	/**
739
+	 * Forgets the cached model of the given relation Name. So the next time we request it,
740
+	 * we will fetch it again from the database. (Handy if you know it's changed somehow).
741
+	 * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
742
+	 * then only remove that one object from our cached array. Otherwise, clear the entire list
743
+	 *
744
+	 * @param string $relationName                         one of the keys in the _model_relations array on the model.
745
+	 *                                                     Eg 'Registration'
746
+	 * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
747
+	 *                                                     if you intend to use $clear_all = TRUE, or the relation only
748
+	 *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
749
+	 * @param bool   $clear_all                            This flags clearing the entire cache relation property if
750
+	 *                                                     this is HasMany or HABTM.
751
+	 * @throws EE_Error
752
+	 * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
753
+	 *                       relation from all
754
+	 */
755
+	public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
756
+	{
757
+		$relationship_to_model = $this->get_model()->related_settings_for($relationName);
758
+		$index_in_cache = '';
759
+		if ( ! $relationship_to_model) {
760
+			throw new EE_Error(
761
+				sprintf(
762
+					__("There is no relationship to %s on a %s. Cannot clear that cache", 'event_espresso'),
763
+					$relationName,
764
+					get_class($this)
765
+				)
766
+			);
767
+		}
768
+		if ($clear_all) {
769
+			$obj_removed = true;
770
+			$this->_model_relations[$relationName] = null;
771
+		} elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
772
+			$obj_removed = $this->_model_relations[$relationName];
773
+			$this->_model_relations[$relationName] = null;
774
+		} else {
775
+			if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
776
+				&& $object_to_remove_or_index_into_array->ID()
777
+			) {
778
+				$index_in_cache = $object_to_remove_or_index_into_array->ID();
779
+				if (is_array($this->_model_relations[$relationName])
780
+					&& ! isset($this->_model_relations[$relationName][$index_in_cache])
781
+				) {
782
+					$index_found_at = null;
783
+					//find this object in the array even though it has a different key
784
+					foreach ($this->_model_relations[$relationName] as $index => $obj) {
785
+						if (
786
+							$obj instanceof EE_Base_Class
787
+							&& (
788
+								$obj == $object_to_remove_or_index_into_array
789
+								|| $obj->ID() === $object_to_remove_or_index_into_array->ID()
790
+							)
791
+						) {
792
+							$index_found_at = $index;
793
+							break;
794
+						}
795
+					}
796
+					if ($index_found_at) {
797
+						$index_in_cache = $index_found_at;
798
+					} else {
799
+						//it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
800
+						//if it wasn't in it to begin with. So we're done
801
+						return $object_to_remove_or_index_into_array;
802
+					}
803
+				}
804
+			} elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
805
+				//so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
806
+				foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
807
+					if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
808
+						$index_in_cache = $index;
809
+					}
810
+				}
811
+			} else {
812
+				$index_in_cache = $object_to_remove_or_index_into_array;
813
+			}
814
+			//supposedly we've found it. But it could just be that the client code
815
+			//provided a bad index/object
816
+			if (
817
+			isset(
818
+				$this->_model_relations[$relationName],
819
+				$this->_model_relations[$relationName][$index_in_cache]
820
+			)
821
+			) {
822
+				$obj_removed = $this->_model_relations[$relationName][$index_in_cache];
823
+				unset($this->_model_relations[$relationName][$index_in_cache]);
824
+			} else {
825
+				//that thing was never cached anyways.
826
+				$obj_removed = null;
827
+			}
828
+		}
829
+		return $obj_removed;
830
+	}
831
+
832
+
833
+
834
+	/**
835
+	 * update_cache_after_object_save
836
+	 * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
837
+	 * obtained after being saved to the db
838
+	 *
839
+	 * @param string         $relationName       - the type of object that is cached
840
+	 * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
841
+	 * @param string         $current_cache_id   - the ID that was used when originally caching the object
842
+	 * @return boolean TRUE on success, FALSE on fail
843
+	 * @throws EE_Error
844
+	 */
845
+	public function update_cache_after_object_save(
846
+		$relationName,
847
+		EE_Base_Class $newly_saved_object,
848
+		$current_cache_id = ''
849
+	) {
850
+		// verify that incoming object is of the correct type
851
+		$obj_class = 'EE_' . $relationName;
852
+		if ($newly_saved_object instanceof $obj_class) {
853
+			/* @type EE_Base_Class $newly_saved_object */
854
+			// now get the type of relation
855
+			$relationship_to_model = $this->get_model()->related_settings_for($relationName);
856
+			// if this is a 1:1 relationship
857
+			if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
858
+				// then just replace the cached object with the newly saved object
859
+				$this->_model_relations[$relationName] = $newly_saved_object;
860
+				return true;
861
+				// or if it's some kind of sordid feral polyamorous relationship...
862
+			} elseif (is_array($this->_model_relations[$relationName])
863
+					  && isset($this->_model_relations[$relationName][$current_cache_id])
864
+			) {
865
+				// then remove the current cached item
866
+				unset($this->_model_relations[$relationName][$current_cache_id]);
867
+				// and cache the newly saved object using it's new ID
868
+				$this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
869
+				return true;
870
+			}
871
+		}
872
+		return false;
873
+	}
874
+
875
+
876
+
877
+	/**
878
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
879
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
880
+	 *
881
+	 * @param string $relationName
882
+	 * @return EE_Base_Class
883
+	 */
884
+	public function get_one_from_cache($relationName)
885
+	{
886
+		$cached_array_or_object = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName]
887
+			: null;
888
+		if (is_array($cached_array_or_object)) {
889
+			return array_shift($cached_array_or_object);
890
+		} else {
891
+			return $cached_array_or_object;
892
+		}
893
+	}
894
+
895
+
896
+	/**
897
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
898
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
899
+	 *
900
+	 * @param string $relationName
901
+	 * @throws \ReflectionException
902
+	 * @throws InvalidArgumentException
903
+	 * @throws InvalidInterfaceException
904
+	 * @throws InvalidDataTypeException
905
+	 * @throws EE_Error
906
+	 * @return EE_Base_Class[] NOT necessarily indexed by primary keys
907
+	 */
908
+	public function get_all_from_cache($relationName)
909
+	{
910
+		$objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
911
+		// if the result is not an array, but exists, make it an array
912
+		$objects = is_array($objects) ? $objects : array($objects);
913
+		//bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
914
+		//basically, if this model object was stored in the session, and these cached model objects
915
+		//already have IDs, let's make sure they're in their model's entity mapper
916
+		//otherwise we will have duplicates next time we call
917
+		// EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
918
+		$model = EE_Registry::instance()->load_model($relationName);
919
+		foreach ($objects as $model_object) {
920
+			if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
921
+				//ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
922
+				if ($model_object->ID()) {
923
+					$model->add_to_entity_map($model_object);
924
+				}
925
+			} else {
926
+				throw new EE_Error(
927
+					sprintf(
928
+						__(
929
+							'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
930
+							'event_espresso'
931
+						),
932
+						$relationName,
933
+						gettype($model_object)
934
+					)
935
+				);
936
+			}
937
+		}
938
+		return $objects;
939
+	}
940
+
941
+
942
+
943
+	/**
944
+	 * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
945
+	 * matching the given query conditions.
946
+	 *
947
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
948
+	 * @param int   $limit              How many objects to return.
949
+	 * @param array $query_params       Any additional conditions on the query.
950
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
951
+	 *                                  you can indicate just the columns you want returned
952
+	 * @return array|EE_Base_Class[]
953
+	 * @throws EE_Error
954
+	 */
955
+	public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
956
+	{
957
+		$model = $this->get_model();
958
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
959
+			? $model->get_primary_key_field()->get_name()
960
+			: $field_to_order_by;
961
+		$current_value = ! empty($field) ? $this->get($field) : null;
962
+		if (empty($field) || empty($current_value)) {
963
+			return array();
964
+		}
965
+		return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
966
+	}
967
+
968
+
969
+
970
+	/**
971
+	 * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
972
+	 * matching the given query conditions.
973
+	 *
974
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
975
+	 * @param int   $limit              How many objects to return.
976
+	 * @param array $query_params       Any additional conditions on the query.
977
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
978
+	 *                                  you can indicate just the columns you want returned
979
+	 * @return array|EE_Base_Class[]
980
+	 * @throws EE_Error
981
+	 */
982
+	public function previous_x(
983
+		$field_to_order_by = null,
984
+		$limit = 1,
985
+		$query_params = array(),
986
+		$columns_to_select = null
987
+	) {
988
+		$model = $this->get_model();
989
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
990
+			? $model->get_primary_key_field()->get_name()
991
+			: $field_to_order_by;
992
+		$current_value = ! empty($field) ? $this->get($field) : null;
993
+		if (empty($field) || empty($current_value)) {
994
+			return array();
995
+		}
996
+		return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
997
+	}
998
+
999
+
1000
+
1001
+	/**
1002
+	 * Returns the next EE_Base_Class object in sequence from this object as found in the database
1003
+	 * matching the given query conditions.
1004
+	 *
1005
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
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
1008
+	 *                                  you can indicate just the columns you want returned
1009
+	 * @return array|EE_Base_Class
1010
+	 * @throws EE_Error
1011
+	 */
1012
+	public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1013
+	{
1014
+		$model = $this->get_model();
1015
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
1016
+			? $model->get_primary_key_field()->get_name()
1017
+			: $field_to_order_by;
1018
+		$current_value = ! empty($field) ? $this->get($field) : null;
1019
+		if (empty($field) || empty($current_value)) {
1020
+			return array();
1021
+		}
1022
+		return $model->next($current_value, $field, $query_params, $columns_to_select);
1023
+	}
1024
+
1025
+
1026
+
1027
+	/**
1028
+	 * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1029
+	 * matching the given query conditions.
1030
+	 *
1031
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
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
1034
+	 *                                  you can indicate just the column you want returned
1035
+	 * @return array|EE_Base_Class
1036
+	 * @throws EE_Error
1037
+	 */
1038
+	public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1039
+	{
1040
+		$model = $this->get_model();
1041
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
1042
+			? $model->get_primary_key_field()->get_name()
1043
+			: $field_to_order_by;
1044
+		$current_value = ! empty($field) ? $this->get($field) : null;
1045
+		if (empty($field) || empty($current_value)) {
1046
+			return array();
1047
+		}
1048
+		return $model->previous($current_value, $field, $query_params, $columns_to_select);
1049
+	}
1050
+
1051
+
1052
+
1053
+	/**
1054
+	 * Overrides parent because parent expects old models.
1055
+	 * This also doesn't do any validation, and won't work for serialized arrays
1056
+	 *
1057
+	 * @param string $field_name
1058
+	 * @param mixed  $field_value_from_db
1059
+	 * @throws EE_Error
1060
+	 */
1061
+	public function set_from_db($field_name, $field_value_from_db)
1062
+	{
1063
+		$field_obj = $this->get_model()->field_settings_for($field_name);
1064
+		if ($field_obj instanceof EE_Model_Field_Base) {
1065
+			//you would think the DB has no NULLs for non-null label fields right? wrong!
1066
+			//eg, a CPT model object could have an entry in the posts table, but no
1067
+			//entry in the meta table. Meaning that all its columns in the meta table
1068
+			//are null! yikes! so when we find one like that, use defaults for its meta columns
1069
+			if ($field_value_from_db === null) {
1070
+				if ($field_obj->is_nullable()) {
1071
+					//if the field allows nulls, then let it be null
1072
+					$field_value = null;
1073
+				} else {
1074
+					$field_value = $field_obj->get_default_value();
1075
+				}
1076
+			} else {
1077
+				$field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1078
+			}
1079
+			$this->_fields[$field_name] = $field_value;
1080
+			$this->_clear_cached_property($field_name);
1081
+		}
1082
+	}
1083
+
1084
+
1085
+
1086
+	/**
1087
+	 * verifies that the specified field is of the correct type
1088
+	 *
1089
+	 * @param string $field_name
1090
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1091
+	 *                                (in cases where the same property may be used for different outputs
1092
+	 *                                - i.e. datetime, money etc.)
1093
+	 * @return mixed
1094
+	 * @throws EE_Error
1095
+	 */
1096
+	public function get($field_name, $extra_cache_ref = null)
1097
+	{
1098
+		return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1099
+	}
1100
+
1101
+
1102
+
1103
+	/**
1104
+	 * This method simply returns the RAW unprocessed value for the given property in this class
1105
+	 *
1106
+	 * @param  string $field_name A valid fieldname
1107
+	 * @return mixed              Whatever the raw value stored on the property is.
1108
+	 * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1109
+	 */
1110
+	public function get_raw($field_name)
1111
+	{
1112
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1113
+		switch(true){
1114
+			case $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime:
1115
+				$value = $this->_fields[$field_name]->format('U');
1116
+				break;
1117
+			case $field_settings instanceof EE_Money_Field && $this->_fields[$field_name] instanceof Money:
1118
+				$value = $this->_fields[$field_name]->floatAmount();
1119
+				break;
1120
+			default:
1121
+				$value = $this->_fields[$field_name];
1122
+		}
1123
+		return $value;
1124
+	}
1125
+
1126
+
1127
+
1128
+	/**
1129
+	 * This is used to return the internal DateTime object used for a field that is a
1130
+	 * EE_Datetime_Field.
1131
+	 *
1132
+	 * @param string $field_name               The field name retrieving the DateTime object.
1133
+	 * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1134
+	 * @throws EE_Error
1135
+	 *                                         an error is set and false returned.  If the field IS an
1136
+	 *                                         EE_Datetime_Field and but the field value is null, then
1137
+	 *                                         just null is returned (because that indicates that likely
1138
+	 *                                         this field is nullable).
1139
+	 */
1140
+	public function get_DateTime_object($field_name)
1141
+	{
1142
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1143
+		if ( ! $field_settings instanceof EE_Datetime_Field) {
1144
+			EE_Error::add_error(
1145
+				sprintf(
1146
+					__(
1147
+						'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1148
+						'event_espresso'
1149
+					),
1150
+					$field_name
1151
+				),
1152
+				__FILE__,
1153
+				__FUNCTION__,
1154
+				__LINE__
1155
+			);
1156
+			return false;
1157
+		}
1158
+		return $this->_fields[$field_name];
1159
+	}
1160
+
1161
+
1162
+
1163
+	/**
1164
+	 * Gets a Money object for the specified field. Please note that this should only be
1165
+	 * used for fields corresponding to EE_Money_Fields, and it will always return a money object,
1166
+	 * or else it will throw an exception.
1167
+	 *
1168
+	 * @param $field_name
1169
+	 * @return Money
1170
+	 * @throws InvalidEntityException
1171
+	 * @throws EE_Error
1172
+	 */
1173
+	public function getMoneyObject($field_name)
1174
+	{
1175
+		$field = $this->get_model()->field_settings_for($field_name);
1176
+		$value = isset($this->_fields[$field_name]) ? $this->_fields[$field_name] : null;
1177
+		if (! $field instanceof EE_Money_Field
1178
+			|| ! $value instanceof Money) {
1179
+			throw new InvalidEntityException(
1180
+				get_class($value),
1181
+				'Money',
1182
+				sprintf(
1183
+					esc_html__(
1184
+						// @codingStandardsIgnoreStart
1185
+						'Tried to retrieve money value from %1$s with ID %2$s from field %3$s but no money object present.',
1186
+						// @codingStandardsIgnoreEnd
1187
+						'event_espresso'
1188
+					),
1189
+					get_class($this),
1190
+					$this->ID(),
1191
+					$field_name
1192
+				)
1193
+			);
1194
+		}
1195
+		return $value;
1196
+	}
1197
+
1198
+
1199
+
1200
+	/**
1201
+	 * To be used in template to immediately echo out the value, and format it for output.
1202
+	 * Eg, should call stripslashes and whatnot before echoing
1203
+	 *
1204
+	 * @param string $field_name      the name of the field as it appears in the DB
1205
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1206
+	 *                                (in cases where the same property may be used for different outputs
1207
+	 *                                - i.e. datetime, money etc.)
1208
+	 * @return void
1209
+	 * @throws EE_Error
1210
+	 */
1211
+	public function e($field_name, $extra_cache_ref = null)
1212
+	{
1213
+		echo $this->get_pretty($field_name, $extra_cache_ref);
1214
+	}
1215
+
1216
+
1217
+
1218
+	/**
1219
+	 * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1220
+	 * can be easily used as the value of form input.
1221
+	 *
1222
+	 * @param string $field_name
1223
+	 * @return void
1224
+	 * @throws EE_Error
1225
+	 */
1226
+	public function f($field_name)
1227
+	{
1228
+		$this->e($field_name, 'form_input');
1229
+	}
1230
+
1231
+	/**
1232
+	 * Same as `f()` but just returns the value instead of echoing it
1233
+	 * @param string $field_name
1234
+	 * @return string
1235
+	 * @throws EE_Error
1236
+	 */
1237
+	public function get_f($field_name)
1238
+	{
1239
+		return (string)$this->get_pretty($field_name,'form_input');
1240
+	}
1241
+
1242
+
1243
+
1244
+	/**
1245
+	 * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1246
+	 * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1247
+	 * to see what options are available.
1248
+	 * @param string $field_name
1249
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1250
+	 *                                (in cases where the same property may be used for different outputs
1251
+	 *                                - i.e. datetime, money etc.)
1252
+	 * @return mixed
1253
+	 * @throws EE_Error
1254
+	 */
1255
+	public function get_pretty($field_name, $extra_cache_ref = null)
1256
+	{
1257
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1258
+	}
1259
+
1260
+
1261
+
1262
+	/**
1263
+	 * This simply returns the datetime for the given field name
1264
+	 * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1265
+	 * (and the equivalent e_date, e_time, e_datetime).
1266
+	 *
1267
+	 * @access   protected
1268
+	 * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1269
+	 * @param string   $dt_frmt      valid datetime format used for date
1270
+	 *                               (if '' then we just use the default on the field,
1271
+	 *                               if NULL we use the last-used format)
1272
+	 * @param string   $tm_frmt      Same as above except this is for time format
1273
+	 * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1274
+	 * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1275
+	 * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1276
+	 *                               if field is not a valid dtt field, or void if echoing
1277
+	 * @throws EE_Error
1278
+	 */
1279
+	protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1280
+	{
1281
+		// clear cached property
1282
+		$this->_clear_cached_property($field_name);
1283
+		//reset format properties because they are used in get()
1284
+		$this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1285
+		$this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1286
+		if ($echo) {
1287
+			$this->e($field_name, $date_or_time);
1288
+			return '';
1289
+		}
1290
+		return $this->get($field_name, $date_or_time);
1291
+	}
1292
+
1293
+
1294
+
1295
+	/**
1296
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1297
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1298
+	 * other echoes the pretty value for dtt)
1299
+	 *
1300
+	 * @param  string $field_name name of model object datetime field holding the value
1301
+	 * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1302
+	 * @return string            datetime value formatted
1303
+	 * @throws EE_Error
1304
+	 */
1305
+	public function get_date($field_name, $format = '')
1306
+	{
1307
+		return $this->_get_datetime($field_name, $format, null, 'D');
1308
+	}
1309
+
1310
+
1311
+
1312
+	/**
1313
+	 * @param      $field_name
1314
+	 * @param string $format
1315
+	 * @throws EE_Error
1316
+	 */
1317
+	public function e_date($field_name, $format = '')
1318
+	{
1319
+		$this->_get_datetime($field_name, $format, null, 'D', true);
1320
+	}
1321
+
1322
+
1323
+
1324
+	/**
1325
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1326
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1327
+	 * other echoes the pretty value for dtt)
1328
+	 *
1329
+	 * @param  string $field_name name of model object datetime field holding the value
1330
+	 * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1331
+	 * @return string             datetime value formatted
1332
+	 * @throws EE_Error
1333
+	 */
1334
+	public function get_time($field_name, $format = '')
1335
+	{
1336
+		return $this->_get_datetime($field_name, null, $format, 'T');
1337
+	}
1338
+
1339
+
1340
+
1341
+	/**
1342
+	 * @param      $field_name
1343
+	 * @param string $format
1344
+	 * @throws EE_Error
1345
+	 */
1346
+	public function e_time($field_name, $format = '')
1347
+	{
1348
+		$this->_get_datetime($field_name, null, $format, 'T', true);
1349
+	}
1350
+
1351
+
1352
+
1353
+	/**
1354
+	 * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1355
+	 * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1356
+	 * other echoes the pretty value for dtt)
1357
+	 *
1358
+	 * @param  string $field_name name of model object datetime field holding the value
1359
+	 * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1360
+	 * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1361
+	 * @return string             datetime value formatted
1362
+	 * @throws EE_Error
1363
+	 */
1364
+	public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1365
+	{
1366
+		return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1367
+	}
1368
+
1369
+
1370
+
1371
+	/**
1372
+	 * @param string $field_name
1373
+	 * @param string $dt_frmt
1374
+	 * @param string $tm_frmt
1375
+	 * @throws EE_Error
1376
+	 */
1377
+	public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1378
+	{
1379
+		$this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1380
+	}
1381
+
1382
+
1383
+	/**
1384
+	 * Get the i8ln value for a date using the WordPress @see date_i18n function.
1385
+	 *
1386
+	 * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1387
+	 * @param string $format PHP valid date/time string format.  If none is provided then the internal set format
1388
+	 *                           on the object will be used.
1389
+	 * @return string Date and time string in set locale or false if no field exists for the given
1390
+	 * @throws InvalidArgumentException
1391
+	 * @throws InvalidInterfaceException
1392
+	 * @throws InvalidDataTypeException
1393
+	 * @throws EE_Error
1394
+	 *                           field name.
1395
+	 */
1396
+	public function get_i18n_datetime($field_name, $format = '')
1397
+	{
1398
+		$format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1399
+		return date_i18n(
1400
+			$format,
1401
+			EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
1402
+		);
1403
+	}
1404
+
1405
+
1406
+
1407
+	/**
1408
+	 * This method validates whether the given field name is a valid field on the model object as well as it is of a
1409
+	 * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1410
+	 * thrown.
1411
+	 *
1412
+	 * @param  string $field_name The field name being checked
1413
+	 * @throws EE_Error
1414
+	 * @return EE_Datetime_Field
1415
+	 */
1416
+	protected function _get_dtt_field_settings($field_name)
1417
+	{
1418
+		$field = $this->get_model()->field_settings_for($field_name);
1419
+		//check if field is dtt
1420
+		if ($field instanceof EE_Datetime_Field) {
1421
+			return $field;
1422
+		} else {
1423
+			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',
1424
+				'event_espresso'), $field_name, self::_get_model_classname(get_class($this))));
1425
+		}
1426
+	}
1427
+
1428
+
1429
+
1430
+
1431
+	/**
1432
+	 * NOTE ABOUT BELOW:
1433
+	 * These convenience date and time setters are for setting date and time independently.  In other words you might
1434
+	 * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1435
+	 * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1436
+	 * method and make sure you send the entire datetime value for setting.
1437
+	 */
1438
+	/**
1439
+	 * sets the time on a datetime property
1440
+	 *
1441
+	 * @access protected
1442
+	 * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1443
+	 * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1444
+	 * @throws EE_Error
1445
+	 */
1446
+	protected function _set_time_for($time, $fieldname)
1447
+	{
1448
+		$this->_set_date_time('T', $time, $fieldname);
1449
+	}
1450
+
1451
+
1452
+
1453
+	/**
1454
+	 * sets the date on a datetime property
1455
+	 *
1456
+	 * @access protected
1457
+	 * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1458
+	 * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1459
+	 * @throws EE_Error
1460
+	 */
1461
+	protected function _set_date_for($date, $fieldname)
1462
+	{
1463
+		$this->_set_date_time('D', $date, $fieldname);
1464
+	}
1465
+
1466
+
1467
+	/**
1468
+	 * This takes care of setting a date or time independently on a given model object property. This method also
1469
+	 * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1470
+	 *
1471
+	 * @access protected
1472
+	 * @param string $what "T" for time, 'B' for both, 'D' for Date.
1473
+	 * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1474
+	 * @param string $fieldname the name of the field the date OR time is being set on (must match a
1475
+	 *                                        EE_Datetime_Field property)
1476
+	 * @throws InvalidArgumentException
1477
+	 * @throws InvalidInterfaceException
1478
+	 * @throws InvalidDataTypeException
1479
+	 * @throws EE_Error
1480
+	 */
1481
+	protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1482
+	{
1483
+		$field = $this->_get_dtt_field_settings($fieldname);
1484
+		$field->set_timezone($this->_timezone);
1485
+		$field->set_date_format($this->_dt_frmt);
1486
+		$field->set_time_format($this->_tm_frmt);
1487
+		switch ($what) {
1488
+			case 'T' :
1489
+				$this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1490
+					$datetime_value,
1491
+					$this->_fields[$fieldname]
1492
+				);
1493
+				break;
1494
+			case 'D' :
1495
+				$this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1496
+					$datetime_value,
1497
+					$this->_fields[$fieldname]
1498
+				);
1499
+				break;
1500
+			case 'B' :
1501
+				$this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1502
+				break;
1503
+		}
1504
+		$this->_clear_cached_property($fieldname);
1505
+	}
1506
+
1507
+
1508
+	/**
1509
+	 * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1510
+	 * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1511
+	 * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1512
+	 * that could lead to some unexpected results!
1513
+	 *
1514
+	 * @access public
1515
+	 * @param string $field_name This is the name of the field on the object that contains the date/time
1516
+	 *                                         value being returned.
1517
+	 * @param string $callback must match a valid method in this class (defaults to get_datetime)
1518
+	 * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1519
+	 * @param string $prepend You can include something to prepend on the timestamp
1520
+	 * @param string $append You can include something to append on the timestamp
1521
+	 * @throws InvalidArgumentException
1522
+	 * @throws InvalidInterfaceException
1523
+	 * @throws InvalidDataTypeException
1524
+	 * @throws EE_Error
1525
+	 * @return string timestamp
1526
+	 */
1527
+	public function display_in_my_timezone(
1528
+		$field_name,
1529
+		$callback = 'get_datetime',
1530
+		$args = null,
1531
+		$prepend = '',
1532
+		$append = ''
1533
+	) {
1534
+		$timezone = EEH_DTT_Helper::get_timezone();
1535
+		if ($timezone === $this->_timezone) {
1536
+			return '';
1537
+		}
1538
+		$original_timezone = $this->_timezone;
1539
+		$this->set_timezone($timezone);
1540
+		$fn = (array)$field_name;
1541
+		$args = array_merge($fn, (array)$args);
1542
+		if ( ! method_exists($this, $callback)) {
1543
+			throw new EE_Error(
1544
+				sprintf(
1545
+					__(
1546
+						'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1547
+						'event_espresso'
1548
+					),
1549
+					$callback
1550
+				)
1551
+			);
1552
+		}
1553
+		$args = (array)$args;
1554
+		$return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1555
+		$this->set_timezone($original_timezone);
1556
+		return $return;
1557
+	}
1558
+
1559
+
1560
+
1561
+	/**
1562
+	 * Deletes this model object.
1563
+	 * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1564
+	 * override
1565
+	 * `EE_Base_Class::_delete` NOT this class.
1566
+	 *
1567
+	 * @return boolean | int
1568
+	 * @throws EE_Error
1569
+	 */
1570
+	public function delete()
1571
+	{
1572
+		/**
1573
+		 * Called just before the `EE_Base_Class::_delete` method call.
1574
+		 * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1575
+		 * should be aware that `_delete` may not always result in a permanent delete.  For example, `EE_Soft_Delete_Base_Class::_delete`
1576
+		 * soft deletes (trash) the object and does not permanently delete it.
1577
+		 *
1578
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1579
+		 */
1580
+		do_action('AHEE__EE_Base_Class__delete__before', $this);
1581
+		$result = $this->_delete();
1582
+		/**
1583
+		 * Called just after the `EE_Base_Class::_delete` method call.
1584
+		 * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1585
+		 * should be aware that `_delete` may not always result in a permanent delete.  For example `EE_Soft_Base_Class::_delete`
1586
+		 * soft deletes (trash) the object and does not permanently delete it.
1587
+		 *
1588
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1589
+		 * @param boolean       $result
1590
+		 */
1591
+		do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1592
+		return $result;
1593
+	}
1594
+
1595
+
1596
+
1597
+	/**
1598
+	 * Calls the specific delete method for the instantiated class.
1599
+	 * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1600
+	 * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1601
+	 * `EE_Base_Class::delete`
1602
+	 *
1603
+	 * @return bool|int
1604
+	 * @throws EE_Error
1605
+	 */
1606
+	protected function _delete()
1607
+	{
1608
+		return $this->delete_permanently();
1609
+	}
1610
+
1611
+
1612
+
1613
+	/**
1614
+	 * Deletes this model object permanently from db (but keep in mind related models my block the delete and return an
1615
+	 * error)
1616
+	 *
1617
+	 * @return bool | int
1618
+	 * @throws EE_Error
1619
+	 */
1620
+	public function delete_permanently()
1621
+	{
1622
+		/**
1623
+		 * Called just before HARD deleting a model object
1624
+		 *
1625
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1626
+		 */
1627
+		do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1628
+		$model = $this->get_model();
1629
+		$result = $model->delete_permanently_by_ID($this->ID());
1630
+		$this->refresh_cache_of_related_objects();
1631
+		/**
1632
+		 * Called just after HARD deleting a model object
1633
+		 *
1634
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1635
+		 * @param boolean       $result
1636
+		 */
1637
+		do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1638
+		return $result;
1639
+	}
1640
+
1641
+
1642
+
1643
+	/**
1644
+	 * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1645
+	 * related model objects
1646
+	 *
1647
+	 * @throws EE_Error
1648
+	 */
1649
+	public function refresh_cache_of_related_objects()
1650
+	{
1651
+		$model = $this->get_model();
1652
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1653
+			if ( ! empty($this->_model_relations[$relation_name])) {
1654
+				$related_objects = $this->_model_relations[$relation_name];
1655
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
1656
+					//this relation only stores a single model object, not an array
1657
+					//but let's make it consistent
1658
+					$related_objects = array($related_objects);
1659
+				}
1660
+				foreach ($related_objects as $related_object) {
1661
+					//only refresh their cache if they're in memory
1662
+					if ($related_object instanceof EE_Base_Class) {
1663
+						$related_object->clear_cache($model->get_this_model_name(), $this);
1664
+					}
1665
+				}
1666
+			}
1667
+		}
1668
+	}
1669
+
1670
+
1671
+
1672
+	/**
1673
+	 *        Saves this object to the database. An array may be supplied to set some values on this
1674
+	 * object just before saving.
1675
+	 *
1676
+	 * @access public
1677
+	 * @param array $set_cols_n_values keys are field names, values are their new values,
1678
+	 *                                 if provided during the save() method (often client code will change the fields'
1679
+	 *                                 values before calling save)
1680
+	 * @throws EE_Error
1681
+	 * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1682
+	 *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1683
+	 */
1684
+	public function save($set_cols_n_values = array())
1685
+	{
1686
+		$model = $this->get_model();
1687
+		/**
1688
+		 * Filters the fields we're about to save on the model object
1689
+		 *
1690
+		 * @param array         $set_cols_n_values
1691
+		 * @param EE_Base_Class $model_object
1692
+		 */
1693
+		$set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1694
+			$this);
1695
+		//set attributes as provided in $set_cols_n_values
1696
+		foreach ($set_cols_n_values as $column => $value) {
1697
+			$this->set($column, $value);
1698
+		}
1699
+		// no changes ? then don't do anything
1700
+		if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1701
+			return 0;
1702
+		}
1703
+		/**
1704
+		 * Saving a model object.
1705
+		 * Before we perform a save, this action is fired.
1706
+		 *
1707
+		 * @param EE_Base_Class $model_object the model object about to be saved.
1708
+		 */
1709
+		do_action('AHEE__EE_Base_Class__save__begin', $this);
1710
+		if ( ! $this->allow_persist()) {
1711
+			return 0;
1712
+		}
1713
+		//now get current attribute values
1714
+		$save_cols_n_values = $this->_fields;
1715
+		//if the object already has an ID, update it. Otherwise, insert it
1716
+		//also: change the assumption about values passed to the model NOT being prepare dby the model object. They have been
1717
+		$old_assumption_concerning_value_preparation = $model
1718
+															->get_assumption_concerning_values_already_prepared_by_model_object();
1719
+		$model->assume_values_already_prepared_by_model_object(true);
1720
+		//does this model have an autoincrement PK?
1721
+		if ($model->has_primary_key_field()) {
1722
+			if ($model->get_primary_key_field()->is_auto_increment()) {
1723
+				//ok check if it's set, if so: update; if not, insert
1724
+				if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1725
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1726
+				} else {
1727
+					unset($save_cols_n_values[$model->primary_key_name()]);
1728
+					$results = $model->insert($save_cols_n_values);
1729
+					if ($results) {
1730
+						//if successful, set the primary key
1731
+						//but don't use the normal SET method, because it will check if
1732
+						//an item with the same ID exists in the mapper & db, then
1733
+						//will find it in the db (because we just added it) and THAT object
1734
+						//will get added to the mapper before we can add this one!
1735
+						//but if we just avoid using the SET method, all that headache can be avoided
1736
+						$pk_field_name = $model->primary_key_name();
1737
+						$this->_fields[$pk_field_name] = $results;
1738
+						$this->_clear_cached_property($pk_field_name);
1739
+						$model->add_to_entity_map($this);
1740
+						$this->_update_cached_related_model_objs_fks();
1741
+					}
1742
+				}
1743
+			} else {//PK is NOT auto-increment
1744
+				//so check if one like it already exists in the db
1745
+				if ($model->exists_by_ID($this->ID())) {
1746
+					if (WP_DEBUG && ! $this->in_entity_map()) {
1747
+						throw new EE_Error(
1748
+							sprintf(
1749
+								__('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',
1750
+									'event_espresso'),
1751
+								get_class($this),
1752
+								get_class($model) . '::instance()->add_to_entity_map()',
1753
+								get_class($model) . '::instance()->get_one_by_ID()',
1754
+								'<br />'
1755
+							)
1756
+						);
1757
+					}
1758
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1759
+				} else {
1760
+					$results = $model->insert($save_cols_n_values);
1761
+					$this->_update_cached_related_model_objs_fks();
1762
+				}
1763
+			}
1764
+		} else {//there is NO primary key
1765
+			$already_in_db = false;
1766
+			foreach ($model->unique_indexes() as $index) {
1767
+				$uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1768
+				if ($model->exists(array($uniqueness_where_params))) {
1769
+					$already_in_db = true;
1770
+				}
1771
+			}
1772
+			if ($already_in_db) {
1773
+				$combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1774
+					$model->get_combined_primary_key_fields());
1775
+				$results = $model->update($save_cols_n_values, $combined_pk_fields_n_values);
1776
+			} else {
1777
+				$results = $model->insert($save_cols_n_values);
1778
+			}
1779
+		}
1780
+		//restore the old assumption about values being prepared by the model object
1781
+		$model
1782
+			 ->assume_values_already_prepared_by_model_object($old_assumption_concerning_value_preparation);
1783
+		/**
1784
+		 * After saving the model object this action is called
1785
+		 *
1786
+		 * @param EE_Base_Class $model_object which was just saved
1787
+		 * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1788
+		 *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1789
+		 */
1790
+		do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1791
+		$this->_has_changes = false;
1792
+		return $results;
1793
+	}
1794
+
1795
+
1796
+
1797
+	/**
1798
+	 * Updates the foreign key on related models objects pointing to this to have this model object's ID
1799
+	 * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1800
+	 * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1801
+	 * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1802
+	 * 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
1803
+	 * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1804
+	 * or not they exist in the DB (if they do, their DB records will be automatically updated)
1805
+	 *
1806
+	 * @return void
1807
+	 * @throws EE_Error
1808
+	 */
1809
+	protected function _update_cached_related_model_objs_fks()
1810
+	{
1811
+		$model = $this->get_model();
1812
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1813
+			if ($relation_obj instanceof EE_Has_Many_Relation) {
1814
+				foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1815
+					$fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1816
+						$model->get_this_model_name()
1817
+					);
1818
+					$related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1819
+					if ($related_model_obj_in_cache->ID()) {
1820
+						$related_model_obj_in_cache->save();
1821
+					}
1822
+				}
1823
+			}
1824
+		}
1825
+	}
1826
+
1827
+
1828
+
1829
+	/**
1830
+	 * Saves this model object and its NEW cached relations to the database.
1831
+	 * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1832
+	 * In order for that to work, we would need to mark model objects as dirty/clean...
1833
+	 * because otherwise, there's a potential for infinite looping of saving
1834
+	 * Saves the cached related model objects, and ensures the relation between them
1835
+	 * and this object and properly setup
1836
+	 *
1837
+	 * @return int ID of new model object on save; 0 on failure+
1838
+	 * @throws EE_Error
1839
+	 */
1840
+	public function save_new_cached_related_model_objs()
1841
+	{
1842
+		//make sure this has been saved
1843
+		if ( ! $this->ID()) {
1844
+			$id = $this->save();
1845
+		} else {
1846
+			$id = $this->ID();
1847
+		}
1848
+		//now save all the NEW cached model objects  (ie they don't exist in the DB)
1849
+		foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1850
+			if ($this->_model_relations[$relationName]) {
1851
+				//is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1852
+				//or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1853
+				if ($relationObj instanceof EE_Belongs_To_Relation) {
1854
+					//add a relation to that relation type (which saves the appropriate thing in the process)
1855
+					//but ONLY if it DOES NOT exist in the DB
1856
+					/* @var $related_model_obj EE_Base_Class */
1857
+					$related_model_obj = $this->_model_relations[$relationName];
1858
+					//					if( ! $related_model_obj->ID()){
1859
+					$this->_add_relation_to($related_model_obj, $relationName);
1860
+					$related_model_obj->save_new_cached_related_model_objs();
1861
+					//					}
1862
+				} else {
1863
+					foreach ($this->_model_relations[$relationName] as $related_model_obj) {
1864
+						//add a relation to that relation type (which saves the appropriate thing in the process)
1865
+						//but ONLY if it DOES NOT exist in the DB
1866
+						//						if( ! $related_model_obj->ID()){
1867
+						$this->_add_relation_to($related_model_obj, $relationName);
1868
+						$related_model_obj->save_new_cached_related_model_objs();
1869
+						//						}
1870
+					}
1871
+				}
1872
+			}
1873
+		}
1874
+		return $id;
1875
+	}
1876
+
1877
+
1878
+
1879
+	/**
1880
+	 * for getting a model while instantiated.
1881
+	 *
1882
+	 * @return EEM_Base | EEM_CPT_Base
1883
+	 */
1884
+	public function get_model()
1885
+	{
1886
+		if( ! $this->_model){
1887
+			$modelName = self::_get_model_classname(get_class($this));
1888
+			$this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1889
+		} else {
1890
+			$this->_model->set_timezone($this->_timezone);
1891
+		}
1892
+
1893
+		return $this->_model;
1894
+	}
1895
+
1896
+
1897
+
1898
+	/**
1899
+	 * @param $props_n_values
1900
+	 * @param $classname
1901
+	 * @return mixed bool|EE_Base_Class|EEM_CPT_Base
1902
+	 * @throws EE_Error
1903
+	 */
1904
+	protected static function _get_object_from_entity_mapper($props_n_values, $classname)
1905
+	{
1906
+		//TODO: will not work for Term_Relationships because they have no PK!
1907
+		$primary_id_ref = self::_get_primary_key_name($classname);
1908
+		if (array_key_exists($primary_id_ref, $props_n_values) && ! empty($props_n_values[$primary_id_ref])) {
1909
+			$id = $props_n_values[$primary_id_ref];
1910
+			return self::_get_model($classname)->get_from_entity_map($id);
1911
+		}
1912
+		return false;
1913
+	}
1914
+
1915
+
1916
+
1917
+	/**
1918
+	 * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
1919
+	 * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
1920
+	 * 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
1921
+	 * we return false.
1922
+	 *
1923
+	 * @param  array  $props_n_values   incoming array of properties and their values
1924
+	 * @param  string $classname        the classname of the child class
1925
+	 * @param null    $timezone
1926
+	 * @param array   $date_formats     incoming date_formats in an array where the first value is the
1927
+	 *                                  date_format and the second value is the time format
1928
+	 * @return mixed (EE_Base_Class|bool)
1929
+	 * @throws EE_Error
1930
+	 */
1931
+	protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
1932
+	{
1933
+		$existing = null;
1934
+		$model = self::_get_model($classname, $timezone);
1935
+		if ($model->has_primary_key_field()) {
1936
+			$primary_id_ref = self::_get_primary_key_name($classname);
1937
+			if (array_key_exists($primary_id_ref, $props_n_values)
1938
+				&& ! empty($props_n_values[$primary_id_ref])
1939
+			) {
1940
+				$existing = $model->get_one_by_ID(
1941
+					$props_n_values[$primary_id_ref]
1942
+				);
1943
+			}
1944
+		} elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
1945
+			//no primary key on this model, but there's still a matching item in the DB
1946
+			$existing = self::_get_model($classname, $timezone)->get_one_by_ID(
1947
+				self::_get_model($classname, $timezone)->get_index_primary_key_string($props_n_values)
1948
+			);
1949
+		}
1950
+		if ($existing) {
1951
+			//set date formats if present before setting values
1952
+			if ( ! empty($date_formats) && is_array($date_formats)) {
1953
+				$existing->set_date_format($date_formats[0]);
1954
+				$existing->set_time_format($date_formats[1]);
1955
+			} else {
1956
+				//set default formats for date and time
1957
+				$existing->set_date_format(get_option('date_format'));
1958
+				$existing->set_time_format(get_option('time_format'));
1959
+			}
1960
+			foreach ($props_n_values as $property => $field_value) {
1961
+				$existing->set($property, $field_value);
1962
+			}
1963
+			return $existing;
1964
+		} else {
1965
+			return false;
1966
+		}
1967
+	}
1968
+
1969
+
1970
+
1971
+	/**
1972
+	 * Gets the EEM_*_Model for this class
1973
+	 *
1974
+	 * @access public now, as this is more convenient
1975
+	 * @param      $classname
1976
+	 * @param null $timezone
1977
+	 * @throws EE_Error
1978
+	 * @return EEM_Base
1979
+	 */
1980
+	protected static function _get_model($classname, $timezone = null)
1981
+	{
1982
+		//find model for this class
1983
+		if ( ! $classname) {
1984
+			throw new EE_Error(
1985
+				sprintf(
1986
+					__(
1987
+						"What were you thinking calling _get_model(%s)?? You need to specify the class name",
1988
+						"event_espresso"
1989
+					),
1990
+					$classname
1991
+				)
1992
+			);
1993
+		}
1994
+		$modelName = self::_get_model_classname($classname);
1995
+		return self::_get_model_instance_with_name($modelName, $timezone);
1996
+	}
1997
+
1998
+
1999
+	/**
2000
+	 * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2001
+	 *
2002
+	 * @param string $model_classname
2003
+	 * @param null $timezone
2004
+	 * @return EEM_Base
2005
+	 * @throws \ReflectionException
2006
+	 * @throws InvalidArgumentException
2007
+	 * @throws InvalidInterfaceException
2008
+	 * @throws InvalidDataTypeException
2009
+	 * @throws EE_Error
2010
+	 */
2011
+	protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2012
+	{
2013
+		$model_classname = str_replace('EEM_', '', $model_classname);
2014
+		$model = EE_Registry::instance()->load_model($model_classname);
2015
+		$model->set_timezone($timezone);
2016
+		return $model;
2017
+	}
2018
+
2019
+
2020
+
2021
+	/**
2022
+	 * If a model name is provided (eg Registration), gets the model classname for that model.
2023
+	 * Also works if a model class's classname is provided (eg EE_Registration).
2024
+	 *
2025
+	 * @param null $model_name
2026
+	 * @return string like EEM_Attendee
2027
+	 */
2028
+	private static function _get_model_classname($model_name = null)
2029
+	{
2030
+		if (strpos($model_name, "EE_") === 0) {
2031
+			$model_classname = str_replace("EE_", "EEM_", $model_name);
2032
+		} else {
2033
+			$model_classname = "EEM_" . $model_name;
2034
+		}
2035
+		return $model_classname;
2036
+	}
2037
+
2038
+
2039
+
2040
+	/**
2041
+	 * returns the name of the primary key attribute
2042
+	 *
2043
+	 * @param null $classname
2044
+	 * @throws EE_Error
2045
+	 * @return string
2046
+	 */
2047
+	protected static function _get_primary_key_name($classname = null)
2048
+	{
2049
+		if ( ! $classname) {
2050
+			throw new EE_Error(
2051
+				sprintf(
2052
+					__("What were you thinking calling _get_primary_key_name(%s)", "event_espresso"),
2053
+					$classname
2054
+				)
2055
+			);
2056
+		}
2057
+		return self::_get_model($classname)->get_primary_key_field()->get_name();
2058
+	}
2059
+
2060
+
2061
+
2062
+	/**
2063
+	 * Gets the value of the primary key.
2064
+	 * If the object hasn't yet been saved, it should be whatever the model field's default was
2065
+	 * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2066
+	 * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2067
+	 *
2068
+	 * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2069
+	 * @throws EE_Error
2070
+	 */
2071
+	public function ID()
2072
+	{
2073
+		$model = $this->get_model();
2074
+		//now that we know the name of the variable, use a variable variable to get its value and return its
2075
+		if ($model->has_primary_key_field()) {
2076
+			return $this->_fields[$model->primary_key_name()];
2077
+		} else {
2078
+			return $model->get_index_primary_key_string($this->_fields);
2079
+		}
2080
+	}
2081
+
2082
+
2083
+
2084
+	/**
2085
+	 * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2086
+	 * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2087
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2088
+	 *
2089
+	 * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2090
+	 * @param string $relationName                     eg 'Events','Question',etc.
2091
+	 *                                                 an attendee to a group, you also want to specify which role they
2092
+	 *                                                 will have in that group. So you would use this parameter to
2093
+	 *                                                 specify array('role-column-name'=>'role-id')
2094
+	 * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2095
+	 *                                                 allow you to further constrict the relation to being added.
2096
+	 *                                                 However, keep in mind that the columns (keys) given must match a
2097
+	 *                                                 column on the JOIN table and currently only the HABTM models
2098
+	 *                                                 accept these additional conditions.  Also remember that if an
2099
+	 *                                                 exact match isn't found for these extra cols/val pairs, then a
2100
+	 *                                                 NEW row is created in the join table.
2101
+	 * @param null   $cache_id
2102
+	 * @throws EE_Error
2103
+	 * @return EE_Base_Class the object the relation was added to
2104
+	 */
2105
+	public function _add_relation_to(
2106
+		$otherObjectModelObjectOrID,
2107
+		$relationName,
2108
+		$extra_join_model_fields_n_values = array(),
2109
+		$cache_id = null
2110
+	) {
2111
+		$model = $this->get_model();
2112
+		//if this thing exists in the DB, save the relation to the DB
2113
+		if ($this->ID()) {
2114
+			$otherObject = $model
2115
+								->add_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2116
+									$extra_join_model_fields_n_values);
2117
+			//clear cache so future get_many_related and get_first_related() return new results.
2118
+			$this->clear_cache($relationName, $otherObject, true);
2119
+			if ($otherObject instanceof EE_Base_Class) {
2120
+				$otherObject->clear_cache($model->get_this_model_name(), $this);
2121
+			}
2122
+		} else {
2123
+			//this thing doesn't exist in the DB,  so just cache it
2124
+			if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2125
+				throw new EE_Error(sprintf(
2126
+					__('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',
2127
+						'event_espresso'),
2128
+					$otherObjectModelObjectOrID,
2129
+					get_class($this)
2130
+				));
2131
+			} else {
2132
+				$otherObject = $otherObjectModelObjectOrID;
2133
+			}
2134
+			$this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2135
+		}
2136
+		if ($otherObject instanceof EE_Base_Class) {
2137
+			//fix the reciprocal relation too
2138
+			if ($otherObject->ID()) {
2139
+				//its saved so assumed relations exist in the DB, so we can just
2140
+				//clear the cache so future queries use the updated info in the DB
2141
+				$otherObject->clear_cache($model->get_this_model_name(), null, true);
2142
+			} else {
2143
+				//it's not saved, so it caches relations like this
2144
+				$otherObject->cache($model->get_this_model_name(), $this);
2145
+			}
2146
+		}
2147
+		return $otherObject;
2148
+	}
2149
+
2150
+
2151
+
2152
+	/**
2153
+	 * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2154
+	 * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2155
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2156
+	 * from the cache
2157
+	 *
2158
+	 * @param mixed  $otherObjectModelObjectOrID
2159
+	 *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2160
+	 *                to the DB yet
2161
+	 * @param string $relationName
2162
+	 * @param array  $where_query
2163
+	 *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2164
+	 *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2165
+	 *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2166
+	 *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2167
+	 *                created in the join table.
2168
+	 * @return EE_Base_Class the relation was removed from
2169
+	 * @throws EE_Error
2170
+	 */
2171
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2172
+	{
2173
+		if ($this->ID()) {
2174
+			//if this exists in the DB, save the relation change to the DB too
2175
+			$otherObject = $this->get_model()
2176
+								->remove_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2177
+									$where_query);
2178
+			$this->clear_cache($relationName, $otherObject);
2179
+		} else {
2180
+			//this doesn't exist in the DB, just remove it from the cache
2181
+			$otherObject = $this->clear_cache($relationName, $otherObjectModelObjectOrID);
2182
+		}
2183
+		if ($otherObject instanceof EE_Base_Class) {
2184
+			$otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2185
+		}
2186
+		return $otherObject;
2187
+	}
2188
+
2189
+
2190
+
2191
+	/**
2192
+	 * Removes ALL the related things for the $relationName.
2193
+	 *
2194
+	 * @param string $relationName
2195
+	 * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2196
+	 * @return EE_Base_Class
2197
+	 * @throws EE_Error
2198
+	 */
2199
+	public function _remove_relations($relationName, $where_query_params = array())
2200
+	{
2201
+		if ($this->ID()) {
2202
+			//if this exists in the DB, save the relation change to the DB too
2203
+			$otherObjects = $this->get_model()->remove_relations($this, $relationName, $where_query_params);
2204
+			$this->clear_cache($relationName, null, true);
2205
+		} else {
2206
+			//this doesn't exist in the DB, just remove it from the cache
2207
+			$otherObjects = $this->clear_cache($relationName, null, true);
2208
+		}
2209
+		if (is_array($otherObjects)) {
2210
+			foreach ($otherObjects as $otherObject) {
2211
+				$otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2212
+			}
2213
+		}
2214
+		return $otherObjects;
2215
+	}
2216
+
2217
+
2218
+
2219
+	/**
2220
+	 * Gets all the related model objects of the specified type. Eg, if the current class if
2221
+	 * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2222
+	 * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2223
+	 * because we want to get even deleted items etc.
2224
+	 *
2225
+	 * @param string $relationName key in the model's _model_relations array
2226
+	 * @param array  $query_params like EEM_Base::get_all
2227
+	 * @return EE_Base_Class[] Results not necessarily indexed by IDs, because some results might not have primary keys
2228
+	 * @throws EE_Error
2229
+	 *                             or might not be saved yet. Consider using EEM_Base::get_IDs() on these results if
2230
+	 *                             you want IDs
2231
+	 */
2232
+	public function get_many_related($relationName, $query_params = array())
2233
+	{
2234
+		if ($this->ID()) {
2235
+			//this exists in the DB, so get the related things from either the cache or the DB
2236
+			//if there are query parameters, forget about caching the related model objects.
2237
+			if ($query_params) {
2238
+				$related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2239
+			} else {
2240
+				//did we already cache the result of this query?
2241
+				$cached_results = $this->get_all_from_cache($relationName);
2242
+				if ( ! $cached_results) {
2243
+					$related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2244
+					//if no query parameters were passed, then we got all the related model objects
2245
+					//for that relation. We can cache them then.
2246
+					foreach ($related_model_objects as $related_model_object) {
2247
+						$this->cache($relationName, $related_model_object);
2248
+					}
2249
+				} else {
2250
+					$related_model_objects = $cached_results;
2251
+				}
2252
+			}
2253
+		} else {
2254
+			//this doesn't exist in the DB, so just get the related things from the cache
2255
+			$related_model_objects = $this->get_all_from_cache($relationName);
2256
+		}
2257
+		return $related_model_objects;
2258
+	}
2259
+
2260
+
2261
+	/**
2262
+	 * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2263
+	 * unless otherwise specified in the $query_params
2264
+	 *
2265
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2266
+	 * @param array $query_params like EEM_Base::get_all's
2267
+	 * @param string $field_to_count name of field to count by. By default, uses primary key
2268
+	 * @param bool $distinct if we want to only count the distinct values for the column then you can trigger
2269
+	 *                               that by the setting $distinct to TRUE;
2270
+	 * @return int
2271
+	 * @throws EE_Error
2272
+	 */
2273
+	public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2274
+	{
2275
+		return $this->get_model()->count_related($this, $relation_name, $query_params, $field_to_count, $distinct);
2276
+	}
2277
+
2278
+
2279
+	/**
2280
+	 * Instead of getting the related model objects, simply sums up the values of the specified field.
2281
+	 * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2282
+	 *
2283
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2284
+	 * @param array $query_params like EEM_Base::get_all's
2285
+	 * @param string $field_to_sum name of field to count by.
2286
+	 *                              By default, uses primary key (which doesn't make much sense, so you should probably
2287
+	 *                              change it)
2288
+	 * @return int
2289
+	 * @throws EE_Error
2290
+	 */
2291
+	public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2292
+	{
2293
+		return $this->get_model()->sum_related($this, $relation_name, $query_params, $field_to_sum);
2294
+	}
2295
+
2296
+
2297
+
2298
+	/**
2299
+	 * Gets the first (ie, one) related model object of the specified type.
2300
+	 *
2301
+	 * @param string $relationName key in the model's _model_relations array
2302
+	 * @param array  $query_params like EEM_Base::get_all
2303
+	 * @return EE_Base_Class (not an array, a single object)
2304
+	 * @throws EE_Error
2305
+	 */
2306
+	public function get_first_related($relationName, $query_params = array())
2307
+	{
2308
+		$model = $this->get_model();
2309
+		if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2310
+			//if they've provided some query parameters, don't bother trying to cache the result
2311
+			//also make sure we're not caching the result of get_first_related
2312
+			//on a relation which should have an array of objects (because the cache might have an array of objects)
2313
+			if ($query_params
2314
+				|| ! $model->related_settings_for($relationName)
2315
+					 instanceof
2316
+					 EE_Belongs_To_Relation
2317
+			) {
2318
+				$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2319
+			} else {
2320
+				//first, check if we've already cached the result of this query
2321
+				$cached_result = $this->get_one_from_cache($relationName);
2322
+				if ( ! $cached_result) {
2323
+					$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2324
+					$this->cache($relationName, $related_model_object);
2325
+				} else {
2326
+					$related_model_object = $cached_result;
2327
+				}
2328
+			}
2329
+		} else {
2330
+			$related_model_object = null;
2331
+			//this doesn't exist in the Db, but maybe the relation is of type belongs to, and so the related thing might
2332
+			if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2333
+				$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2334
+			}
2335
+			//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
2336
+			if ( ! $related_model_object) {
2337
+				$related_model_object = $this->get_one_from_cache($relationName);
2338
+			}
2339
+		}
2340
+		return $related_model_object;
2341
+	}
2342
+
2343
+
2344
+
2345
+	/**
2346
+	 * Does a delete on all related objects of type $relationName and removes
2347
+	 * the current model object's relation to them. If they can't be deleted (because
2348
+	 * of blocking related model objects) does nothing. If the related model objects are
2349
+	 * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2350
+	 * If this model object doesn't exist yet in the DB, just removes its related things
2351
+	 *
2352
+	 * @param string $relationName
2353
+	 * @param array  $query_params like EEM_Base::get_all's
2354
+	 * @return int how many deleted
2355
+	 * @throws EE_Error
2356
+	 */
2357
+	public function delete_related($relationName, $query_params = array())
2358
+	{
2359
+		if ($this->ID()) {
2360
+			$count = $this->get_model()->delete_related($this, $relationName, $query_params);
2361
+		} else {
2362
+			$count = count($this->get_all_from_cache($relationName));
2363
+			$this->clear_cache($relationName, null, true);
2364
+		}
2365
+		return $count;
2366
+	}
2367
+
2368
+
2369
+
2370
+	/**
2371
+	 * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2372
+	 * the current model object's relation to them. If they can't be deleted (because
2373
+	 * of blocking related model objects) just does a soft delete on it instead, if possible.
2374
+	 * If the related thing isn't a soft-deletable model object, this function is identical
2375
+	 * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2376
+	 *
2377
+	 * @param string $relationName
2378
+	 * @param array  $query_params like EEM_Base::get_all's
2379
+	 * @return int how many deleted (including those soft deleted)
2380
+	 * @throws EE_Error
2381
+	 */
2382
+	public function delete_related_permanently($relationName, $query_params = array())
2383
+	{
2384
+		if ($this->ID()) {
2385
+			$count = $this->get_model()->delete_related_permanently($this, $relationName, $query_params);
2386
+		} else {
2387
+			$count = count($this->get_all_from_cache($relationName));
2388
+		}
2389
+		$this->clear_cache($relationName, null, true);
2390
+		return $count;
2391
+	}
2392
+
2393
+
2394
+
2395
+	/**
2396
+	 * is_set
2397
+	 * Just a simple utility function children can use for checking if property exists
2398
+	 *
2399
+	 * @access  public
2400
+	 * @param  string $field_name property to check
2401
+	 * @return bool                              TRUE if existing,FALSE if not.
2402
+	 */
2403
+	public function is_set($field_name)
2404
+	{
2405
+		return isset($this->_fields[$field_name]);
2406
+	}
2407
+
2408
+
2409
+
2410
+	/**
2411
+	 * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2412
+	 * EE_Error exception if they don't
2413
+	 *
2414
+	 * @param  mixed (string|array) $properties properties to check
2415
+	 * @throws EE_Error
2416
+	 * @return bool                              TRUE if existing, throw EE_Error if not.
2417
+	 */
2418
+	protected function _property_exists($properties)
2419
+	{
2420
+		foreach ((array)$properties as $property_name) {
2421
+			//first make sure this property exists
2422
+			if ( ! $this->_fields[$property_name]) {
2423
+				throw new EE_Error(
2424
+					sprintf(
2425
+						__(
2426
+							'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2427
+							'event_espresso'
2428
+						),
2429
+						$property_name
2430
+					)
2431
+				);
2432
+			}
2433
+		}
2434
+		return true;
2435
+	}
2436
+
2437
+
2438
+
2439
+	/**
2440
+	 * This simply returns an array of model fields for this object
2441
+	 *
2442
+	 * @return array
2443
+	 * @throws EE_Error
2444
+	 */
2445
+	public function model_field_array()
2446
+	{
2447
+		$fields = $this->get_model()->field_settings(false);
2448
+		$properties = array();
2449
+		//remove prepended underscore
2450
+		foreach ($fields as $field_name => $settings) {
2451
+			$properties[$field_name] = $this->get($field_name);
2452
+		}
2453
+		return $properties;
2454
+	}
2455
+
2456
+
2457
+
2458
+	/**
2459
+	 * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2460
+	 * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2461
+	 * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
2462
+	 * requiring a plugin to extend the EE_Base_Class (which works fine is there's only 1 plugin, but when will that
2463
+	 * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
2464
+	 * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
2465
+	 * was called, and an array of the original arguments passed to the function. Whatever their callback function
2466
+	 * returns will be returned by this function. Example: in functions.php (or in a plugin):
2467
+	 * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
2468
+	 * my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2469
+	 * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2470
+	 *        return $previousReturnValue.$returnString;
2471
+	 * }
2472
+	 * require('EE_Answer.class.php');
2473
+	 * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2474
+	 * echo $answer->my_callback('monkeys',100);
2475
+	 * //will output "you called my_callback! and passed args:monkeys,100"
2476
+	 *
2477
+	 * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2478
+	 * @param array  $args       array of original arguments passed to the function
2479
+	 * @throws EE_Error
2480
+	 * @return mixed whatever the plugin which calls add_filter decides
2481
+	 */
2482
+	public function __call($methodName, $args)
2483
+	{
2484
+		$className = get_class($this);
2485
+		$tagName = "FHEE__{$className}__{$methodName}";
2486
+		if ( ! has_filter($tagName)) {
2487
+			throw new EE_Error(
2488
+				sprintf(
2489
+					__(
2490
+						"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;}",
2491
+						"event_espresso"
2492
+					),
2493
+					$methodName,
2494
+					$className,
2495
+					$tagName
2496
+				)
2497
+			);
2498
+		}
2499
+		return apply_filters($tagName, null, $this, $args);
2500
+	}
2501
+
2502
+
2503
+	/**
2504
+	 * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2505
+	 * A $previous_value can be specified in case there are many meta rows with the same key
2506
+	 *
2507
+	 * @param string $meta_key
2508
+	 * @param mixed $meta_value
2509
+	 * @param mixed $previous_value
2510
+	 * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2511
+	 * @throws InvalidArgumentException
2512
+	 * @throws InvalidInterfaceException
2513
+	 * @throws InvalidDataTypeException
2514
+	 * @throws EE_Error
2515
+	 * NOTE: if the values haven't changed, returns 0
2516
+	 */
2517
+	public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2518
+	{
2519
+		$query_params = array(
2520
+			array(
2521
+				'EXM_key'  => $meta_key,
2522
+				'OBJ_ID'   => $this->ID(),
2523
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2524
+			),
2525
+		);
2526
+		if ($previous_value !== null) {
2527
+			$query_params[0]['EXM_value'] = $meta_value;
2528
+		}
2529
+		$existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2530
+		if ( ! $existing_rows_like_that) {
2531
+			return $this->add_extra_meta($meta_key, $meta_value);
2532
+		}
2533
+		foreach ($existing_rows_like_that as $existing_row) {
2534
+			$existing_row->save(array('EXM_value' => $meta_value));
2535
+		}
2536
+		return count($existing_rows_like_that);
2537
+	}
2538
+
2539
+
2540
+	/**
2541
+	 * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2542
+	 * no other extra meta for this model object have the same key. Returns TRUE if the
2543
+	 * extra meta row was entered, false if not
2544
+	 *
2545
+	 * @param string $meta_key
2546
+	 * @param mixed $meta_value
2547
+	 * @param boolean $unique
2548
+	 * @return boolean
2549
+	 * @throws InvalidArgumentException
2550
+	 * @throws InvalidInterfaceException
2551
+	 * @throws InvalidDataTypeException
2552
+	 * @throws EE_Error
2553
+	 */
2554
+	public function add_extra_meta($meta_key, $meta_value, $unique = false)
2555
+	{
2556
+		if ($unique) {
2557
+			$existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2558
+				array(
2559
+					array(
2560
+						'EXM_key'  => $meta_key,
2561
+						'OBJ_ID'   => $this->ID(),
2562
+						'EXM_type' => $this->get_model()->get_this_model_name(),
2563
+					),
2564
+				)
2565
+			);
2566
+			if ($existing_extra_meta) {
2567
+				return false;
2568
+			}
2569
+		}
2570
+		$new_extra_meta = EE_Extra_Meta::new_instance(
2571
+			array(
2572
+				'EXM_key'   => $meta_key,
2573
+				'EXM_value' => $meta_value,
2574
+				'OBJ_ID'    => $this->ID(),
2575
+				'EXM_type'  => $this->get_model()->get_this_model_name(),
2576
+			)
2577
+		);
2578
+		$new_extra_meta->save();
2579
+		return true;
2580
+	}
2581
+
2582
+
2583
+	/**
2584
+	 * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2585
+	 * is specified, only deletes extra meta records with that value.
2586
+	 *
2587
+	 * @param string $meta_key
2588
+	 * @param mixed $meta_value
2589
+	 * @return int number of extra meta rows deleted
2590
+	 * @throws InvalidArgumentException
2591
+	 * @throws InvalidInterfaceException
2592
+	 * @throws InvalidDataTypeException
2593
+	 * @throws EE_Error
2594
+	 */
2595
+	public function delete_extra_meta($meta_key, $meta_value = null)
2596
+	{
2597
+		$query_params = array(
2598
+			array(
2599
+				'EXM_key'  => $meta_key,
2600
+				'OBJ_ID'   => $this->ID(),
2601
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2602
+			),
2603
+		);
2604
+		if ($meta_value !== null) {
2605
+			$query_params[0]['EXM_value'] = $meta_value;
2606
+		}
2607
+		return EEM_Extra_Meta::instance()->delete($query_params);
2608
+	}
2609
+
2610
+
2611
+
2612
+	/**
2613
+	 * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2614
+	 * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2615
+	 * You can specify $default is case you haven't found the extra meta
2616
+	 *
2617
+	 * @param string  $meta_key
2618
+	 * @param boolean $single
2619
+	 * @param mixed   $default if we don't find anything, what should we return?
2620
+	 * @return mixed single value if $single; array if ! $single
2621
+	 * @throws EE_Error
2622
+	 */
2623
+	public function get_extra_meta($meta_key, $single = false, $default = null)
2624
+	{
2625
+		if ($single) {
2626
+			$result = $this->get_first_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2627
+			if ($result instanceof EE_Extra_Meta) {
2628
+				return $result->value();
2629
+			}
2630
+		} else {
2631
+			$results = $this->get_many_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2632
+			if ($results) {
2633
+				$values = array();
2634
+				foreach ($results as $result) {
2635
+					if ($result instanceof EE_Extra_Meta) {
2636
+						$values[$result->ID()] = $result->value();
2637
+					}
2638
+				}
2639
+				return $values;
2640
+			}
2641
+		}
2642
+		//if nothing discovered yet return default.
2643
+		return apply_filters(
2644
+			'FHEE__EE_Base_Class__get_extra_meta__default_value',
2645
+			$default,
2646
+			$meta_key,
2647
+			$single,
2648
+			$this
2649
+			);
2650
+	}
2651
+
2652
+
2653
+
2654
+	/**
2655
+	 * Returns a simple array of all the extra meta associated with this model object.
2656
+	 * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2657
+	 * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2658
+	 * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2659
+	 * If $one_of_each_key is false, it will return an array with the top-level keys being
2660
+	 * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2661
+	 * finally the extra meta's value as each sub-value. (eg
2662
+	 * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2663
+	 *
2664
+	 * @param boolean $one_of_each_key
2665
+	 * @return array
2666
+	 * @throws EE_Error
2667
+	 */
2668
+	public function all_extra_meta_array($one_of_each_key = true)
2669
+	{
2670
+		$return_array = array();
2671
+		if ($one_of_each_key) {
2672
+			$extra_meta_objs = $this->get_many_related('Extra_Meta', array('group_by' => 'EXM_key'));
2673
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2674
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2675
+					$return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2676
+				}
2677
+			}
2678
+		} else {
2679
+			$extra_meta_objs = $this->get_many_related('Extra_Meta');
2680
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2681
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2682
+					if ( ! isset($return_array[$extra_meta_obj->key()])) {
2683
+						$return_array[$extra_meta_obj->key()] = array();
2684
+					}
2685
+					$return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2686
+				}
2687
+			}
2688
+		}
2689
+		return $return_array;
2690
+	}
2691
+
2692
+
2693
+
2694
+	/**
2695
+	 * Gets a pretty nice displayable nice for this model object. Often overridden
2696
+	 *
2697
+	 * @return string
2698
+	 * @throws EE_Error
2699
+	 */
2700
+	public function name()
2701
+	{
2702
+		//find a field that's not a text field
2703
+		$field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2704
+		if ($field_we_can_use) {
2705
+			return $this->get($field_we_can_use->get_name());
2706
+		} else {
2707
+			$first_few_properties = $this->model_field_array();
2708
+			$first_few_properties = array_slice($first_few_properties, 0, 3);
2709
+			$name_parts = array();
2710
+			foreach ($first_few_properties as $name => $value) {
2711
+				$name_parts[] = "$name:$value";
2712
+			}
2713
+			return implode(",", $name_parts);
2714
+		}
2715
+	}
2716
+
2717
+
2718
+
2719
+	/**
2720
+	 * in_entity_map
2721
+	 * Checks if this model object has been proven to already be in the entity map
2722
+	 *
2723
+	 * @return boolean
2724
+	 * @throws EE_Error
2725
+	 */
2726
+	public function in_entity_map()
2727
+	{
2728
+		if ($this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this) {
2729
+			//well, if we looked, did we find it in the entity map?
2730
+			return true;
2731
+		} else {
2732
+			return false;
2733
+		}
2734
+	}
2735
+
2736
+
2737
+
2738
+	/**
2739
+	 * refresh_from_db
2740
+	 * Makes sure the fields and values on this model object are in-sync with what's in the database.
2741
+	 *
2742
+	 * @throws EE_Error if this model object isn't in the entity mapper (because then you should
2743
+	 * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
2744
+	 */
2745
+	public function refresh_from_db()
2746
+	{
2747
+		if ($this->ID() && $this->in_entity_map()) {
2748
+			$this->get_model()->refresh_entity_map_from_db($this->ID());
2749
+		} else {
2750
+			//if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
2751
+			//if it has an ID but it's not in the map, and you're asking me to refresh it
2752
+			//that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
2753
+			//absolutely nothing in it for this ID
2754
+			if (WP_DEBUG) {
2755
+				throw new EE_Error(
2756
+					sprintf(
2757
+						__('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.',
2758
+							'event_espresso'),
2759
+						$this->ID(),
2760
+						get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2761
+						get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2762
+					)
2763
+				);
2764
+			}
2765
+		}
2766
+	}
2767
+
2768
+	/**
2769
+	 * Gets the money field's amount in subunits (and if the currency has no subunits, gets it in the main units)
2770
+	 * @param string $money_field_name
2771
+	 * @return int
2772
+	 * @throws InvalidEntityException
2773
+	 * @throws EE_Error
2774
+	 */
2775
+	public function moneyInSubunits($money_field_name)
2776
+	{
2777
+		return $this->getMoneyObject($money_field_name)->amountInSubunits();
2778
+	}
2779
+
2780
+	/**
2781
+	 * Sets the money field's amount based on the incoming monetary subunits (eg pennies). If the currency has no subunits,
2782
+	 * the amount is actually assumed to be in the currency's main units
2783
+	 * @param string $money_field_name
2784
+	 * @param int $amount_in_subunits
2785
+	 * @throws InvalidArgumentException
2786
+	 * @throws InvalidInterfaceException
2787
+	 * @throws InvalidIdentifierException
2788
+	 * @throws InvalidDataTypeException
2789
+	 * @throws EE_Error
2790
+	 */
2791
+	public function setMoneySubunits($money_field_name,$amount_in_subunits)
2792
+	{
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
+	/**
2803
+	 * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
2804
+	 * (probably a bad assumption they have made, oh well)
2805
+	 *
2806
+	 * @return string
2807
+	 */
2808
+	public function __toString()
2809
+	{
2810
+		try {
2811
+			return sprintf('%s (%s)', $this->name(), $this->ID());
2812
+		} catch (Exception $e) {
2813
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
2814
+			return '';
2815
+		}
2816
+	}
2817
+
2818
+
2819
+
2820
+	/**
2821
+	 * Clear related model objects if they're already in the DB, because otherwise when we
2822
+	 * UN-serialize this model object we'll need to be careful to add them to the entity map.
2823
+	 * This means if we have made changes to those related model objects, and want to unserialize
2824
+	 * the this model object on a subsequent request, changes to those related model objects will be lost.
2825
+	 * Instead, those related model objects should be directly serialized and stored.
2826
+	 * Eg, the following won't work:
2827
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2828
+	 * $att = $reg->attendee();
2829
+	 * $att->set( 'ATT_fname', 'Dirk' );
2830
+	 * update_option( 'my_option', serialize( $reg ) );
2831
+	 * //END REQUEST
2832
+	 * //START NEXT REQUEST
2833
+	 * $reg = get_option( 'my_option' );
2834
+	 * $reg->attendee()->save();
2835
+	 * And would need to be replace with:
2836
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2837
+	 * $att = $reg->attendee();
2838
+	 * $att->set( 'ATT_fname', 'Dirk' );
2839
+	 * update_option( 'my_option', serialize( $reg ) );
2840
+	 * //END REQUEST
2841
+	 * //START NEXT REQUEST
2842
+	 * $att = get_option( 'my_option' );
2843
+	 * $att->save();
2844
+	 *
2845
+	 * @return array
2846
+	 * @throws EE_Error
2847
+	 */
2848
+	public function __sleep()
2849
+	{
2850
+		$model = $this->get_model();
2851
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2852
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
2853
+				$classname = 'EE_' . $model->get_this_model_name();
2854
+				if (
2855
+					$this->get_one_from_cache($relation_name) instanceof $classname
2856
+					&& $this->get_one_from_cache($relation_name)->ID()
2857
+				) {
2858
+					$this->clear_cache($relation_name, $this->get_one_from_cache($relation_name)->ID());
2859
+				}
2860
+			}
2861
+		}
2862
+		$this->_props_n_values_provided_in_constructor = array();
2863
+		$properties_to_serialize = get_object_vars($this);
2864
+		//don't serialize the model. It's big and that risks recursion
2865
+		unset($properties_to_serialize['_model']);
2866
+		return array_keys($properties_to_serialize);
2867
+	}
2868
+
2869
+
2870
+
2871
+	/**
2872
+	 * restore _props_n_values_provided_in_constructor
2873
+	 * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
2874
+	 * and therefore should NOT be used to determine if state change has occurred since initial construction.
2875
+	 * At best, you would only be able to detect if state change has occurred during THIS request.
2876
+	 */
2877
+	public function __wakeup()
2878
+	{
2879
+		$this->_props_n_values_provided_in_constructor = $this->_fields;
2880
+	}
2881 2881
 
2882 2882
 
2883 2883
 
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
         $date_formats = array(),
160 160
         MoneyFactory $money_factory = null
161 161
     ) {
162
-        if (! $money_factory instanceof MoneyFactory) {
162
+        if ( ! $money_factory instanceof MoneyFactory) {
163 163
             $money_factory = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\currency\MoneyFactory');
164 164
         }
165 165
         $this->money_factory = $money_factory;
@@ -183,8 +183,8 @@  discard block
 block discarded – undo
183 183
             list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
184 184
         } else {
185 185
             //set default formats for date and time
186
-            $this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
187
-            $this->_tm_frmt = (string)get_option('time_format', 'g:i a');
186
+            $this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
187
+            $this->_tm_frmt = (string) get_option('time_format', 'g:i a');
188 188
         }
189 189
         //if db model is instantiating
190 190
         if ($bydb) {
@@ -510,7 +510,7 @@  discard block
 block discarded – undo
510 510
      */
511 511
     public function get_format($full = true)
512 512
     {
513
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
513
+        return $full ? $this->_dt_frmt.' '.$this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
514 514
     }
515 515
 
516 516
 
@@ -619,7 +619,7 @@  discard block
 block discarded – undo
619 619
         $model = $this->get_model();
620 620
         $model->field_settings_for($fieldname);
621 621
         $cache_type = $pretty ? 'pretty' : 'standard';
622
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
622
+        $cache_type .= ! empty($extra_cache_ref) ? '_'.$extra_cache_ref : '';
623 623
         if (isset($this->_cached_properties[$fieldname][$cache_type])) {
624 624
             return $this->_cached_properties[$fieldname][$cache_type];
625 625
         }
@@ -848,7 +848,7 @@  discard block
 block discarded – undo
848 848
         $current_cache_id = ''
849 849
     ) {
850 850
         // verify that incoming object is of the correct type
851
-        $obj_class = 'EE_' . $relationName;
851
+        $obj_class = 'EE_'.$relationName;
852 852
         if ($newly_saved_object instanceof $obj_class) {
853 853
             /* @type EE_Base_Class $newly_saved_object */
854 854
             // now get the type of relation
@@ -1110,7 +1110,7 @@  discard block
 block discarded – undo
1110 1110
     public function get_raw($field_name)
1111 1111
     {
1112 1112
         $field_settings = $this->get_model()->field_settings_for($field_name);
1113
-        switch(true){
1113
+        switch (true) {
1114 1114
             case $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime:
1115 1115
                 $value = $this->_fields[$field_name]->format('U');
1116 1116
                 break;
@@ -1174,7 +1174,7 @@  discard block
 block discarded – undo
1174 1174
     {
1175 1175
         $field = $this->get_model()->field_settings_for($field_name);
1176 1176
         $value = isset($this->_fields[$field_name]) ? $this->_fields[$field_name] : null;
1177
-        if (! $field instanceof EE_Money_Field
1177
+        if ( ! $field instanceof EE_Money_Field
1178 1178
             || ! $value instanceof Money) {
1179 1179
             throw new InvalidEntityException(
1180 1180
                 get_class($value),
@@ -1236,7 +1236,7 @@  discard block
 block discarded – undo
1236 1236
      */
1237 1237
     public function get_f($field_name)
1238 1238
     {
1239
-        return (string)$this->get_pretty($field_name,'form_input');
1239
+        return (string) $this->get_pretty($field_name, 'form_input');
1240 1240
     }
1241 1241
 
1242 1242
 
@@ -1395,7 +1395,7 @@  discard block
 block discarded – undo
1395 1395
      */
1396 1396
     public function get_i18n_datetime($field_name, $format = '')
1397 1397
     {
1398
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1398
+        $format = empty($format) ? $this->_dt_frmt.' '.$this->_tm_frmt : $format;
1399 1399
         return date_i18n(
1400 1400
             $format,
1401 1401
             EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
@@ -1537,8 +1537,8 @@  discard block
 block discarded – undo
1537 1537
         }
1538 1538
         $original_timezone = $this->_timezone;
1539 1539
         $this->set_timezone($timezone);
1540
-        $fn = (array)$field_name;
1541
-        $args = array_merge($fn, (array)$args);
1540
+        $fn = (array) $field_name;
1541
+        $args = array_merge($fn, (array) $args);
1542 1542
         if ( ! method_exists($this, $callback)) {
1543 1543
             throw new EE_Error(
1544 1544
                 sprintf(
@@ -1550,8 +1550,8 @@  discard block
 block discarded – undo
1550 1550
                 )
1551 1551
             );
1552 1552
         }
1553
-        $args = (array)$args;
1554
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1553
+        $args = (array) $args;
1554
+        $return = $prepend.call_user_func_array(array($this, $callback), $args).$append;
1555 1555
         $this->set_timezone($original_timezone);
1556 1556
         return $return;
1557 1557
     }
@@ -1690,14 +1690,14 @@  discard block
 block discarded – undo
1690 1690
          * @param array         $set_cols_n_values
1691 1691
          * @param EE_Base_Class $model_object
1692 1692
          */
1693
-        $set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1693
+        $set_cols_n_values = (array) apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1694 1694
             $this);
1695 1695
         //set attributes as provided in $set_cols_n_values
1696 1696
         foreach ($set_cols_n_values as $column => $value) {
1697 1697
             $this->set($column, $value);
1698 1698
         }
1699 1699
         // no changes ? then don't do anything
1700
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1700
+        if ( ! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1701 1701
             return 0;
1702 1702
         }
1703 1703
         /**
@@ -1749,8 +1749,8 @@  discard block
 block discarded – undo
1749 1749
                                 __('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',
1750 1750
                                     'event_espresso'),
1751 1751
                                 get_class($this),
1752
-                                get_class($model) . '::instance()->add_to_entity_map()',
1753
-                                get_class($model) . '::instance()->get_one_by_ID()',
1752
+                                get_class($model).'::instance()->add_to_entity_map()',
1753
+                                get_class($model).'::instance()->get_one_by_ID()',
1754 1754
                                 '<br />'
1755 1755
                             )
1756 1756
                         );
@@ -1883,7 +1883,7 @@  discard block
 block discarded – undo
1883 1883
      */
1884 1884
     public function get_model()
1885 1885
     {
1886
-        if( ! $this->_model){
1886
+        if ( ! $this->_model) {
1887 1887
             $modelName = self::_get_model_classname(get_class($this));
1888 1888
             $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1889 1889
         } else {
@@ -2030,7 +2030,7 @@  discard block
 block discarded – undo
2030 2030
         if (strpos($model_name, "EE_") === 0) {
2031 2031
             $model_classname = str_replace("EE_", "EEM_", $model_name);
2032 2032
         } else {
2033
-            $model_classname = "EEM_" . $model_name;
2033
+            $model_classname = "EEM_".$model_name;
2034 2034
         }
2035 2035
         return $model_classname;
2036 2036
     }
@@ -2417,7 +2417,7 @@  discard block
 block discarded – undo
2417 2417
      */
2418 2418
     protected function _property_exists($properties)
2419 2419
     {
2420
-        foreach ((array)$properties as $property_name) {
2420
+        foreach ((array) $properties as $property_name) {
2421 2421
             //first make sure this property exists
2422 2422
             if ( ! $this->_fields[$property_name]) {
2423 2423
                 throw new EE_Error(
@@ -2757,8 +2757,8 @@  discard block
 block discarded – undo
2757 2757
                         __('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.',
2758 2758
                             'event_espresso'),
2759 2759
                         $this->ID(),
2760
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2761
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2760
+                        get_class($this->get_model()).'::instance()->add_to_entity_map()',
2761
+                        get_class($this->get_model()).'::instance()->refresh_entity_map()'
2762 2762
                     )
2763 2763
                 );
2764 2764
             }
@@ -2788,7 +2788,7 @@  discard block
 block discarded – undo
2788 2788
      * @throws InvalidDataTypeException
2789 2789
      * @throws EE_Error
2790 2790
      */
2791
-    public function setMoneySubunits($money_field_name,$amount_in_subunits)
2791
+    public function setMoneySubunits($money_field_name, $amount_in_subunits)
2792 2792
     {
2793 2793
         $money = $this->money_factory->createFromSubUnits(
2794 2794
             $amount_in_subunits,
@@ -2850,7 +2850,7 @@  discard block
 block discarded – undo
2850 2850
         $model = $this->get_model();
2851 2851
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2852 2852
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
2853
-                $classname = 'EE_' . $model->get_this_model_name();
2853
+                $classname = 'EE_'.$model->get_this_model_name();
2854 2854
                 if (
2855 2855
                     $this->get_one_from_cache($relation_name) instanceof $classname
2856 2856
                     && $this->get_one_from_cache($relation_name)->ID()
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
@@ -19,7 +19,7 @@  discard block
 block discarded – undo
19 19
 	 * @param array  $props_n_values          incoming values
20 20
 	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
21 21
 	 *                                        used.)
22
-	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
22
+	 * @param string[]  $date_formats            incoming date_formats in an array where the first value is the
23 23
 	 *                                        date_format and the second value is the time format
24 24
 	 * @return EE_Payment
25 25
 	 * @throws EE_Error
@@ -596,7 +596,7 @@  discard block
 block discarded – undo
596 596
 	 * Gets all the extra meta info on this payment
597 597
 	 *
598 598
 	 * @param array $query_params like EEM_Base::get_all
599
-	 * @return EE_Extra_Meta
599
+	 * @return EE_Base_Class[]
600 600
 	 * @throws EE_Error
601 601
 	 */
602 602
 	public function extra_meta( $query_params = array() ) {
@@ -845,7 +845,7 @@  discard block
 block discarded – undo
845 845
 
846 846
     /**
847 847
      * Returns the payment's transaction's primary registration
848
-     * @return EE_Registration|null
848
+     * @return EE_Base_Class|null
849 849
      * @throws EE_Error
850 850
      */
851 851
     public function get_primary_registration()
Please login to merge, or discard this patch.
Indentation   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -449,16 +449,16 @@  discard block
 block discarded – undo
449 449
 	}
450 450
 
451 451
 
452
-    /**
453
-     * returns a pretty version of the status, good for displaying to users
454
-     *
455
-     * @param bool $show_icons
456
-     * @return string
457
-     * @throws InvalidArgumentException
458
-     * @throws InvalidInterfaceException
459
-     * @throws InvalidDataTypeException
460
-     * @throws EE_Error
461
-     */
452
+	/**
453
+	 * returns a pretty version of the status, good for displaying to users
454
+	 *
455
+	 * @param bool $show_icons
456
+	 * @return string
457
+	 * @throws InvalidArgumentException
458
+	 * @throws InvalidInterfaceException
459
+	 * @throws InvalidDataTypeException
460
+	 * @throws EE_Error
461
+	 */
462 462
 	public function pretty_status( $show_icons = false ) {
463 463
 		$status = EEM_Status::instance()->localized_status(
464 464
 			array( $this->STS_ID() => __( 'unknown', 'event_espresso' ) ),
@@ -667,11 +667,11 @@  discard block
 block discarded – undo
667 667
 				$redirect_url = str_replace( '?' . $querystring, '', $redirect_url );
668 668
 			}
669 669
 			$form = EEH_HTML::nl( 1 )
670
-			        . '<form method="'
671
-			        . $method
672
-			        . '" name="gateway_form" action="'
673
-			        . $redirect_url
674
-			        . '">';
670
+					. '<form method="'
671
+					. $method
672
+					. '" name="gateway_form" action="'
673
+					. $redirect_url
674
+					. '">';
675 675
 			$form .= EEH_HTML::nl( 1 ) . $this->redirect_args_as_inputs();
676 676
 			$form .= $inside_form_html;
677 677
 			$form .= EEH_HTML::nl( -1 ) . '</form>' . EEH_HTML::nl( -1 );
@@ -708,11 +708,11 @@  discard block
 block discarded – undo
708 708
 		if ( $args !== null && is_array( $args ) ) {
709 709
 			foreach ( $args as $name => $value ) {
710 710
 				$html .= EEH_HTML::nl( 0 )
711
-				         . '<input type="hidden" name="'
712
-				         . $name
713
-				         . '" value="'
714
-				         . esc_attr( $value )
715
-				         . '"/>';
711
+						 . '<input type="hidden" name="'
712
+						 . $name
713
+						 . '" value="'
714
+						 . esc_attr( $value )
715
+						 . '"/>';
716 716
 			}
717 717
 		}
718 718
 		return $html;
@@ -811,86 +811,86 @@  discard block
 block discarded – undo
811 811
 	}
812 812
 
813 813
 
814
-    /**
815
-     * Gets the first event for this payment (it's possible that it could be for multiple)
816
-     *
817
-     * @return EE_Event|null
818
-     * @throws EE_Error
819
-     */
820
-    public function get_first_event()
821
-    {
822
-        $transaction = $this->transaction();
823
-        if ($transaction instanceof EE_Transaction) {
824
-            $primary_registrant = $transaction->primary_registration();
825
-            if ($primary_registrant instanceof EE_Registration) {
826
-                return $primary_registrant->event_obj();
827
-            }
828
-        }
829
-        return null;
830
-    }
831
-
832
-
833
-    /**
834
-     * Gets the name of the first event for which is being paid
835
-     *
836
-     * @return string
837
-     * @throws EE_Error
838
-     */
839
-    public function get_first_event_name()
840
-    {
841
-        $event = $this->get_first_event();
842
-        return $event instanceof EE_Event ? $event->name() : __('Event', 'event_espresso');
843
-    }
844
-
845
-
846
-    /**
847
-     * Returns the payment's transaction's primary registration
848
-     * @return EE_Registration|null
849
-     * @throws EE_Error
850
-     */
851
-    public function get_primary_registration()
852
-    {
853
-        if ($this->transaction() instanceof EE_Transaction) {
854
-            return $this->transaction()->primary_registration();
855
-        }
856
-        return null;
857
-    }
858
-
859
-
860
-    /**
861
-     * Gets the payment's transaction's primary registration's attendee, or null
862
-     * @return EE_Attendee|null
863
-     * @throws EE_Error
864
-     */
865
-    public function get_primary_attendee()
866
-    {
867
-        $primary_reg = $this->get_primary_registration();
868
-        if( $primary_reg instanceof EE_Registration) {
869
-            return $primary_reg->attendee();
870
-        }
871
-        return null;
872
-    }
873
-
874
-    /**
875
-     * Returns the payment's amount in subunits (if the currency has subunits; otherwise this will actually be
876
-     * in the currency's main units)
877
-     * @return int
878
-     */
879
-    public function amountInSubunits()
880
-    {
881
-        return $this->moneyInSubunits('PAY_amount');
882
-    }
883
-
884
-    /**
885
-     * Sets the payment's amount based on the incoming monetary subunits (eg pennies). If the currency has no subunits,
886
-     * the amount is actually assumed to be in the currency's main units
887
-     * @param int $amount_in_subunits
888
-     * @return void
889
-     */
890
-    public function setAmountInSubunits($amount_in_subunits)
891
-    {
892
-        $this->setMoneySubunits('PAY_amount', $amount_in_subunits);
893
-    }
814
+	/**
815
+	 * Gets the first event for this payment (it's possible that it could be for multiple)
816
+	 *
817
+	 * @return EE_Event|null
818
+	 * @throws EE_Error
819
+	 */
820
+	public function get_first_event()
821
+	{
822
+		$transaction = $this->transaction();
823
+		if ($transaction instanceof EE_Transaction) {
824
+			$primary_registrant = $transaction->primary_registration();
825
+			if ($primary_registrant instanceof EE_Registration) {
826
+				return $primary_registrant->event_obj();
827
+			}
828
+		}
829
+		return null;
830
+	}
831
+
832
+
833
+	/**
834
+	 * Gets the name of the first event for which is being paid
835
+	 *
836
+	 * @return string
837
+	 * @throws EE_Error
838
+	 */
839
+	public function get_first_event_name()
840
+	{
841
+		$event = $this->get_first_event();
842
+		return $event instanceof EE_Event ? $event->name() : __('Event', 'event_espresso');
843
+	}
844
+
845
+
846
+	/**
847
+	 * Returns the payment's transaction's primary registration
848
+	 * @return EE_Registration|null
849
+	 * @throws EE_Error
850
+	 */
851
+	public function get_primary_registration()
852
+	{
853
+		if ($this->transaction() instanceof EE_Transaction) {
854
+			return $this->transaction()->primary_registration();
855
+		}
856
+		return null;
857
+	}
858
+
859
+
860
+	/**
861
+	 * Gets the payment's transaction's primary registration's attendee, or null
862
+	 * @return EE_Attendee|null
863
+	 * @throws EE_Error
864
+	 */
865
+	public function get_primary_attendee()
866
+	{
867
+		$primary_reg = $this->get_primary_registration();
868
+		if( $primary_reg instanceof EE_Registration) {
869
+			return $primary_reg->attendee();
870
+		}
871
+		return null;
872
+	}
873
+
874
+	/**
875
+	 * Returns the payment's amount in subunits (if the currency has subunits; otherwise this will actually be
876
+	 * in the currency's main units)
877
+	 * @return int
878
+	 */
879
+	public function amountInSubunits()
880
+	{
881
+		return $this->moneyInSubunits('PAY_amount');
882
+	}
883
+
884
+	/**
885
+	 * Sets the payment's amount based on the incoming monetary subunits (eg pennies). If the currency has no subunits,
886
+	 * the amount is actually assumed to be in the currency's main units
887
+	 * @param int $amount_in_subunits
888
+	 * @return void
889
+	 */
890
+	public function setAmountInSubunits($amount_in_subunits)
891
+	{
892
+		$this->setMoneySubunits('PAY_amount', $amount_in_subunits);
893
+	}
894 894
 }
895 895
 /* End of file EE_Payment.class.php */
896 896
 /* Location: /includes/classes/EE_Payment.class.php */
Please login to merge, or discard this patch.
Spacing   +104 added lines, -104 removed lines patch added patch discarded remove patch
@@ -2,8 +2,8 @@  discard block
 block discarded – undo
2 2
 use EventEspresso\core\exceptions\InvalidDataTypeException;
3 3
 use EventEspresso\core\exceptions\InvalidInterfaceException;
4 4
 
5
-if ( ! defined( 'EVENT_ESPRESSO_VERSION' ) ) {
6
-	exit( 'No direct script access allowed' );
5
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
6
+	exit('No direct script access allowed');
7 7
 }
8 8
 
9 9
 /**
@@ -24,9 +24,9 @@  discard block
 block discarded – undo
24 24
 	 * @return EE_Payment
25 25
 	 * @throws EE_Error
26 26
 	 */
27
-	public static function new_instance( $props_n_values = array(), $timezone = null, $date_formats = array() ) {
28
-		$has_object = parent::_check_for_object( $props_n_values, __CLASS__, $timezone, $date_formats );
29
-		return $has_object ? $has_object : new self( $props_n_values, false, $timezone, $date_formats );
27
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) {
28
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
29
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
30 30
 	}
31 31
 
32 32
 
@@ -38,8 +38,8 @@  discard block
 block discarded – undo
38 38
 	 * @return EE_Payment
39 39
 	 * @throws EE_Error
40 40
 	 */
41
-	public static function new_instance_from_db( $props_n_values = array(), $timezone = null ) {
42
-		return new self( $props_n_values, true, $timezone );
41
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null) {
42
+		return new self($props_n_values, true, $timezone);
43 43
 	}
44 44
 
45 45
 
@@ -51,8 +51,8 @@  discard block
 block discarded – undo
51 51
 	 * @param int $TXN_ID
52 52
 	 * @throws EE_Error
53 53
 	 */
54
-	public function set_transaction_id( $TXN_ID = 0 ) {
55
-		$this->set( 'TXN_ID', $TXN_ID );
54
+	public function set_transaction_id($TXN_ID = 0) {
55
+		$this->set('TXN_ID', $TXN_ID);
56 56
 	}
57 57
 
58 58
 
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
 	 * @throws EE_Error
65 65
 	 */
66 66
 	public function transaction() {
67
-		return $this->get_first_related( 'Transaction' );
67
+		return $this->get_first_related('Transaction');
68 68
 	}
69 69
 
70 70
 
@@ -76,8 +76,8 @@  discard block
 block discarded – undo
76 76
 	 * @param string $STS_ID
77 77
 	 * @throws EE_Error
78 78
 	 */
79
-	public function set_status( $STS_ID = '' ) {
80
-		$this->set( 'STS_ID', $STS_ID );
79
+	public function set_status($STS_ID = '') {
80
+		$this->set('STS_ID', $STS_ID);
81 81
 	}
82 82
 
83 83
 
@@ -89,8 +89,8 @@  discard block
 block discarded – undo
89 89
 	 * @param int $timestamp
90 90
 	 * @throws EE_Error
91 91
 	 */
92
-	public function set_timestamp( $timestamp = 0 ) {
93
-		$this->set( 'PAY_timestamp', $timestamp );
92
+	public function set_timestamp($timestamp = 0) {
93
+		$this->set('PAY_timestamp', $timestamp);
94 94
 	}
95 95
 
96 96
 
@@ -102,8 +102,8 @@  discard block
 block discarded – undo
102 102
 	 * @param string $PAY_source
103 103
 	 * @throws EE_Error
104 104
 	 */
105
-	public function set_source( $PAY_source = '' ) {
106
-		$this->set( 'PAY_source', $PAY_source );
105
+	public function set_source($PAY_source = '') {
106
+		$this->set('PAY_source', $PAY_source);
107 107
 	}
108 108
 
109 109
 
@@ -115,8 +115,8 @@  discard block
 block discarded – undo
115 115
 	 * @param float $amount
116 116
 	 * @throws EE_Error
117 117
 	 */
118
-	public function set_amount( $amount = 0.00 ) {
119
-		$this->set( 'PAY_amount', (float)$amount );
118
+	public function set_amount($amount = 0.00) {
119
+		$this->set('PAY_amount', (float) $amount);
120 120
 	}
121 121
 
122 122
 
@@ -128,8 +128,8 @@  discard block
 block discarded – undo
128 128
 	 * @param string $gateway_response
129 129
 	 * @throws EE_Error
130 130
 	 */
131
-	public function set_gateway_response( $gateway_response = '' ) {
132
-		$this->set( 'PAY_gateway_response', $gateway_response );
131
+	public function set_gateway_response($gateway_response = '') {
132
+		$this->set('PAY_gateway_response', $gateway_response);
133 133
 	}
134 134
 
135 135
 
@@ -152,7 +152,7 @@  discard block
 block discarded – undo
152 152
 			),
153 153
 			'4.6.0'
154 154
 		);
155
-		return $this->payment_method() ? $this->payment_method()->name() : __( 'Unknown', 'event_espresso' );
155
+		return $this->payment_method() ? $this->payment_method()->name() : __('Unknown', 'event_espresso');
156 156
 	}
157 157
 
158 158
 
@@ -164,8 +164,8 @@  discard block
 block discarded – undo
164 164
 	 * @param string $txn_id_chq_nmbr
165 165
 	 * @throws EE_Error
166 166
 	 */
167
-	public function set_txn_id_chq_nmbr( $txn_id_chq_nmbr = '' ) {
168
-		$this->set( 'PAY_txn_id_chq_nmbr', $txn_id_chq_nmbr );
167
+	public function set_txn_id_chq_nmbr($txn_id_chq_nmbr = '') {
168
+		$this->set('PAY_txn_id_chq_nmbr', $txn_id_chq_nmbr);
169 169
 	}
170 170
 
171 171
 
@@ -177,8 +177,8 @@  discard block
 block discarded – undo
177 177
 	 * @param string $po_number
178 178
 	 * @throws EE_Error
179 179
 	 */
180
-	public function set_po_number( $po_number = '' ) {
181
-		$this->set( 'PAY_po_number', $po_number );
180
+	public function set_po_number($po_number = '') {
181
+		$this->set('PAY_po_number', $po_number);
182 182
 	}
183 183
 
184 184
 
@@ -190,8 +190,8 @@  discard block
 block discarded – undo
190 190
 	 * @param string $extra_accntng
191 191
 	 * @throws EE_Error
192 192
 	 */
193
-	public function set_extra_accntng( $extra_accntng = '' ) {
194
-		$this->set( 'PAY_extra_accntng', $extra_accntng );
193
+	public function set_extra_accntng($extra_accntng = '') {
194
+		$this->set('PAY_extra_accntng', $extra_accntng);
195 195
 	}
196 196
 
197 197
 
@@ -203,11 +203,11 @@  discard block
 block discarded – undo
203 203
 	 * @param bool $via_admin
204 204
 	 * @throws EE_Error
205 205
 	 */
206
-	public function set_payment_made_via_admin( $via_admin = false ) {
207
-		if ( $via_admin ) {
208
-			$this->set( 'PAY_source', EEM_Payment_Method::scope_admin );
206
+	public function set_payment_made_via_admin($via_admin = false) {
207
+		if ($via_admin) {
208
+			$this->set('PAY_source', EEM_Payment_Method::scope_admin);
209 209
 		} else {
210
-			$this->set( 'PAY_source', EEM_Payment_Method::scope_cart );
210
+			$this->set('PAY_source', EEM_Payment_Method::scope_cart);
211 211
 		}
212 212
 	}
213 213
 
@@ -220,13 +220,13 @@  discard block
 block discarded – undo
220 220
 	 * @param string|array $details
221 221
 	 * @throws EE_Error
222 222
 	 */
223
-	public function set_details( $details = '' ) {
224
-		if ( is_array( $details ) ) {
225
-			array_walk_recursive( $details, array( $this, '_strip_all_tags_within_array' ) );
223
+	public function set_details($details = '') {
224
+		if (is_array($details)) {
225
+			array_walk_recursive($details, array($this, '_strip_all_tags_within_array'));
226 226
 		} else {
227
-			$details = wp_strip_all_tags( $details );
227
+			$details = wp_strip_all_tags($details);
228 228
 		}
229
-		$this->set( 'PAY_details', $details );
229
+		$this->set('PAY_details', $details);
230 230
 	}
231 231
 
232 232
 
@@ -237,8 +237,8 @@  discard block
 block discarded – undo
237 237
 	 * @param string $redirect_url
238 238
 	 * @throws EE_Error
239 239
 	 */
240
-	public function set_redirect_url( $redirect_url ) {
241
-		$this->set( 'PAY_redirect_url', $redirect_url );
240
+	public function set_redirect_url($redirect_url) {
241
+		$this->set('PAY_redirect_url', $redirect_url);
242 242
 	}
243 243
 
244 244
 
@@ -249,8 +249,8 @@  discard block
 block discarded – undo
249 249
 	 * @param array $redirect_args
250 250
 	 * @throws EE_Error
251 251
 	 */
252
-	public function set_redirect_args( $redirect_args ) {
253
-		$this->set( 'PAY_redirect_args', $redirect_args );
252
+	public function set_redirect_args($redirect_args) {
253
+		$this->set('PAY_redirect_args', $redirect_args);
254 254
 	}
255 255
 
256 256
 
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
 	 * @throws EE_Error
263 263
 	 */
264 264
 	public function TXN_ID() {
265
-		return $this->get( 'TXN_ID' );
265
+		return $this->get('TXN_ID');
266 266
 	}
267 267
 
268 268
 
@@ -274,7 +274,7 @@  discard block
 block discarded – undo
274 274
 	 * @throws EE_Error
275 275
 	 */
276 276
 	public function status() {
277
-		return $this->get( 'STS_ID' );
277
+		return $this->get('STS_ID');
278 278
 	}
279 279
 
280 280
 
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
 	 * @throws EE_Error
287 287
 	 */
288 288
 	public function STS_ID() {
289
-		return $this->get( 'STS_ID' );
289
+		return $this->get('STS_ID');
290 290
 	}
291 291
 
292 292
 
@@ -300,8 +300,8 @@  discard block
 block discarded – undo
300 300
 	 * @return string
301 301
 	 * @throws EE_Error
302 302
 	 */
303
-	public function timestamp( $dt_frmt = '', $tm_frmt = '' ) {
304
-		return $this->get_i18n_datetime( 'PAY_timestamp', trim( $dt_frmt . ' ' . $tm_frmt) );
303
+	public function timestamp($dt_frmt = '', $tm_frmt = '') {
304
+		return $this->get_i18n_datetime('PAY_timestamp', trim($dt_frmt.' '.$tm_frmt));
305 305
 	}
306 306
 
307 307
 
@@ -313,7 +313,7 @@  discard block
 block discarded – undo
313 313
 	 * @throws EE_Error
314 314
 	 */
315 315
 	public function source() {
316
-		return $this->get( 'PAY_source' );
316
+		return $this->get('PAY_source');
317 317
 	}
318 318
 
319 319
 
@@ -326,7 +326,7 @@  discard block
 block discarded – undo
326 326
 	 * @throws EE_Error
327 327
 	 */
328 328
 	public function amount() {
329
-		return (float)$this->get( 'PAY_amount' );
329
+		return (float) $this->get('PAY_amount');
330 330
 	}
331 331
 
332 332
 
@@ -336,7 +336,7 @@  discard block
 block discarded – undo
336 336
 	 * @throws EE_Error
337 337
 	 */
338 338
 	public function amount_no_code() {
339
-		return $this->get_pretty( 'PAY_amount', 'no_currency_code' );
339
+		return $this->get_pretty('PAY_amount', 'no_currency_code');
340 340
 	}
341 341
 
342 342
 
@@ -348,7 +348,7 @@  discard block
 block discarded – undo
348 348
 	 * @throws EE_Error
349 349
 	 */
350 350
 	public function gateway_response() {
351
-		return $this->get( 'PAY_gateway_response' );
351
+		return $this->get('PAY_gateway_response');
352 352
 	}
353 353
 
354 354
 
@@ -360,7 +360,7 @@  discard block
 block discarded – undo
360 360
 	 * @throws EE_Error
361 361
 	 */
362 362
 	public function txn_id_chq_nmbr() {
363
-		return $this->get( 'PAY_txn_id_chq_nmbr' );
363
+		return $this->get('PAY_txn_id_chq_nmbr');
364 364
 	}
365 365
 
366 366
 
@@ -372,7 +372,7 @@  discard block
 block discarded – undo
372 372
 	 * @throws EE_Error
373 373
 	 */
374 374
 	public function po_number() {
375
-		return $this->get( 'PAY_po_number' );
375
+		return $this->get('PAY_po_number');
376 376
 	}
377 377
 
378 378
 
@@ -384,7 +384,7 @@  discard block
 block discarded – undo
384 384
 	 * @throws EE_Error
385 385
 	 */
386 386
 	public function extra_accntng() {
387
-		return $this->get( 'PAY_extra_accntng' );
387
+		return $this->get('PAY_extra_accntng');
388 388
 	}
389 389
 
390 390
 
@@ -396,7 +396,7 @@  discard block
 block discarded – undo
396 396
 	 * @throws EE_Error
397 397
 	 */
398 398
 	public function payment_made_via_admin() {
399
-		return ( $this->get( 'PAY_source' ) === EEM_Payment_Method::scope_admin );
399
+		return ($this->get('PAY_source') === EEM_Payment_Method::scope_admin);
400 400
 	}
401 401
 
402 402
 
@@ -408,7 +408,7 @@  discard block
 block discarded – undo
408 408
 	 * @throws EE_Error
409 409
 	 */
410 410
 	public function details() {
411
-		return $this->get( 'PAY_details' );
411
+		return $this->get('PAY_details');
412 412
 	}
413 413
 
414 414
 
@@ -420,7 +420,7 @@  discard block
 block discarded – undo
420 420
 	 * @throws EE_Error
421 421
 	 */
422 422
 	public function redirect_url() {
423
-		return $this->get( 'PAY_redirect_url' );
423
+		return $this->get('PAY_redirect_url');
424 424
 	}
425 425
 
426 426
 
@@ -432,7 +432,7 @@  discard block
 block discarded – undo
432 432
 	 * @throws EE_Error
433 433
 	 */
434 434
 	public function redirect_args() {
435
-		return $this->get( 'PAY_redirect_args' );
435
+		return $this->get('PAY_redirect_args');
436 436
 	}
437 437
 
438 438
 
@@ -444,8 +444,8 @@  discard block
 block discarded – undo
444 444
 	 * @return void
445 445
 	 * @throws EE_Error
446 446
 	 */
447
-	public function e_pretty_status( $show_icons = false ) {
448
-		echo $this->pretty_status( $show_icons );
447
+	public function e_pretty_status($show_icons = false) {
448
+		echo $this->pretty_status($show_icons);
449 449
 	}
450 450
 
451 451
 
@@ -459,14 +459,14 @@  discard block
 block discarded – undo
459 459
      * @throws InvalidDataTypeException
460 460
      * @throws EE_Error
461 461
      */
462
-	public function pretty_status( $show_icons = false ) {
462
+	public function pretty_status($show_icons = false) {
463 463
 		$status = EEM_Status::instance()->localized_status(
464
-			array( $this->STS_ID() => __( 'unknown', 'event_espresso' ) ),
464
+			array($this->STS_ID() => __('unknown', 'event_espresso')),
465 465
 			false,
466 466
 			'sentence'
467 467
 		);
468 468
 		$icon = '';
469
-		switch ( $this->STS_ID() ) {
469
+		switch ($this->STS_ID()) {
470 470
 			case EEM_Payment::status_id_approved:
471 471
 				$icon = $show_icons
472 472
 					? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>'
@@ -488,7 +488,7 @@  discard block
 block discarded – undo
488 488
 					: '';
489 489
 				break;
490 490
 		}
491
-		return $icon . $status[ $this->STS_ID() ];
491
+		return $icon.$status[$this->STS_ID()];
492 492
 	}
493 493
 
494 494
 
@@ -500,7 +500,7 @@  discard block
 block discarded – undo
500 500
 	 * @throws EE_Error
501 501
 	 */
502 502
 	public function is_approved() {
503
-		return $this->status_is( EEM_Payment::status_id_approved );
503
+		return $this->status_is(EEM_Payment::status_id_approved);
504 504
 	}
505 505
 
506 506
 
@@ -514,7 +514,7 @@  discard block
 block discarded – undo
514 514
 	 * @return boolean whether the status of this payment equals the status id
515 515
 	 * @throws EE_Error
516 516
 	 */
517
-	protected function status_is( $STS_ID ) {
517
+	protected function status_is($STS_ID) {
518 518
 		return $STS_ID === $this->STS_ID() ? true : false;
519 519
 	}
520 520
 
@@ -527,7 +527,7 @@  discard block
 block discarded – undo
527 527
 	 * @throws EE_Error
528 528
 	 */
529 529
 	public function is_pending() {
530
-		return $this->status_is( EEM_Payment::status_id_pending );
530
+		return $this->status_is(EEM_Payment::status_id_pending);
531 531
 	}
532 532
 
533 533
 
@@ -539,7 +539,7 @@  discard block
 block discarded – undo
539 539
 	 * @throws EE_Error
540 540
 	 */
541 541
 	public function is_cancelled() {
542
-		return $this->status_is( EEM_Payment::status_id_cancelled );
542
+		return $this->status_is(EEM_Payment::status_id_cancelled);
543 543
 	}
544 544
 
545 545
 
@@ -551,7 +551,7 @@  discard block
 block discarded – undo
551 551
 	 * @throws EE_Error
552 552
 	 */
553 553
 	public function is_declined() {
554
-		return $this->status_is( EEM_Payment::status_id_declined );
554
+		return $this->status_is(EEM_Payment::status_id_declined);
555 555
 	}
556 556
 
557 557
 
@@ -563,7 +563,7 @@  discard block
 block discarded – undo
563 563
 	 * @throws EE_Error
564 564
 	 */
565 565
 	public function is_failed() {
566
-		return $this->status_is( EEM_Payment::status_id_failed );
566
+		return $this->status_is(EEM_Payment::status_id_failed);
567 567
 	}
568 568
 
569 569
 
@@ -587,7 +587,7 @@  discard block
 block discarded – undo
587 587
 	 * @throws EE_Error
588 588
 	 */
589 589
 	public function status_obj() {
590
-		return $this->get_first_related( 'Status' );
590
+		return $this->get_first_related('Status');
591 591
 	}
592 592
 
593 593
 
@@ -599,8 +599,8 @@  discard block
 block discarded – undo
599 599
 	 * @return EE_Extra_Meta
600 600
 	 * @throws EE_Error
601 601
 	 */
602
-	public function extra_meta( $query_params = array() ) {
603
-		return $this->get_many_related( 'Extra_Meta', $query_params );
602
+	public function extra_meta($query_params = array()) {
603
+		return $this->get_many_related('Extra_Meta', $query_params);
604 604
 	}
605 605
 
606 606
 
@@ -614,7 +614,7 @@  discard block
 block discarded – undo
614 614
 	 * @throws EE_Error
615 615
 	 */
616 616
 	public function payment_method() {
617
-		return $this->get_first_related( 'Payment_Method' );
617
+		return $this->get_first_related('Payment_Method');
618 618
 	}
619 619
 
620 620
 
@@ -632,18 +632,18 @@  discard block
 block discarded – undo
632 632
 	 * @return string html
633 633
 	 * @throws EE_Error
634 634
 	 */
635
-	public function redirect_form( $inside_form_html = null ) {
635
+	public function redirect_form($inside_form_html = null) {
636 636
 		$redirect_url = $this->redirect_url();
637
-		if ( ! empty( $redirect_url ) ) {
637
+		if ( ! empty($redirect_url)) {
638 638
 			// what ? no inner form content?
639
-			if ( $inside_form_html === null ) {
639
+			if ($inside_form_html === null) {
640 640
 				$inside_form_html = EEH_HTML::p(
641 641
 					sprintf(
642 642
 						__(
643 643
 							'If you are not automatically redirected to the payment website within 10 seconds... %1$s %2$s Click Here %3$s',
644 644
 							'event_espresso'
645 645
 						),
646
-						EEH_HTML::br( 2 ),
646
+						EEH_HTML::br(2),
647 647
 						'<input type="submit" value="',
648 648
 						'">'
649 649
 					),
@@ -659,22 +659,22 @@  discard block
 block discarded – undo
659 659
 			);
660 660
 			//if it's a GET request, we need to remove all the GET params in the querystring
661 661
 			//and put them into the form instead
662
-			if ( $method === 'GET' ) {
663
-				$querystring = parse_url( $redirect_url, PHP_URL_QUERY );
662
+			if ($method === 'GET') {
663
+				$querystring = parse_url($redirect_url, PHP_URL_QUERY);
664 664
 				$get_params = null;
665
-				parse_str( $querystring, $get_params );
666
-				$inside_form_html .= $this->_args_as_inputs( $get_params );
667
-				$redirect_url = str_replace( '?' . $querystring, '', $redirect_url );
665
+				parse_str($querystring, $get_params);
666
+				$inside_form_html .= $this->_args_as_inputs($get_params);
667
+				$redirect_url = str_replace('?'.$querystring, '', $redirect_url);
668 668
 			}
669
-			$form = EEH_HTML::nl( 1 )
669
+			$form = EEH_HTML::nl(1)
670 670
 			        . '<form method="'
671 671
 			        . $method
672 672
 			        . '" name="gateway_form" action="'
673 673
 			        . $redirect_url
674 674
 			        . '">';
675
-			$form .= EEH_HTML::nl( 1 ) . $this->redirect_args_as_inputs();
675
+			$form .= EEH_HTML::nl(1).$this->redirect_args_as_inputs();
676 676
 			$form .= $inside_form_html;
677
-			$form .= EEH_HTML::nl( -1 ) . '</form>' . EEH_HTML::nl( -1 );
677
+			$form .= EEH_HTML::nl( -1 ).'</form>'.EEH_HTML::nl( -1 );
678 678
 			return $form;
679 679
 		} else {
680 680
 			return null;
@@ -691,7 +691,7 @@  discard block
 block discarded – undo
691 691
 	 * @throws EE_Error
692 692
 	 */
693 693
 	public function redirect_args_as_inputs() {
694
-		return $this->_args_as_inputs( $this->redirect_args() );
694
+		return $this->_args_as_inputs($this->redirect_args());
695 695
 	}
696 696
 
697 697
 
@@ -703,15 +703,15 @@  discard block
 block discarded – undo
703 703
 	 * @param array $args key-value pairs
704 704
 	 * @return string
705 705
 	 */
706
-	protected function _args_as_inputs( $args ) {
706
+	protected function _args_as_inputs($args) {
707 707
 		$html = '';
708
-		if ( $args !== null && is_array( $args ) ) {
709
-			foreach ( $args as $name => $value ) {
710
-				$html .= EEH_HTML::nl( 0 )
708
+		if ($args !== null && is_array($args)) {
709
+			foreach ($args as $name => $value) {
710
+				$html .= EEH_HTML::nl(0)
711 711
 				         . '<input type="hidden" name="'
712 712
 				         . $name
713 713
 				         . '" value="'
714
-				         . esc_attr( $value )
714
+				         . esc_attr($value)
715 715
 				         . '"/>';
716 716
 			}
717 717
 		}
@@ -740,14 +740,14 @@  discard block
 block discarded – undo
740 740
 	 * @access private
741 741
 	 * @param mixed $item
742 742
 	 */
743
-	private function _strip_all_tags_within_array( &$item ) {
744
-		if ( is_object( $item ) ) {
745
-			$item = (array)$item;
743
+	private function _strip_all_tags_within_array(&$item) {
744
+		if (is_object($item)) {
745
+			$item = (array) $item;
746 746
 		}
747
-		if ( is_array( $item ) ) {
748
-			array_walk_recursive( $item, array( $this, '_strip_all_tags_within_array' ) );
747
+		if (is_array($item)) {
748
+			array_walk_recursive($item, array($this, '_strip_all_tags_within_array'));
749 749
 		} else {
750
-			$item = wp_strip_all_tags( $item );
750
+			$item = wp_strip_all_tags($item);
751 751
 		}
752 752
 	}
753 753
 
@@ -764,7 +764,7 @@  discard block
 block discarded – undo
764 764
 		$original_status = EEH_Array::is_set(
765 765
 			$this->_props_n_values_provided_in_constructor,
766 766
 			'STS_ID',
767
-			$this->get_model()->field_settings_for( 'STS_ID' )->get_default_value()
767
+			$this->get_model()->field_settings_for('STS_ID')->get_default_value()
768 768
 		);
769 769
 		$current_status = $this->status();
770 770
 		if (
@@ -790,11 +790,11 @@  discard block
 block discarded – undo
790 790
 	 * @return mixed
791 791
 	 * @throws EE_Error
792 792
 	 */
793
-	public function get_pretty( $field_name, $extra_cache_ref = null ) {
794
-		if ( $field_name === 'PAY_gateway' ) {
795
-			return $this->payment_method() ? $this->payment_method()->name() : __( 'Unknown', 'event_espresso' );
793
+	public function get_pretty($field_name, $extra_cache_ref = null) {
794
+		if ($field_name === 'PAY_gateway') {
795
+			return $this->payment_method() ? $this->payment_method()->name() : __('Unknown', 'event_espresso');
796 796
 		}
797
-		return $this->_get_cached_property( $field_name, true, $extra_cache_ref );
797
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
798 798
 	}
799 799
 
800 800
 
@@ -806,8 +806,8 @@  discard block
 block discarded – undo
806 806
 	 * @return EE_Registration_Payment[]
807 807
 	 * @throws EE_Error
808 808
 	 */
809
-	public function registration_payments( $query_params = array() ) {
810
-		return $this->get_many_related( 'Registration_Payment', $query_params );
809
+	public function registration_payments($query_params = array()) {
810
+		return $this->get_many_related('Registration_Payment', $query_params);
811 811
 	}
812 812
 
813 813
 
@@ -865,7 +865,7 @@  discard block
 block discarded – undo
865 865
     public function get_primary_attendee()
866 866
     {
867 867
         $primary_reg = $this->get_primary_registration();
868
-        if( $primary_reg instanceof EE_Registration) {
868
+        if ($primary_reg instanceof EE_Registration) {
869 869
             return $primary_reg->attendee();
870 870
         }
871 871
         return null;
Please login to merge, or discard this patch.
core/libraries/payment_methods/EE_PMT_Base.lib.php 1 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.