Completed
Branch models-cleanup/main (0d2dda)
by
unknown
09:34
created
core/db_models/EEM_Payment_Method.model.php 2 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -32,7 +32,7 @@  discard block
 block discarded – undo
32 32
     /**
33 33
      * private constructor to prevent direct creation
34 34
      *
35
-     * @param null $timezone
35
+     * @param string|null $timezone
36 36
      * @throws EE_Error
37 37
      */
38 38
     protected function __construct($timezone = '')
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
      *
290 290
      * @param string|int|EE_Payment_Method $base_class_obj_or_id
291 291
      * @param boolean                      $ensure_is_in_db
292
-     * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|int|string
292
+     * @return EE_Base_Class|null
293 293
      * @throws EE_Error
294 294
      * @see EEM_Base::ensure_is_obj()
295 295
      */
@@ -454,7 +454,7 @@  discard block
 block discarded – undo
454 454
      *
455 455
      * @param EE_Registration|int $registration_or_reg_id Either the EE_Registration object or the id for the
456 456
      *                                                    registration.
457
-     * @return EE_Payment|null
457
+     * @return null|EE_Base_Class
458 458
      * @throws EE_Error
459 459
      */
460 460
     public function get_last_used_for_registration($registration_or_reg_id)
Please login to merge, or discard this patch.
Indentation   +452 added lines, -452 removed lines patch added patch discarded remove patch
@@ -17,456 +17,456 @@
 block discarded – undo
17 17
 class EEM_Payment_Method extends EEM_Base
18 18
 {
19 19
 
20
-    const scope_cart = 'CART';
21
-
22
-    const scope_admin = 'ADMIN';
23
-
24
-    const scope_api = 'API';
25
-
26
-    /**
27
-     * @type EEM_Payment_Method
28
-     */
29
-    protected static $_instance = null;
30
-
31
-
32
-    /**
33
-     * private constructor to prevent direct creation
34
-     *
35
-     * @param null $timezone
36
-     * @throws EE_Error
37
-     */
38
-    protected function __construct($timezone = '')
39
-    {
40
-        $this->singular_item = esc_html__('Payment Method', 'event_espresso');
41
-        $this->plural_item = esc_html__('Payment Methods', 'event_espresso');
42
-        $this->_tables = [
43
-            'Payment_Method' => new EE_Primary_Table('esp_payment_method', 'PMD_ID'),
44
-        ];
45
-        $this->_fields = [
46
-            'Payment_Method' => [
47
-                'PMD_ID'              => new EE_Primary_Key_Int_Field(
48
-                    'PMD_ID',
49
-                    esc_html__('ID', 'event_espresso')
50
-                ),
51
-                'PMD_type'            => new EE_Plain_Text_Field(
52
-                    'PMD_type',
53
-                    esc_html__('Payment Method Type', 'event_espresso'),
54
-                    false,
55
-                    'Admin_Only'
56
-                ),
57
-                'PMD_name'            => new EE_Plain_Text_Field(
58
-                    'PMD_name',
59
-                    esc_html__('Name', 'event_espresso'),
60
-                    false
61
-                ),
62
-                'PMD_desc'            => new EE_Post_Content_Field(
63
-                    'PMD_desc',
64
-                    esc_html__('Description', 'event_espresso'),
65
-                    false,
66
-                    ''
67
-                ),
68
-                'PMD_admin_name'      => new EE_Plain_Text_Field(
69
-                    'PMD_admin_name',
70
-                    esc_html__('Admin-Only Name', 'event_espresso'),
71
-                    true
72
-                ),
73
-                'PMD_admin_desc'      => new EE_Post_Content_Field(
74
-                    'PMD_admin_desc',
75
-                    esc_html__('Admin-Only Description', 'event_espresso'),
76
-                    true
77
-                ),
78
-                'PMD_slug'            => new EE_Slug_Field(
79
-                    'PMD_slug',
80
-                    esc_html__('Slug', 'event_espresso'),
81
-                    false
82
-                ),
83
-                'PMD_order'           => new EE_Integer_Field(
84
-                    'PMD_order',
85
-                    esc_html__('Order', 'event_espresso'),
86
-                    false,
87
-                    0
88
-                ),
89
-                'PMD_debug_mode'      => new EE_Boolean_Field(
90
-                    'PMD_debug_mode',
91
-                    esc_html__('Debug Mode On?', 'event_espresso'),
92
-                    false,
93
-                    false
94
-                ),
95
-                'PMD_wp_user'         => new EE_WP_User_Field(
96
-                    'PMD_wp_user',
97
-                    esc_html__('Payment Method Creator ID', 'event_espresso'),
98
-                    false
99
-                ),
100
-                'PMD_open_by_default' => new EE_Boolean_Field(
101
-                    'PMD_open_by_default',
102
-                    esc_html__('Open by Default?', 'event_espresso'),
103
-                    false,
104
-                    false
105
-                ),
106
-                'PMD_button_url'      => new EE_Plain_Text_Field(
107
-                    'PMD_button_url',
108
-                    esc_html__('Button URL', 'event_espresso'),
109
-                    true,
110
-                    ''
111
-                ),
112
-                'PMD_scope'           => new EE_Serialized_Text_Field(
113
-                    'PMD_scope',
114
-                    esc_html__('Usable From?', 'event_espresso'),
115
-                    false,
116
-                    []// possible values currently are 'CART','ADMIN','API'
117
-                ),
118
-            ],
119
-        ];
120
-        $this->_model_relations = [
121
-            'Payment'     => new EE_Has_Many_Relation(),
122
-            'Currency'    => new EE_HABTM_Relation('Currency_Payment_Method'),
123
-            'Transaction' => new EE_Has_Many_Relation(),
124
-            'WP_User'     => new EE_Belongs_To_Relation(),
125
-        ];
126
-        parent::__construct($timezone);
127
-    }
128
-
129
-
130
-    /**
131
-     * Gets one by the slug provided
132
-     *
133
-     * @param string $slug
134
-     * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
135
-     * @throws EE_Error
136
-     */
137
-    public function get_one_by_slug($slug)
138
-    {
139
-        return $this->get_one([['PMD_slug' => $slug]]);
140
-    }
141
-
142
-
143
-    /**
144
-     * Gets all the acceptable scopes for payment methods.
145
-     * Keys are their names as store din the DB, and values are nice names for displaying them
146
-     *
147
-     * @return array
148
-     */
149
-    public function scopes()
150
-    {
151
-        return apply_filters(
152
-            'FHEE__EEM_Payment_Method__scopes',
153
-            [
154
-                EEM_Payment_Method::scope_cart  => esc_html__('Front-end Registration Page', 'event_espresso'),
155
-                EEM_Payment_Method::scope_admin => esc_html__(
156
-                    'Admin Registration Page (no online processing)',
157
-                    'event_espresso'
158
-                ),
159
-            ]
160
-        );
161
-    }
162
-
163
-
164
-    /**
165
-     * Determines if this is an valid scope
166
-     *
167
-     * @param string $scope like one of EEM_Payment_Method::instance()->scopes()
168
-     * @return boolean
169
-     */
170
-    public function is_valid_scope($scope)
171
-    {
172
-        $scopes = $this->scopes();
173
-        if (isset($scopes[ $scope ])) {
174
-            return true;
175
-        }
176
-        return false;
177
-    }
178
-
179
-
180
-    /**
181
-     * Gets all active payment methods
182
-     *
183
-     * @param string $scope one of
184
-     * @param array  $query_params
185
-     * @return EE_Base_Class[]|EE_Payment_Method[]
186
-     * @throws EE_Error
187
-     */
188
-    public function get_all_active($scope = null, $query_params = [])
189
-    {
190
-        if (! isset($query_params['order_by']) && ! isset($query_params['order'])) {
191
-            $query_params['order_by'] = ['PMD_order' => 'ASC', 'PMD_ID' => 'ASC'];
192
-        }
193
-        return $this->get_all($this->_get_query_params_for_all_active($scope, $query_params));
194
-    }
195
-
196
-
197
-    /**
198
-     * Counts all active gateways in the specified scope
199
-     *
200
-     * @param string $scope one of EEM_Payment_Method::scope_*
201
-     * @param array  $query_params
202
-     * @return int
203
-     * @throws EE_Error
204
-     */
205
-    public function count_active($scope = null, $query_params = [])
206
-    {
207
-        return $this->count($this->_get_query_params_for_all_active($scope, $query_params));
208
-    }
209
-
210
-
211
-    /**
212
-     * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
213
-     * argument to get all active for a given scope
214
-     *
215
-     * @param string $scope one of the constants EEM_Payment_Method::scope_*
216
-     * @param array  $query_params
217
-     * @return array
218
-     * @throws EE_Error
219
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
220
-     */
221
-    protected function _get_query_params_for_all_active($scope = null, $query_params = [])
222
-    {
223
-        if ($scope) {
224
-            if ($this->is_valid_scope($scope)) {
225
-                return array_replace_recursive([['PMD_scope' => ['LIKE', "%$scope%"]]], $query_params);
226
-            }
227
-            throw new EE_Error(
228
-                sprintf(
229
-                    esc_html__("'%s' is not a valid scope for a payment method", 'event_espresso'),
230
-                    $scope
231
-                )
232
-            );
233
-        }
234
-        $acceptable_scopes = [];
235
-        $count = 0;
236
-        foreach ($this->scopes() as $scope_name => $desc) {
237
-            $count++;
238
-            $acceptable_scopes[ 'PMD_scope*' . $count ] = ['LIKE', '%' . $scope_name . '%'];
239
-        }
240
-        return array_replace_recursive([['OR*active_scope' => $acceptable_scopes]], $query_params);
241
-    }
242
-
243
-
244
-    /**
245
-     * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
246
-     * argument to get all active for a given scope
247
-     *
248
-     * @param string $scope one of the constants EEM_Payment_Method::scope_*
249
-     * @param array  $query_params
250
-     * @return array
251
-     * @throws EE_Error
252
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
253
-     */
254
-    public function get_query_params_for_all_active($scope = null, $query_params = [])
255
-    {
256
-        return $this->_get_query_params_for_all_active($scope, $query_params);
257
-    }
258
-
259
-
260
-    /**
261
-     * Gets one active payment method. see @get_all_active for documentation
262
-     *
263
-     * @param string $scope
264
-     * @param array  $query_params
265
-     * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
266
-     * @throws EE_Error
267
-     */
268
-    public function get_one_active($scope = null, $query_params = [])
269
-    {
270
-        return $this->get_one($this->_get_query_params_for_all_active($scope, $query_params));
271
-    }
272
-
273
-
274
-    /**
275
-     * Gets one payment method of that type, regardless of whether its active or not
276
-     *
277
-     * @param string $type
278
-     * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
279
-     * @throws EE_Error
280
-     */
281
-    public function get_one_of_type($type)
282
-    {
283
-        return $this->get_one([['PMD_type' => $type]]);
284
-    }
285
-
286
-
287
-    /**
288
-     * Overrides parent ot also check by the slug
289
-     *
290
-     * @param string|int|EE_Payment_Method $base_class_obj_or_id
291
-     * @param boolean                      $ensure_is_in_db
292
-     * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|int|string
293
-     * @throws EE_Error
294
-     * @see EEM_Base::ensure_is_obj()
295
-     */
296
-    public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false)
297
-    {
298
-        // first: check if it's a slug
299
-        if (is_string($base_class_obj_or_id)) {
300
-            $obj = $this->get_one_by_slug($base_class_obj_or_id);
301
-            if ($obj) {
302
-                return $obj;
303
-            }
304
-        }
305
-        // ok so it wasn't a slug we were passed. try the usual then (ie, it's an object or an ID)
306
-        try {
307
-            return parent::ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db);
308
-        } catch (EE_Error $e) {
309
-            // handle it outside the catch
310
-        }
311
-        throw new EE_Error(
312
-            sprintf(
313
-                esc_html__("'%s' is neither a Payment Method ID, slug, nor object.", 'event_espresso'),
314
-                $base_class_obj_or_id
315
-            )
316
-        );
317
-    }
318
-
319
-
320
-    /**
321
-     * Gets the ID of this object, or if its a string finds the object's id
322
-     * associated with that slug
323
-     *
324
-     * @param mixed $base_obj_or_id_or_slug
325
-     * @return int
326
-     * @throws EE_Error
327
-     */
328
-    public function ensure_is_ID($base_obj_or_id_or_slug)
329
-    {
330
-        if (is_string($base_obj_or_id_or_slug)) {
331
-            // assume it's a slug
332
-            $base_obj_or_id_or_slug = $this->get_one_by_slug($base_obj_or_id_or_slug);
333
-        }
334
-        return parent::ensure_is_ID($base_obj_or_id_or_slug);
335
-    }
336
-
337
-
338
-    /**
339
-     * Verifies the button urls on all the passed payment methods have a valid button url.
340
-     * If not, resets them to their default.
341
-     *
342
-     * @param EE_Payment_Method[] $payment_methods if NULL, defaults to all payment methods active in the cart
343
-     * @throws EE_Error
344
-     * @throws ReflectionException
345
-     */
346
-    public function verify_button_urls($payment_methods = null)
347
-    {
348
-        $payment_methods = is_array($payment_methods)
349
-            ? $payment_methods
350
-            : $this->get_all_active(EEM_Payment_Method::scope_cart);
351
-        foreach ($payment_methods as $payment_method) {
352
-            try {
353
-                // If there is really no button URL at all, or if the button URLs still point to decaf folder even
354
-                // though this is a caffeinated install, reset it to the default.
355
-                $current_button_url = $payment_method->button_url();
356
-                if (
357
-                    empty($current_button_url)
358
-                    || (
359
-                        strpos($current_button_url, 'decaf') !== false
360
-                        && strpos($payment_method->type_obj()->default_button_url(), 'decaf') === false
361
-                    )
362
-                ) {
363
-                    $payment_method->save(
364
-                        [
365
-                            'PMD_button_url' => $payment_method->type_obj()->default_button_url(),
366
-                        ]
367
-                    );
368
-                }
369
-            } catch (EE_Error $e) {
370
-                $payment_method->deactivate();
371
-            }
372
-        }
373
-    }
374
-
375
-
376
-    /**
377
-     * Overrides parent to not only turn wpdb results into EE_Payment_Method objects,
378
-     * but also verifies the payment method type of each is a usable object. If not,
379
-     * deactivate it, sets a notification, and deactivates it
380
-     *
381
-     * @param array $rows
382
-     * @return EE_Payment_Method[]
383
-     * @throws EE_Error
384
-     * @throws InvalidDataTypeException
385
-     * @throws ReflectionException
386
-     */
387
-    protected function _create_objects($rows = [])
388
-    {
389
-        EE_Registry::instance()->load_lib('Payment_Method_Manager');
390
-        $payment_methods = parent::_create_objects($rows);
391
-        /* @var $payment_methods EE_Payment_Method[] */
392
-        $usable_payment_methods = [];
393
-        foreach ($payment_methods as $key => $payment_method) {
394
-            if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($payment_method->type())) {
395
-                $usable_payment_methods[ $key ] = $payment_method;
396
-                // some payment methods enqueue their scripts in EE_PMT_*::__construct
397
-                // which is kinda a no-no (just because it's being constructed doesn't mean we need to enqueue
398
-                // its scripts). but for backwards-compat we should continue to do that
399
-                $payment_method->type_obj();
400
-            } elseif ($payment_method->active()) {
401
-                // only deactivate and notify the admin if the payment is active somewhere
402
-                $payment_method->deactivate();
403
-                $payment_method->save();
404
-                do_action(
405
-                    'AHEE__EEM_Payment_Method___create_objects_auto_deactivated_payment_method',
406
-                    $payment_method
407
-                );
408
-                new PersistentAdminNotice(
409
-                    'auto-deactivated-' . $payment_method->type(),
410
-                    sprintf(
411
-                        esc_html__(
412
-                            'The payment method %1$s was automatically deactivated because it appears its associated Event Espresso Addon was recently deactivated.%2$sIt can be reactivated on the %3$sPlugins admin page%4$s, then you can reactivate the payment method.',
413
-                            'event_espresso'
414
-                        ),
415
-                        $payment_method->admin_name(),
416
-                        '<br />',
417
-                        '<a href="' . admin_url('plugins.php') . '">',
418
-                        '</a>'
419
-                    ),
420
-                    true
421
-                );
422
-            }
423
-        }
424
-        return $usable_payment_methods;
425
-    }
426
-
427
-
428
-    /**
429
-     * Gets all the payment methods which can be used for transaction
430
-     * (according to the relations between payment methods and events, and
431
-     * the currencies used for the transaction and their relation to payment methods)
432
-     *
433
-     * @param EE_Transaction $transaction
434
-     * @param string         $scope @see EEM_Payment_Method::get_all_for_events
435
-     * @return EE_Payment_Method[]
436
-     * @throws EE_Error
437
-     */
438
-    public function get_all_for_transaction($transaction, $scope)
439
-    {
440
-        // give addons a chance to override what payment methods are chosen based on the transaction
441
-        return apply_filters(
442
-            'FHEE__EEM_Payment_Method__get_all_for_transaction__payment_methods',
443
-            $this->get_all_active($scope, ['group_by' => 'PMD_type']),
444
-            $transaction,
445
-            $scope
446
-        );
447
-    }
448
-
449
-
450
-    /**
451
-     * Returns the payment method used for the last payment made for a registration.
452
-     * Note: if an offline payment method was selected on the related transaction then this will have no payment
453
-     * methods returned. It will ONLY return a payment method for a PAYMENT recorded against the registration.
454
-     *
455
-     * @param EE_Registration|int $registration_or_reg_id Either the EE_Registration object or the id for the
456
-     *                                                    registration.
457
-     * @return EE_Payment|null
458
-     * @throws EE_Error
459
-     */
460
-    public function get_last_used_for_registration($registration_or_reg_id)
461
-    {
462
-        $registration_id = EEM_Registration::instance()->ensure_is_ID($registration_or_reg_id);
463
-
464
-        $query_params = [
465
-            0          => [
466
-                'Payment.Registration.REG_ID' => $registration_id,
467
-            ],
468
-            'order_by' => ['Payment.PAY_ID' => 'DESC'],
469
-        ];
470
-        return $this->get_one($query_params);
471
-    }
20
+	const scope_cart = 'CART';
21
+
22
+	const scope_admin = 'ADMIN';
23
+
24
+	const scope_api = 'API';
25
+
26
+	/**
27
+	 * @type EEM_Payment_Method
28
+	 */
29
+	protected static $_instance = null;
30
+
31
+
32
+	/**
33
+	 * private constructor to prevent direct creation
34
+	 *
35
+	 * @param null $timezone
36
+	 * @throws EE_Error
37
+	 */
38
+	protected function __construct($timezone = '')
39
+	{
40
+		$this->singular_item = esc_html__('Payment Method', 'event_espresso');
41
+		$this->plural_item = esc_html__('Payment Methods', 'event_espresso');
42
+		$this->_tables = [
43
+			'Payment_Method' => new EE_Primary_Table('esp_payment_method', 'PMD_ID'),
44
+		];
45
+		$this->_fields = [
46
+			'Payment_Method' => [
47
+				'PMD_ID'              => new EE_Primary_Key_Int_Field(
48
+					'PMD_ID',
49
+					esc_html__('ID', 'event_espresso')
50
+				),
51
+				'PMD_type'            => new EE_Plain_Text_Field(
52
+					'PMD_type',
53
+					esc_html__('Payment Method Type', 'event_espresso'),
54
+					false,
55
+					'Admin_Only'
56
+				),
57
+				'PMD_name'            => new EE_Plain_Text_Field(
58
+					'PMD_name',
59
+					esc_html__('Name', 'event_espresso'),
60
+					false
61
+				),
62
+				'PMD_desc'            => new EE_Post_Content_Field(
63
+					'PMD_desc',
64
+					esc_html__('Description', 'event_espresso'),
65
+					false,
66
+					''
67
+				),
68
+				'PMD_admin_name'      => new EE_Plain_Text_Field(
69
+					'PMD_admin_name',
70
+					esc_html__('Admin-Only Name', 'event_espresso'),
71
+					true
72
+				),
73
+				'PMD_admin_desc'      => new EE_Post_Content_Field(
74
+					'PMD_admin_desc',
75
+					esc_html__('Admin-Only Description', 'event_espresso'),
76
+					true
77
+				),
78
+				'PMD_slug'            => new EE_Slug_Field(
79
+					'PMD_slug',
80
+					esc_html__('Slug', 'event_espresso'),
81
+					false
82
+				),
83
+				'PMD_order'           => new EE_Integer_Field(
84
+					'PMD_order',
85
+					esc_html__('Order', 'event_espresso'),
86
+					false,
87
+					0
88
+				),
89
+				'PMD_debug_mode'      => new EE_Boolean_Field(
90
+					'PMD_debug_mode',
91
+					esc_html__('Debug Mode On?', 'event_espresso'),
92
+					false,
93
+					false
94
+				),
95
+				'PMD_wp_user'         => new EE_WP_User_Field(
96
+					'PMD_wp_user',
97
+					esc_html__('Payment Method Creator ID', 'event_espresso'),
98
+					false
99
+				),
100
+				'PMD_open_by_default' => new EE_Boolean_Field(
101
+					'PMD_open_by_default',
102
+					esc_html__('Open by Default?', 'event_espresso'),
103
+					false,
104
+					false
105
+				),
106
+				'PMD_button_url'      => new EE_Plain_Text_Field(
107
+					'PMD_button_url',
108
+					esc_html__('Button URL', 'event_espresso'),
109
+					true,
110
+					''
111
+				),
112
+				'PMD_scope'           => new EE_Serialized_Text_Field(
113
+					'PMD_scope',
114
+					esc_html__('Usable From?', 'event_espresso'),
115
+					false,
116
+					[]// possible values currently are 'CART','ADMIN','API'
117
+				),
118
+			],
119
+		];
120
+		$this->_model_relations = [
121
+			'Payment'     => new EE_Has_Many_Relation(),
122
+			'Currency'    => new EE_HABTM_Relation('Currency_Payment_Method'),
123
+			'Transaction' => new EE_Has_Many_Relation(),
124
+			'WP_User'     => new EE_Belongs_To_Relation(),
125
+		];
126
+		parent::__construct($timezone);
127
+	}
128
+
129
+
130
+	/**
131
+	 * Gets one by the slug provided
132
+	 *
133
+	 * @param string $slug
134
+	 * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
135
+	 * @throws EE_Error
136
+	 */
137
+	public function get_one_by_slug($slug)
138
+	{
139
+		return $this->get_one([['PMD_slug' => $slug]]);
140
+	}
141
+
142
+
143
+	/**
144
+	 * Gets all the acceptable scopes for payment methods.
145
+	 * Keys are their names as store din the DB, and values are nice names for displaying them
146
+	 *
147
+	 * @return array
148
+	 */
149
+	public function scopes()
150
+	{
151
+		return apply_filters(
152
+			'FHEE__EEM_Payment_Method__scopes',
153
+			[
154
+				EEM_Payment_Method::scope_cart  => esc_html__('Front-end Registration Page', 'event_espresso'),
155
+				EEM_Payment_Method::scope_admin => esc_html__(
156
+					'Admin Registration Page (no online processing)',
157
+					'event_espresso'
158
+				),
159
+			]
160
+		);
161
+	}
162
+
163
+
164
+	/**
165
+	 * Determines if this is an valid scope
166
+	 *
167
+	 * @param string $scope like one of EEM_Payment_Method::instance()->scopes()
168
+	 * @return boolean
169
+	 */
170
+	public function is_valid_scope($scope)
171
+	{
172
+		$scopes = $this->scopes();
173
+		if (isset($scopes[ $scope ])) {
174
+			return true;
175
+		}
176
+		return false;
177
+	}
178
+
179
+
180
+	/**
181
+	 * Gets all active payment methods
182
+	 *
183
+	 * @param string $scope one of
184
+	 * @param array  $query_params
185
+	 * @return EE_Base_Class[]|EE_Payment_Method[]
186
+	 * @throws EE_Error
187
+	 */
188
+	public function get_all_active($scope = null, $query_params = [])
189
+	{
190
+		if (! isset($query_params['order_by']) && ! isset($query_params['order'])) {
191
+			$query_params['order_by'] = ['PMD_order' => 'ASC', 'PMD_ID' => 'ASC'];
192
+		}
193
+		return $this->get_all($this->_get_query_params_for_all_active($scope, $query_params));
194
+	}
195
+
196
+
197
+	/**
198
+	 * Counts all active gateways in the specified scope
199
+	 *
200
+	 * @param string $scope one of EEM_Payment_Method::scope_*
201
+	 * @param array  $query_params
202
+	 * @return int
203
+	 * @throws EE_Error
204
+	 */
205
+	public function count_active($scope = null, $query_params = [])
206
+	{
207
+		return $this->count($this->_get_query_params_for_all_active($scope, $query_params));
208
+	}
209
+
210
+
211
+	/**
212
+	 * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
213
+	 * argument to get all active for a given scope
214
+	 *
215
+	 * @param string $scope one of the constants EEM_Payment_Method::scope_*
216
+	 * @param array  $query_params
217
+	 * @return array
218
+	 * @throws EE_Error
219
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
220
+	 */
221
+	protected function _get_query_params_for_all_active($scope = null, $query_params = [])
222
+	{
223
+		if ($scope) {
224
+			if ($this->is_valid_scope($scope)) {
225
+				return array_replace_recursive([['PMD_scope' => ['LIKE', "%$scope%"]]], $query_params);
226
+			}
227
+			throw new EE_Error(
228
+				sprintf(
229
+					esc_html__("'%s' is not a valid scope for a payment method", 'event_espresso'),
230
+					$scope
231
+				)
232
+			);
233
+		}
234
+		$acceptable_scopes = [];
235
+		$count = 0;
236
+		foreach ($this->scopes() as $scope_name => $desc) {
237
+			$count++;
238
+			$acceptable_scopes[ 'PMD_scope*' . $count ] = ['LIKE', '%' . $scope_name . '%'];
239
+		}
240
+		return array_replace_recursive([['OR*active_scope' => $acceptable_scopes]], $query_params);
241
+	}
242
+
243
+
244
+	/**
245
+	 * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
246
+	 * argument to get all active for a given scope
247
+	 *
248
+	 * @param string $scope one of the constants EEM_Payment_Method::scope_*
249
+	 * @param array  $query_params
250
+	 * @return array
251
+	 * @throws EE_Error
252
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
253
+	 */
254
+	public function get_query_params_for_all_active($scope = null, $query_params = [])
255
+	{
256
+		return $this->_get_query_params_for_all_active($scope, $query_params);
257
+	}
258
+
259
+
260
+	/**
261
+	 * Gets one active payment method. see @get_all_active for documentation
262
+	 *
263
+	 * @param string $scope
264
+	 * @param array  $query_params
265
+	 * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
266
+	 * @throws EE_Error
267
+	 */
268
+	public function get_one_active($scope = null, $query_params = [])
269
+	{
270
+		return $this->get_one($this->_get_query_params_for_all_active($scope, $query_params));
271
+	}
272
+
273
+
274
+	/**
275
+	 * Gets one payment method of that type, regardless of whether its active or not
276
+	 *
277
+	 * @param string $type
278
+	 * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
279
+	 * @throws EE_Error
280
+	 */
281
+	public function get_one_of_type($type)
282
+	{
283
+		return $this->get_one([['PMD_type' => $type]]);
284
+	}
285
+
286
+
287
+	/**
288
+	 * Overrides parent ot also check by the slug
289
+	 *
290
+	 * @param string|int|EE_Payment_Method $base_class_obj_or_id
291
+	 * @param boolean                      $ensure_is_in_db
292
+	 * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|int|string
293
+	 * @throws EE_Error
294
+	 * @see EEM_Base::ensure_is_obj()
295
+	 */
296
+	public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false)
297
+	{
298
+		// first: check if it's a slug
299
+		if (is_string($base_class_obj_or_id)) {
300
+			$obj = $this->get_one_by_slug($base_class_obj_or_id);
301
+			if ($obj) {
302
+				return $obj;
303
+			}
304
+		}
305
+		// ok so it wasn't a slug we were passed. try the usual then (ie, it's an object or an ID)
306
+		try {
307
+			return parent::ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db);
308
+		} catch (EE_Error $e) {
309
+			// handle it outside the catch
310
+		}
311
+		throw new EE_Error(
312
+			sprintf(
313
+				esc_html__("'%s' is neither a Payment Method ID, slug, nor object.", 'event_espresso'),
314
+				$base_class_obj_or_id
315
+			)
316
+		);
317
+	}
318
+
319
+
320
+	/**
321
+	 * Gets the ID of this object, or if its a string finds the object's id
322
+	 * associated with that slug
323
+	 *
324
+	 * @param mixed $base_obj_or_id_or_slug
325
+	 * @return int
326
+	 * @throws EE_Error
327
+	 */
328
+	public function ensure_is_ID($base_obj_or_id_or_slug)
329
+	{
330
+		if (is_string($base_obj_or_id_or_slug)) {
331
+			// assume it's a slug
332
+			$base_obj_or_id_or_slug = $this->get_one_by_slug($base_obj_or_id_or_slug);
333
+		}
334
+		return parent::ensure_is_ID($base_obj_or_id_or_slug);
335
+	}
336
+
337
+
338
+	/**
339
+	 * Verifies the button urls on all the passed payment methods have a valid button url.
340
+	 * If not, resets them to their default.
341
+	 *
342
+	 * @param EE_Payment_Method[] $payment_methods if NULL, defaults to all payment methods active in the cart
343
+	 * @throws EE_Error
344
+	 * @throws ReflectionException
345
+	 */
346
+	public function verify_button_urls($payment_methods = null)
347
+	{
348
+		$payment_methods = is_array($payment_methods)
349
+			? $payment_methods
350
+			: $this->get_all_active(EEM_Payment_Method::scope_cart);
351
+		foreach ($payment_methods as $payment_method) {
352
+			try {
353
+				// If there is really no button URL at all, or if the button URLs still point to decaf folder even
354
+				// though this is a caffeinated install, reset it to the default.
355
+				$current_button_url = $payment_method->button_url();
356
+				if (
357
+					empty($current_button_url)
358
+					|| (
359
+						strpos($current_button_url, 'decaf') !== false
360
+						&& strpos($payment_method->type_obj()->default_button_url(), 'decaf') === false
361
+					)
362
+				) {
363
+					$payment_method->save(
364
+						[
365
+							'PMD_button_url' => $payment_method->type_obj()->default_button_url(),
366
+						]
367
+					);
368
+				}
369
+			} catch (EE_Error $e) {
370
+				$payment_method->deactivate();
371
+			}
372
+		}
373
+	}
374
+
375
+
376
+	/**
377
+	 * Overrides parent to not only turn wpdb results into EE_Payment_Method objects,
378
+	 * but also verifies the payment method type of each is a usable object. If not,
379
+	 * deactivate it, sets a notification, and deactivates it
380
+	 *
381
+	 * @param array $rows
382
+	 * @return EE_Payment_Method[]
383
+	 * @throws EE_Error
384
+	 * @throws InvalidDataTypeException
385
+	 * @throws ReflectionException
386
+	 */
387
+	protected function _create_objects($rows = [])
388
+	{
389
+		EE_Registry::instance()->load_lib('Payment_Method_Manager');
390
+		$payment_methods = parent::_create_objects($rows);
391
+		/* @var $payment_methods EE_Payment_Method[] */
392
+		$usable_payment_methods = [];
393
+		foreach ($payment_methods as $key => $payment_method) {
394
+			if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($payment_method->type())) {
395
+				$usable_payment_methods[ $key ] = $payment_method;
396
+				// some payment methods enqueue their scripts in EE_PMT_*::__construct
397
+				// which is kinda a no-no (just because it's being constructed doesn't mean we need to enqueue
398
+				// its scripts). but for backwards-compat we should continue to do that
399
+				$payment_method->type_obj();
400
+			} elseif ($payment_method->active()) {
401
+				// only deactivate and notify the admin if the payment is active somewhere
402
+				$payment_method->deactivate();
403
+				$payment_method->save();
404
+				do_action(
405
+					'AHEE__EEM_Payment_Method___create_objects_auto_deactivated_payment_method',
406
+					$payment_method
407
+				);
408
+				new PersistentAdminNotice(
409
+					'auto-deactivated-' . $payment_method->type(),
410
+					sprintf(
411
+						esc_html__(
412
+							'The payment method %1$s was automatically deactivated because it appears its associated Event Espresso Addon was recently deactivated.%2$sIt can be reactivated on the %3$sPlugins admin page%4$s, then you can reactivate the payment method.',
413
+							'event_espresso'
414
+						),
415
+						$payment_method->admin_name(),
416
+						'<br />',
417
+						'<a href="' . admin_url('plugins.php') . '">',
418
+						'</a>'
419
+					),
420
+					true
421
+				);
422
+			}
423
+		}
424
+		return $usable_payment_methods;
425
+	}
426
+
427
+
428
+	/**
429
+	 * Gets all the payment methods which can be used for transaction
430
+	 * (according to the relations between payment methods and events, and
431
+	 * the currencies used for the transaction and their relation to payment methods)
432
+	 *
433
+	 * @param EE_Transaction $transaction
434
+	 * @param string         $scope @see EEM_Payment_Method::get_all_for_events
435
+	 * @return EE_Payment_Method[]
436
+	 * @throws EE_Error
437
+	 */
438
+	public function get_all_for_transaction($transaction, $scope)
439
+	{
440
+		// give addons a chance to override what payment methods are chosen based on the transaction
441
+		return apply_filters(
442
+			'FHEE__EEM_Payment_Method__get_all_for_transaction__payment_methods',
443
+			$this->get_all_active($scope, ['group_by' => 'PMD_type']),
444
+			$transaction,
445
+			$scope
446
+		);
447
+	}
448
+
449
+
450
+	/**
451
+	 * Returns the payment method used for the last payment made for a registration.
452
+	 * Note: if an offline payment method was selected on the related transaction then this will have no payment
453
+	 * methods returned. It will ONLY return a payment method for a PAYMENT recorded against the registration.
454
+	 *
455
+	 * @param EE_Registration|int $registration_or_reg_id Either the EE_Registration object or the id for the
456
+	 *                                                    registration.
457
+	 * @return EE_Payment|null
458
+	 * @throws EE_Error
459
+	 */
460
+	public function get_last_used_for_registration($registration_or_reg_id)
461
+	{
462
+		$registration_id = EEM_Registration::instance()->ensure_is_ID($registration_or_reg_id);
463
+
464
+		$query_params = [
465
+			0          => [
466
+				'Payment.Registration.REG_ID' => $registration_id,
467
+			],
468
+			'order_by' => ['Payment.PAY_ID' => 'DESC'],
469
+		];
470
+		return $this->get_one($query_params);
471
+	}
472 472
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Question.model.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -104,7 +104,7 @@
 block discarded – undo
104 104
     /**
105 105
      * EEM_Question constructor.
106 106
      *
107
-     * @param null $timezone
107
+     * @param string|null $timezone
108 108
      */
109 109
     protected function __construct($timezone = '')
110 110
     {
Please login to merge, or discard this patch.
Indentation   +573 added lines, -573 removed lines patch added patch discarded remove patch
@@ -10,578 +10,578 @@
 block discarded – undo
10 10
 class EEM_Question extends EEM_Soft_Delete_Base
11 11
 {
12 12
 
13
-    // constant used to indicate that the question type is CHECKBOX
14
-    const QST_type_checkbox = 'CHECKBOX';
13
+	// constant used to indicate that the question type is CHECKBOX
14
+	const QST_type_checkbox = 'CHECKBOX';
15 15
 
16
-    // constant used to indicate that the question type is COUNTRY
17
-    const QST_type_country = 'COUNTRY';
18
-
19
-    // constant used to indicate that the question type is DATE
20
-    const QST_type_date = 'DATE';
21
-
22
-    // constant used to indicate that the question type is a decimal (float)
23
-    const QST_type_decimal = 'DECIMAL';
24
-
25
-    // constant used to indicate that the question type is DROPDOWN
26
-    const QST_type_dropdown = 'DROPDOWN';
27
-
28
-    // constant used to indicate that the question type is an email input
29
-    const QST_type_email = 'EMAIL';
30
-
31
-    // constant used to indicate that the question type is an email input
32
-    const QST_type_email_confirm = 'EMAIL_CONFIRM';
33
-
34
-    // constant used to indicate that the question type is a TEXTAREA that allows simple html
35
-    const QST_type_html_textarea = 'HTML_TEXTAREA';
36
-
37
-    // constant used to indicate that the question type is an integer (whole number)
38
-    const QST_type_int = 'INTEGER';
39
-
40
-    // constant used to indicate that the question type is a multi-select
41
-    const QST_type_multi_select = 'MULTI_SELECT';
42
-
43
-    // constant used to indicate that the question type is RADIO_BTN
44
-    const QST_type_radio = 'RADIO_BTN';
45
-
46
-    // constant used to indicate that the question type is STATE
47
-    const QST_type_state = 'STATE';
48
-
49
-    // constant used to indicate that the question type is TEXT
50
-    const QST_type_text = 'TEXT';
51
-
52
-    // constant used to indicate that the question type is TEXTAREA
53
-    const QST_type_textarea = 'TEXTAREA';
54
-
55
-    // constant used to indicate that the question type is a valid URL
56
-    const QST_type_url = 'URL';
57
-
58
-    // constant used to indicate that the question type is a US-formatted phone number
59
-    const QST_type_us_phone = 'US_PHONE';
60
-
61
-    // constant used to indicate that the question type is a YEAR
62
-    const QST_type_year = 'YEAR';
63
-
64
-    /**
65
-     * lists all the question types which should be allowed. Ideally, this will be extensible.
66
-     *
67
-     * @var array $_allowed_question_types
68
-     */
69
-    protected $_allowed_question_types = [];
70
-
71
-
72
-    // private instance of the Attendee object
73
-    protected static $_instance = null;
74
-
75
-    /**
76
-     * brief descriptions for all the question types
77
-     *
78
-     * @var EEM_Question $_instance
79
-     */
80
-    protected $_question_descriptions;
81
-
82
-    /**
83
-     * Question types that are interchangeable, even after answers have been provided for them.
84
-     * Top-level keys are category slugs, next level is an array of question types. If question types
85
-     * aren't in this array, it is assumed they AREN'T interchangeable with any other question types.
86
-     *
87
-     * @var array   $_question_type_categories {
88
-     * @type string $text
89
-     * @type string $single                    -answer-enum
90
-     * @type string $multi                     -answer-enum
91
-     *                    }
92
-     */
93
-    protected $_question_type_categories = [];
94
-
95
-
96
-    /**
97
-     * Question types that should have an admin-defined max input length
98
-     *
99
-     * @var array
100
-     */
101
-    protected $question_types_with_max_length;
102
-
103
-
104
-    /**
105
-     * EEM_Question constructor.
106
-     *
107
-     * @param null $timezone
108
-     */
109
-    protected function __construct($timezone = '')
110
-    {
111
-        $this->singular_item                  = esc_html__('Question', 'event_espresso');
112
-        $this->plural_item                    = esc_html__('Questions', 'event_espresso');
113
-        $this->_allowed_question_types        = apply_filters(
114
-            'FHEE__EEM_Question__construct__allowed_question_types',
115
-            [
116
-                EEM_Question::QST_type_checkbox      => esc_html__('Checkboxes', 'event_espresso'),
117
-                EEM_Question::QST_type_country       => esc_html__('Country Dropdown', 'event_espresso'),
118
-                EEM_Question::QST_type_date          => esc_html__('Date Picker', 'event_espresso'),
119
-                EEM_Question::QST_type_decimal       => esc_html__('Number', 'event_espresso'),
120
-                EEM_Question::QST_type_dropdown      => esc_html__('Dropdown', 'event_espresso'),
121
-                EEM_Question::QST_type_email         => esc_html__('Email', 'event_espresso'),
122
-                EEM_Question::QST_type_email_confirm => esc_html__('Confirm Email', 'event_espresso'),
123
-                EEM_Question::QST_type_html_textarea => esc_html__('HTML Textarea', 'event_espresso'),
124
-                EEM_Question::QST_type_int           => esc_html__('Whole Number', 'event_espresso'),
125
-                EEM_Question::QST_type_multi_select  => esc_html__('Multi Select', 'event_espresso'),
126
-                EEM_Question::QST_type_radio         => esc_html__('Radio Buttons', 'event_espresso'),
127
-                EEM_Question::QST_type_state         => esc_html__('State/Province Dropdown', 'event_espresso'),
128
-                EEM_Question::QST_type_text          => esc_html__('Text', 'event_espresso'),
129
-                EEM_Question::QST_type_textarea      => esc_html__('Textarea', 'event_espresso'),
130
-                EEM_Question::QST_type_url           => esc_html__('URL', 'event_espresso'),
131
-                EEM_Question::QST_type_us_phone      => esc_html__('USA - Format Phone', 'event_espresso'),
132
-                EEM_Question::QST_type_year          => esc_html__('Year', 'event_espresso'),
133
-            ]
134
-        );
135
-        $this->_question_descriptions         = apply_filters(
136
-            'FHEE__EEM_Question__construct__question_descriptions',
137
-            [
138
-                EEM_Question::QST_type_checkbox      => esc_html__(
139
-                    'Allows multiple preset options to be selected',
140
-                    'event_espresso'
141
-                ),
142
-                EEM_Question::QST_type_country       => esc_html__(
143
-                    'A dropdown that lists countries',
144
-                    'event_espresso'
145
-                ),
146
-                EEM_Question::QST_type_date          => esc_html__(
147
-                    'A popup calendar that allows date selections',
148
-                    'event_espresso'
149
-                ),
150
-                EEM_Question::QST_type_decimal       => esc_html__(
151
-                    'A text field that allows number values with decimals',
152
-                    'event_espresso'
153
-                ),
154
-                EEM_Question::QST_type_dropdown      => esc_html__(
155
-                    'A dropdown that allows a single selection',
156
-                    'event_espresso'
157
-                ),
158
-                EEM_Question::QST_type_email         => esc_html__(
159
-                    'A text field that must contain a valid Email address',
160
-                    'event_espresso'
161
-                ),
162
-                EEM_Question::QST_type_email_confirm => esc_html__(
163
-                    'A text field that must contain a valid Email address and be equal to Email field',
164
-                    'event_espresso'
165
-                ),
166
-                EEM_Question::QST_type_html_textarea => esc_html__(
167
-                    'A multi line text input field that allows HTML',
168
-                    'event_espresso'
169
-                ),
170
-                EEM_Question::QST_type_int           => esc_html__(
171
-                    'A text field that only allows whole numbers (no decimals)',
172
-                    'event_espresso'
173
-                ),
174
-                EEM_Question::QST_type_multi_select  => esc_html__(
175
-                    'A dropdown that allows multiple selections',
176
-                    'event_espresso'
177
-                ),
178
-                EEM_Question::QST_type_radio         => esc_html__(
179
-                    'Allows a single preset option to be selected',
180
-                    'event_espresso'
181
-                ),
182
-                EEM_Question::QST_type_state         => esc_html__(
183
-                    'A dropdown that lists states/provinces',
184
-                    'event_espresso'
185
-                ),
186
-                EEM_Question::QST_type_text          => esc_html__(
187
-                    'A single line text input field',
188
-                    'event_espresso'
189
-                ),
190
-                EEM_Question::QST_type_textarea      => esc_html__(
191
-                    'A multi line text input field',
192
-                    'event_espresso'
193
-                ),
194
-                EEM_Question::QST_type_url           => esc_html__(
195
-                    'A text field that must contain a valid URL',
196
-                    'event_espresso'
197
-                ),
198
-                EEM_Question::QST_type_us_phone      => esc_html__(
199
-                    'A text field that must contain a valid US phone number',
200
-                    'event_espresso'
201
-                ),
202
-                EEM_Question::QST_type_year          => esc_html__(
203
-                    'A dropdown that lists the last 100 years',
204
-                    'event_espresso'
205
-                ),
206
-            ]
207
-        );
208
-        $this->_question_type_categories      = (array) apply_filters(
209
-            'FHEE__EEM_Question__construct__question_type_categories',
210
-            [
211
-                'text'               => [
212
-                    EEM_Question::QST_type_date,
213
-                    EEM_Question::QST_type_decimal,
214
-                    EEM_Question::QST_type_email,
215
-                    EEM_Question::QST_type_email_confirm,
216
-                    EEM_Question::QST_type_html_textarea,
217
-                    EEM_Question::QST_type_int,
218
-                    EEM_Question::QST_type_text,
219
-                    EEM_Question::QST_type_textarea,
220
-                    EEM_Question::QST_type_url,
221
-                    EEM_Question::QST_type_us_phone,
222
-                    EEM_Question::QST_type_year,
223
-                ],
224
-                'single-answer-enum' => [
225
-                    EEM_Question::QST_type_dropdown,
226
-                    EEM_Question::QST_type_radio,
227
-                ],
228
-                'multi-answer-enum'  => [
229
-                    EEM_Question::QST_type_multi_select,
230
-                    EEM_Question::QST_type_checkbox,
231
-                ],
232
-            ]
233
-        );
234
-        $this->question_types_with_max_length = apply_filters(
235
-            'FHEE__EEM_Question___construct__question_types_with_max_length',
236
-            [
237
-                EEM_Question::QST_type_html_textarea,
238
-                EEM_Question::QST_type_text,
239
-                EEM_Question::QST_type_textarea,
240
-            ]
241
-        );
242
-
243
-        $this->_tables          = [
244
-            'Question' => new EE_Primary_Table('esp_question', 'QST_ID'),
245
-        ];
246
-        $this->_fields          = [
247
-            'Question' => [
248
-                'QST_ID'            => new EE_Primary_Key_Int_Field(
249
-                    'QST_ID',
250
-                    esc_html__('Question ID', 'event_espresso')
251
-                ),
252
-                'QST_admin_label'   => new EE_Plain_Text_Field(
253
-                    'QST_admin_label',
254
-                    esc_html__('Question Label (admin-only)', 'event_espresso'),
255
-                    true,
256
-                    ''
257
-                ),
258
-                'QST_admin_only'    => new EE_Boolean_Field(
259
-                    'QST_admin_only',
260
-                    esc_html__('Admin-Only Question?', 'event_espresso'),
261
-                    false,
262
-                    false
263
-                ),
264
-                'QST_deleted'       => new EE_Trashed_Flag_Field(
265
-                    'QST_deleted',
266
-                    esc_html__('Flag Indicating question was deleted', 'event_espresso'),
267
-                    false,
268
-                    false
269
-                ),
270
-                'QST_display_text'  => new EE_Post_Content_Field(
271
-                    'QST_display_text',
272
-                    esc_html__('Question Text', 'event_espresso'),
273
-                    true,
274
-                    ''
275
-                ),
276
-                'QST_max'           => new EE_Infinite_Integer_Field(
277
-                    'QST_max',
278
-                    esc_html__('Max Size', 'event_espresso'),
279
-                    false,
280
-                    EE_INF
281
-                ),
282
-                'QST_order'         => new EE_Integer_Field(
283
-                    'QST_order',
284
-                    esc_html__('Question Order', 'event_espresso'),
285
-                    false,
286
-                    0
287
-                ),
288
-                'QST_required'      => new EE_Boolean_Field(
289
-                    'QST_required',
290
-                    esc_html__('Required Question?', 'event_espresso'),
291
-                    false,
292
-                    false
293
-                ),
294
-                'QST_required_text' => new EE_Simple_HTML_Field(
295
-                    'QST_required_text',
296
-                    esc_html__('Text to Display if Not Provided', 'event_espresso'),
297
-                    true,
298
-                    ''
299
-                ),
300
-                'QST_system'        => new EE_Plain_Text_Field(
301
-                    'QST_system',
302
-                    esc_html__('Internal string ID for question', 'event_espresso'),
303
-                    false,
304
-                    ''
305
-                ),
306
-                'QST_type'          => new EE_Enum_Text_Field(
307
-                    'QST_type',
308
-                    esc_html__('Question Type', 'event_espresso'),
309
-                    false,
310
-                    'TEXT',
311
-                    $this->_allowed_question_types
312
-                ),
313
-                'QST_wp_user'       => new EE_WP_User_Field(
314
-                    'QST_wp_user',
315
-                    esc_html__('Question Creator ID', 'event_espresso'),
316
-                    false
317
-                ),
318
-            ],
319
-        ];
320
-        $this->_model_relations = [
321
-            'Answer'                  => new EE_Has_Many_Relation(),
322
-            'Question_Group'          => new EE_HABTM_Relation('Question_Group_Question'),
323
-            // for QST_order column
324
-            'Question_Group_Question' => new EE_Has_Many_Relation(),
325
-            'Question_Option'         => new EE_Has_Many_Relation(),
326
-            'WP_User'                 => new EE_Belongs_To_Relation(),
327
-        ];
328
-        // this model is generally available for reading
329
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ]       =
330
-            new EE_Restriction_Generator_Public();
331
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
332
-            new EE_Restriction_Generator_Reg_Form('QST_system');
333
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
334
-            new EE_Restriction_Generator_Reg_Form('QST_system');
335
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
336
-            new EE_Restriction_Generator_Reg_Form('QST_system');
337
-
338
-        parent::__construct($timezone);
339
-    }
340
-
341
-
342
-    /**
343
-     * Returns the list of allowed question types, which are normally:
344
-     * 'TEXT','TEXTAREA','RADIO_BTN','DROPDOWN','CHECKBOX','DATE' but they can be extended
345
-     *
346
-     * @return string[]
347
-     */
348
-    public function allowed_question_types(): array
349
-    {
350
-        return $this->_allowed_question_types;
351
-    }
352
-
353
-
354
-    /**
355
-     * Gets all the question types in the same category
356
-     *
357
-     * @param string $question_type one of EEM_Question::allowed_question_types(
358
-     * @return string[] like EEM_Question::allowed_question_types()
359
-     */
360
-    public function question_types_in_same_category(string $question_type): array
361
-    {
362
-        $question_types = [$question_type];
363
-        foreach ($this->_question_type_categories as $category => $question_types_in_category) {
364
-            if (in_array($question_type, $question_types_in_category)) {
365
-                $question_types = $question_types_in_category;
366
-                break;
367
-            }
368
-        }
369
-
370
-        return array_intersect_key($this->allowed_question_types(), array_flip($question_types));
371
-    }
372
-
373
-
374
-    /**
375
-     * Determines if the given question type is in the given question type category
376
-     *
377
-     * @param string $question_type one of EEM_Question::allowed_question_types()
378
-     * @param string $category      one of the top-level keys of EEM_Question::question_type_categories()
379
-     * @return boolean
380
-     */
381
-    public function question_type_is_in_category(string $question_type, string $category): bool
382
-    {
383
-        if (! isset($this->_question_type_categories[ $category ])) {
384
-            return false;
385
-        }
386
-        return in_array($question_type, $this->_question_type_categories[ $category ]);
387
-    }
388
-
389
-
390
-    /**
391
-     * Returns all the question types in the given category
392
-     *
393
-     * @param string $category
394
-     * @return array|mixed
395
-     */
396
-    public function question_types_in_category(string $category): array
397
-    {
398
-        if (isset($this->_question_type_categories[ $category ])) {
399
-            return $this->_question_type_categories[ $category ];
400
-        }
401
-        return [];
402
-    }
403
-
404
-
405
-    /**
406
-     * Returns all the question types that should have question options
407
-     *
408
-     * @return array
409
-     */
410
-    public function question_types_with_options(): array
411
-    {
412
-        return array_merge(
413
-            $this->question_types_in_category('single-answer-enum'),
414
-            $this->question_types_in_category('multi-answer-enum')
415
-        );
416
-    }
417
-
418
-
419
-    /**
420
-     * Returns the question type categories 2d array
421
-     *
422
-     * @return array see EEM_Question::_question_type_categories
423
-     */
424
-    public function question_type_categories(): array
425
-    {
426
-        return $this->_question_type_categories;
427
-    }
428
-
429
-
430
-    /**
431
-     * Returns an array of all the QST_system values that can be allowed in the system question group
432
-     * identified by $system_question_group_id
433
-     *
434
-     * @param string $system_question_group_id QSG_system
435
-     * @return array of system question names (QST_system)
436
-     */
437
-    public function allowed_system_questions_in_system_question_group(string $system_question_group_id): array
438
-    {
439
-        $question_system_ids = [];
440
-        switch ($system_question_group_id) {
441
-            case EEM_Question_Group::system_personal:
442
-                $question_system_ids = [
443
-                    EEM_Attendee::system_question_fname,
444
-                    EEM_Attendee::system_question_lname,
445
-                    EEM_Attendee::system_question_email,
446
-                    EEM_Attendee::system_question_email_confirm,
447
-                    EEM_Attendee::system_question_phone,
448
-                ];
449
-                break;
450
-            case EEM_Question_Group::system_address:
451
-                $question_system_ids = [
452
-                    EEM_Attendee::system_question_address,
453
-                    EEM_Attendee::system_question_address2,
454
-                    EEM_Attendee::system_question_city,
455
-                    EEM_Attendee::system_question_state,
456
-                    EEM_Attendee::system_question_country,
457
-                    EEM_Attendee::system_question_zip,
458
-                    EEM_Attendee::system_question_phone,
459
-                ];
460
-                break;
461
-        }
462
-        return apply_filters(
463
-            'FHEE__EEM_Question__system_questions_allowed_in_system_question_group__return',
464
-            $question_system_ids,
465
-            $system_question_group_id
466
-        );
467
-    }
468
-
469
-
470
-    /**
471
-     * Returns an array of all the QST_system values that are required in the system question group
472
-     * identified by $system_question_group_id
473
-     *
474
-     * @param string $system_question_group_id QSG_system
475
-     * @return array of system question names (QST_system)
476
-     */
477
-    public function required_system_questions_in_system_question_group(string $system_question_group_id): array
478
-    {
479
-        $question_system_ids = null;
480
-        switch ($system_question_group_id) {
481
-            case EEM_Question_Group::system_personal:
482
-                $question_system_ids = [
483
-                    EEM_Attendee::system_question_fname,
484
-                    EEM_Attendee::system_question_email,
485
-                ];
486
-                break;
487
-            default:
488
-                $question_system_ids = [];
489
-        }
490
-        return apply_filters(
491
-            'FHEE__EEM_Question__system_questions_required_in_system_question_group',
492
-            $question_system_ids,
493
-            $system_question_group_id
494
-        );
495
-    }
496
-
497
-
498
-    /**
499
-     * Gets an array for converting between QST_system and QST_IDs for system questions. Eg, if you want to know
500
-     * which system question QST_ID corresponds to the QST_system 'city', use
501
-     * EEM_Question::instance()->get_Question_ID_from_system_string('city');
502
-     *
503
-     * @param $QST_system
504
-     * @return int of QST_ID for the question that corresponds to that QST_system
505
-     * @throws EE_Error
506
-     */
507
-    public function get_Question_ID_from_system_string($QST_system): int
508
-    {
509
-        return $this->get_var([['QST_system' => $QST_system]]);
510
-    }
511
-
512
-
513
-    /**
514
-     * searches the db for the question with the latest question order and returns that value.
515
-     *
516
-     * @return int
517
-     * @throws EE_Error
518
-     */
519
-    public function get_latest_question_order(): int
520
-    {
521
-        $columns_to_select = [
522
-            'max_order' => ["MAX(QST_order)", "%d"],
523
-        ];
524
-        $max               = $this->_get_all_wpdb_results([], ARRAY_A, $columns_to_select);
525
-        return isset($max[0], $max[0]['max_order']) ? $max[0]['max_order'] : 0;
526
-    }
527
-
528
-
529
-    /**
530
-     * Returns an array where keys are system question QST_system values,
531
-     * and values are the highest question max the admin can set on the question
532
-     * (aka the "max max"; eg, a site admin can change the zip question to have a max
533
-     * of 5, but no larger than 12)
534
-     *
535
-     * @return array
536
-     */
537
-    public function system_question_maxes(): array
538
-    {
539
-        return [
540
-            'fname'         => 45,
541
-            'lname'         => 45,
542
-            'address'       => 255,
543
-            'address2'      => 255,
544
-            'city'          => 45,
545
-            'zip'           => 12,
546
-            'email'         => 255,
547
-            'email_confirm' => 255,
548
-            'phone'         => 45,
549
-        ];
550
-    }
551
-
552
-
553
-    /**
554
-     * Given a QST_system value, gets the question's largest allowable max input.
555
-     *
556
-     * @param string $system_question_value
557
-     * @return int|float
558
-     * @see Registration_Form_Admin_Page::system_question_maxes()
559
-     */
560
-    public function absolute_max_for_system_question(string $system_question_value)
561
-    {
562
-        $maxes = $this->system_question_maxes();
563
-        return isset($maxes[ $system_question_value ]) ?
564
-            $maxes[ $system_question_value ]
565
-            : EE_INF;
566
-    }
567
-
568
-
569
-    /**
570
-     * @return array
571
-     */
572
-    public function question_descriptions(): array
573
-    {
574
-        return $this->_question_descriptions;
575
-    }
576
-
577
-
578
-    /**
579
-     * Returns all the question types that should have an admin-defined max input length
580
-     *
581
-     * @return array
582
-     */
583
-    public function questionTypesWithMaxLength(): array
584
-    {
585
-        return (array) $this->question_types_with_max_length;
586
-    }
16
+	// constant used to indicate that the question type is COUNTRY
17
+	const QST_type_country = 'COUNTRY';
18
+
19
+	// constant used to indicate that the question type is DATE
20
+	const QST_type_date = 'DATE';
21
+
22
+	// constant used to indicate that the question type is a decimal (float)
23
+	const QST_type_decimal = 'DECIMAL';
24
+
25
+	// constant used to indicate that the question type is DROPDOWN
26
+	const QST_type_dropdown = 'DROPDOWN';
27
+
28
+	// constant used to indicate that the question type is an email input
29
+	const QST_type_email = 'EMAIL';
30
+
31
+	// constant used to indicate that the question type is an email input
32
+	const QST_type_email_confirm = 'EMAIL_CONFIRM';
33
+
34
+	// constant used to indicate that the question type is a TEXTAREA that allows simple html
35
+	const QST_type_html_textarea = 'HTML_TEXTAREA';
36
+
37
+	// constant used to indicate that the question type is an integer (whole number)
38
+	const QST_type_int = 'INTEGER';
39
+
40
+	// constant used to indicate that the question type is a multi-select
41
+	const QST_type_multi_select = 'MULTI_SELECT';
42
+
43
+	// constant used to indicate that the question type is RADIO_BTN
44
+	const QST_type_radio = 'RADIO_BTN';
45
+
46
+	// constant used to indicate that the question type is STATE
47
+	const QST_type_state = 'STATE';
48
+
49
+	// constant used to indicate that the question type is TEXT
50
+	const QST_type_text = 'TEXT';
51
+
52
+	// constant used to indicate that the question type is TEXTAREA
53
+	const QST_type_textarea = 'TEXTAREA';
54
+
55
+	// constant used to indicate that the question type is a valid URL
56
+	const QST_type_url = 'URL';
57
+
58
+	// constant used to indicate that the question type is a US-formatted phone number
59
+	const QST_type_us_phone = 'US_PHONE';
60
+
61
+	// constant used to indicate that the question type is a YEAR
62
+	const QST_type_year = 'YEAR';
63
+
64
+	/**
65
+	 * lists all the question types which should be allowed. Ideally, this will be extensible.
66
+	 *
67
+	 * @var array $_allowed_question_types
68
+	 */
69
+	protected $_allowed_question_types = [];
70
+
71
+
72
+	// private instance of the Attendee object
73
+	protected static $_instance = null;
74
+
75
+	/**
76
+	 * brief descriptions for all the question types
77
+	 *
78
+	 * @var EEM_Question $_instance
79
+	 */
80
+	protected $_question_descriptions;
81
+
82
+	/**
83
+	 * Question types that are interchangeable, even after answers have been provided for them.
84
+	 * Top-level keys are category slugs, next level is an array of question types. If question types
85
+	 * aren't in this array, it is assumed they AREN'T interchangeable with any other question types.
86
+	 *
87
+	 * @var array   $_question_type_categories {
88
+	 * @type string $text
89
+	 * @type string $single                    -answer-enum
90
+	 * @type string $multi                     -answer-enum
91
+	 *                    }
92
+	 */
93
+	protected $_question_type_categories = [];
94
+
95
+
96
+	/**
97
+	 * Question types that should have an admin-defined max input length
98
+	 *
99
+	 * @var array
100
+	 */
101
+	protected $question_types_with_max_length;
102
+
103
+
104
+	/**
105
+	 * EEM_Question constructor.
106
+	 *
107
+	 * @param null $timezone
108
+	 */
109
+	protected function __construct($timezone = '')
110
+	{
111
+		$this->singular_item                  = esc_html__('Question', 'event_espresso');
112
+		$this->plural_item                    = esc_html__('Questions', 'event_espresso');
113
+		$this->_allowed_question_types        = apply_filters(
114
+			'FHEE__EEM_Question__construct__allowed_question_types',
115
+			[
116
+				EEM_Question::QST_type_checkbox      => esc_html__('Checkboxes', 'event_espresso'),
117
+				EEM_Question::QST_type_country       => esc_html__('Country Dropdown', 'event_espresso'),
118
+				EEM_Question::QST_type_date          => esc_html__('Date Picker', 'event_espresso'),
119
+				EEM_Question::QST_type_decimal       => esc_html__('Number', 'event_espresso'),
120
+				EEM_Question::QST_type_dropdown      => esc_html__('Dropdown', 'event_espresso'),
121
+				EEM_Question::QST_type_email         => esc_html__('Email', 'event_espresso'),
122
+				EEM_Question::QST_type_email_confirm => esc_html__('Confirm Email', 'event_espresso'),
123
+				EEM_Question::QST_type_html_textarea => esc_html__('HTML Textarea', 'event_espresso'),
124
+				EEM_Question::QST_type_int           => esc_html__('Whole Number', 'event_espresso'),
125
+				EEM_Question::QST_type_multi_select  => esc_html__('Multi Select', 'event_espresso'),
126
+				EEM_Question::QST_type_radio         => esc_html__('Radio Buttons', 'event_espresso'),
127
+				EEM_Question::QST_type_state         => esc_html__('State/Province Dropdown', 'event_espresso'),
128
+				EEM_Question::QST_type_text          => esc_html__('Text', 'event_espresso'),
129
+				EEM_Question::QST_type_textarea      => esc_html__('Textarea', 'event_espresso'),
130
+				EEM_Question::QST_type_url           => esc_html__('URL', 'event_espresso'),
131
+				EEM_Question::QST_type_us_phone      => esc_html__('USA - Format Phone', 'event_espresso'),
132
+				EEM_Question::QST_type_year          => esc_html__('Year', 'event_espresso'),
133
+			]
134
+		);
135
+		$this->_question_descriptions         = apply_filters(
136
+			'FHEE__EEM_Question__construct__question_descriptions',
137
+			[
138
+				EEM_Question::QST_type_checkbox      => esc_html__(
139
+					'Allows multiple preset options to be selected',
140
+					'event_espresso'
141
+				),
142
+				EEM_Question::QST_type_country       => esc_html__(
143
+					'A dropdown that lists countries',
144
+					'event_espresso'
145
+				),
146
+				EEM_Question::QST_type_date          => esc_html__(
147
+					'A popup calendar that allows date selections',
148
+					'event_espresso'
149
+				),
150
+				EEM_Question::QST_type_decimal       => esc_html__(
151
+					'A text field that allows number values with decimals',
152
+					'event_espresso'
153
+				),
154
+				EEM_Question::QST_type_dropdown      => esc_html__(
155
+					'A dropdown that allows a single selection',
156
+					'event_espresso'
157
+				),
158
+				EEM_Question::QST_type_email         => esc_html__(
159
+					'A text field that must contain a valid Email address',
160
+					'event_espresso'
161
+				),
162
+				EEM_Question::QST_type_email_confirm => esc_html__(
163
+					'A text field that must contain a valid Email address and be equal to Email field',
164
+					'event_espresso'
165
+				),
166
+				EEM_Question::QST_type_html_textarea => esc_html__(
167
+					'A multi line text input field that allows HTML',
168
+					'event_espresso'
169
+				),
170
+				EEM_Question::QST_type_int           => esc_html__(
171
+					'A text field that only allows whole numbers (no decimals)',
172
+					'event_espresso'
173
+				),
174
+				EEM_Question::QST_type_multi_select  => esc_html__(
175
+					'A dropdown that allows multiple selections',
176
+					'event_espresso'
177
+				),
178
+				EEM_Question::QST_type_radio         => esc_html__(
179
+					'Allows a single preset option to be selected',
180
+					'event_espresso'
181
+				),
182
+				EEM_Question::QST_type_state         => esc_html__(
183
+					'A dropdown that lists states/provinces',
184
+					'event_espresso'
185
+				),
186
+				EEM_Question::QST_type_text          => esc_html__(
187
+					'A single line text input field',
188
+					'event_espresso'
189
+				),
190
+				EEM_Question::QST_type_textarea      => esc_html__(
191
+					'A multi line text input field',
192
+					'event_espresso'
193
+				),
194
+				EEM_Question::QST_type_url           => esc_html__(
195
+					'A text field that must contain a valid URL',
196
+					'event_espresso'
197
+				),
198
+				EEM_Question::QST_type_us_phone      => esc_html__(
199
+					'A text field that must contain a valid US phone number',
200
+					'event_espresso'
201
+				),
202
+				EEM_Question::QST_type_year          => esc_html__(
203
+					'A dropdown that lists the last 100 years',
204
+					'event_espresso'
205
+				),
206
+			]
207
+		);
208
+		$this->_question_type_categories      = (array) apply_filters(
209
+			'FHEE__EEM_Question__construct__question_type_categories',
210
+			[
211
+				'text'               => [
212
+					EEM_Question::QST_type_date,
213
+					EEM_Question::QST_type_decimal,
214
+					EEM_Question::QST_type_email,
215
+					EEM_Question::QST_type_email_confirm,
216
+					EEM_Question::QST_type_html_textarea,
217
+					EEM_Question::QST_type_int,
218
+					EEM_Question::QST_type_text,
219
+					EEM_Question::QST_type_textarea,
220
+					EEM_Question::QST_type_url,
221
+					EEM_Question::QST_type_us_phone,
222
+					EEM_Question::QST_type_year,
223
+				],
224
+				'single-answer-enum' => [
225
+					EEM_Question::QST_type_dropdown,
226
+					EEM_Question::QST_type_radio,
227
+				],
228
+				'multi-answer-enum'  => [
229
+					EEM_Question::QST_type_multi_select,
230
+					EEM_Question::QST_type_checkbox,
231
+				],
232
+			]
233
+		);
234
+		$this->question_types_with_max_length = apply_filters(
235
+			'FHEE__EEM_Question___construct__question_types_with_max_length',
236
+			[
237
+				EEM_Question::QST_type_html_textarea,
238
+				EEM_Question::QST_type_text,
239
+				EEM_Question::QST_type_textarea,
240
+			]
241
+		);
242
+
243
+		$this->_tables          = [
244
+			'Question' => new EE_Primary_Table('esp_question', 'QST_ID'),
245
+		];
246
+		$this->_fields          = [
247
+			'Question' => [
248
+				'QST_ID'            => new EE_Primary_Key_Int_Field(
249
+					'QST_ID',
250
+					esc_html__('Question ID', 'event_espresso')
251
+				),
252
+				'QST_admin_label'   => new EE_Plain_Text_Field(
253
+					'QST_admin_label',
254
+					esc_html__('Question Label (admin-only)', 'event_espresso'),
255
+					true,
256
+					''
257
+				),
258
+				'QST_admin_only'    => new EE_Boolean_Field(
259
+					'QST_admin_only',
260
+					esc_html__('Admin-Only Question?', 'event_espresso'),
261
+					false,
262
+					false
263
+				),
264
+				'QST_deleted'       => new EE_Trashed_Flag_Field(
265
+					'QST_deleted',
266
+					esc_html__('Flag Indicating question was deleted', 'event_espresso'),
267
+					false,
268
+					false
269
+				),
270
+				'QST_display_text'  => new EE_Post_Content_Field(
271
+					'QST_display_text',
272
+					esc_html__('Question Text', 'event_espresso'),
273
+					true,
274
+					''
275
+				),
276
+				'QST_max'           => new EE_Infinite_Integer_Field(
277
+					'QST_max',
278
+					esc_html__('Max Size', 'event_espresso'),
279
+					false,
280
+					EE_INF
281
+				),
282
+				'QST_order'         => new EE_Integer_Field(
283
+					'QST_order',
284
+					esc_html__('Question Order', 'event_espresso'),
285
+					false,
286
+					0
287
+				),
288
+				'QST_required'      => new EE_Boolean_Field(
289
+					'QST_required',
290
+					esc_html__('Required Question?', 'event_espresso'),
291
+					false,
292
+					false
293
+				),
294
+				'QST_required_text' => new EE_Simple_HTML_Field(
295
+					'QST_required_text',
296
+					esc_html__('Text to Display if Not Provided', 'event_espresso'),
297
+					true,
298
+					''
299
+				),
300
+				'QST_system'        => new EE_Plain_Text_Field(
301
+					'QST_system',
302
+					esc_html__('Internal string ID for question', 'event_espresso'),
303
+					false,
304
+					''
305
+				),
306
+				'QST_type'          => new EE_Enum_Text_Field(
307
+					'QST_type',
308
+					esc_html__('Question Type', 'event_espresso'),
309
+					false,
310
+					'TEXT',
311
+					$this->_allowed_question_types
312
+				),
313
+				'QST_wp_user'       => new EE_WP_User_Field(
314
+					'QST_wp_user',
315
+					esc_html__('Question Creator ID', 'event_espresso'),
316
+					false
317
+				),
318
+			],
319
+		];
320
+		$this->_model_relations = [
321
+			'Answer'                  => new EE_Has_Many_Relation(),
322
+			'Question_Group'          => new EE_HABTM_Relation('Question_Group_Question'),
323
+			// for QST_order column
324
+			'Question_Group_Question' => new EE_Has_Many_Relation(),
325
+			'Question_Option'         => new EE_Has_Many_Relation(),
326
+			'WP_User'                 => new EE_Belongs_To_Relation(),
327
+		];
328
+		// this model is generally available for reading
329
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ]       =
330
+			new EE_Restriction_Generator_Public();
331
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
332
+			new EE_Restriction_Generator_Reg_Form('QST_system');
333
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
334
+			new EE_Restriction_Generator_Reg_Form('QST_system');
335
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
336
+			new EE_Restriction_Generator_Reg_Form('QST_system');
337
+
338
+		parent::__construct($timezone);
339
+	}
340
+
341
+
342
+	/**
343
+	 * Returns the list of allowed question types, which are normally:
344
+	 * 'TEXT','TEXTAREA','RADIO_BTN','DROPDOWN','CHECKBOX','DATE' but they can be extended
345
+	 *
346
+	 * @return string[]
347
+	 */
348
+	public function allowed_question_types(): array
349
+	{
350
+		return $this->_allowed_question_types;
351
+	}
352
+
353
+
354
+	/**
355
+	 * Gets all the question types in the same category
356
+	 *
357
+	 * @param string $question_type one of EEM_Question::allowed_question_types(
358
+	 * @return string[] like EEM_Question::allowed_question_types()
359
+	 */
360
+	public function question_types_in_same_category(string $question_type): array
361
+	{
362
+		$question_types = [$question_type];
363
+		foreach ($this->_question_type_categories as $category => $question_types_in_category) {
364
+			if (in_array($question_type, $question_types_in_category)) {
365
+				$question_types = $question_types_in_category;
366
+				break;
367
+			}
368
+		}
369
+
370
+		return array_intersect_key($this->allowed_question_types(), array_flip($question_types));
371
+	}
372
+
373
+
374
+	/**
375
+	 * Determines if the given question type is in the given question type category
376
+	 *
377
+	 * @param string $question_type one of EEM_Question::allowed_question_types()
378
+	 * @param string $category      one of the top-level keys of EEM_Question::question_type_categories()
379
+	 * @return boolean
380
+	 */
381
+	public function question_type_is_in_category(string $question_type, string $category): bool
382
+	{
383
+		if (! isset($this->_question_type_categories[ $category ])) {
384
+			return false;
385
+		}
386
+		return in_array($question_type, $this->_question_type_categories[ $category ]);
387
+	}
388
+
389
+
390
+	/**
391
+	 * Returns all the question types in the given category
392
+	 *
393
+	 * @param string $category
394
+	 * @return array|mixed
395
+	 */
396
+	public function question_types_in_category(string $category): array
397
+	{
398
+		if (isset($this->_question_type_categories[ $category ])) {
399
+			return $this->_question_type_categories[ $category ];
400
+		}
401
+		return [];
402
+	}
403
+
404
+
405
+	/**
406
+	 * Returns all the question types that should have question options
407
+	 *
408
+	 * @return array
409
+	 */
410
+	public function question_types_with_options(): array
411
+	{
412
+		return array_merge(
413
+			$this->question_types_in_category('single-answer-enum'),
414
+			$this->question_types_in_category('multi-answer-enum')
415
+		);
416
+	}
417
+
418
+
419
+	/**
420
+	 * Returns the question type categories 2d array
421
+	 *
422
+	 * @return array see EEM_Question::_question_type_categories
423
+	 */
424
+	public function question_type_categories(): array
425
+	{
426
+		return $this->_question_type_categories;
427
+	}
428
+
429
+
430
+	/**
431
+	 * Returns an array of all the QST_system values that can be allowed in the system question group
432
+	 * identified by $system_question_group_id
433
+	 *
434
+	 * @param string $system_question_group_id QSG_system
435
+	 * @return array of system question names (QST_system)
436
+	 */
437
+	public function allowed_system_questions_in_system_question_group(string $system_question_group_id): array
438
+	{
439
+		$question_system_ids = [];
440
+		switch ($system_question_group_id) {
441
+			case EEM_Question_Group::system_personal:
442
+				$question_system_ids = [
443
+					EEM_Attendee::system_question_fname,
444
+					EEM_Attendee::system_question_lname,
445
+					EEM_Attendee::system_question_email,
446
+					EEM_Attendee::system_question_email_confirm,
447
+					EEM_Attendee::system_question_phone,
448
+				];
449
+				break;
450
+			case EEM_Question_Group::system_address:
451
+				$question_system_ids = [
452
+					EEM_Attendee::system_question_address,
453
+					EEM_Attendee::system_question_address2,
454
+					EEM_Attendee::system_question_city,
455
+					EEM_Attendee::system_question_state,
456
+					EEM_Attendee::system_question_country,
457
+					EEM_Attendee::system_question_zip,
458
+					EEM_Attendee::system_question_phone,
459
+				];
460
+				break;
461
+		}
462
+		return apply_filters(
463
+			'FHEE__EEM_Question__system_questions_allowed_in_system_question_group__return',
464
+			$question_system_ids,
465
+			$system_question_group_id
466
+		);
467
+	}
468
+
469
+
470
+	/**
471
+	 * Returns an array of all the QST_system values that are required in the system question group
472
+	 * identified by $system_question_group_id
473
+	 *
474
+	 * @param string $system_question_group_id QSG_system
475
+	 * @return array of system question names (QST_system)
476
+	 */
477
+	public function required_system_questions_in_system_question_group(string $system_question_group_id): array
478
+	{
479
+		$question_system_ids = null;
480
+		switch ($system_question_group_id) {
481
+			case EEM_Question_Group::system_personal:
482
+				$question_system_ids = [
483
+					EEM_Attendee::system_question_fname,
484
+					EEM_Attendee::system_question_email,
485
+				];
486
+				break;
487
+			default:
488
+				$question_system_ids = [];
489
+		}
490
+		return apply_filters(
491
+			'FHEE__EEM_Question__system_questions_required_in_system_question_group',
492
+			$question_system_ids,
493
+			$system_question_group_id
494
+		);
495
+	}
496
+
497
+
498
+	/**
499
+	 * Gets an array for converting between QST_system and QST_IDs for system questions. Eg, if you want to know
500
+	 * which system question QST_ID corresponds to the QST_system 'city', use
501
+	 * EEM_Question::instance()->get_Question_ID_from_system_string('city');
502
+	 *
503
+	 * @param $QST_system
504
+	 * @return int of QST_ID for the question that corresponds to that QST_system
505
+	 * @throws EE_Error
506
+	 */
507
+	public function get_Question_ID_from_system_string($QST_system): int
508
+	{
509
+		return $this->get_var([['QST_system' => $QST_system]]);
510
+	}
511
+
512
+
513
+	/**
514
+	 * searches the db for the question with the latest question order and returns that value.
515
+	 *
516
+	 * @return int
517
+	 * @throws EE_Error
518
+	 */
519
+	public function get_latest_question_order(): int
520
+	{
521
+		$columns_to_select = [
522
+			'max_order' => ["MAX(QST_order)", "%d"],
523
+		];
524
+		$max               = $this->_get_all_wpdb_results([], ARRAY_A, $columns_to_select);
525
+		return isset($max[0], $max[0]['max_order']) ? $max[0]['max_order'] : 0;
526
+	}
527
+
528
+
529
+	/**
530
+	 * Returns an array where keys are system question QST_system values,
531
+	 * and values are the highest question max the admin can set on the question
532
+	 * (aka the "max max"; eg, a site admin can change the zip question to have a max
533
+	 * of 5, but no larger than 12)
534
+	 *
535
+	 * @return array
536
+	 */
537
+	public function system_question_maxes(): array
538
+	{
539
+		return [
540
+			'fname'         => 45,
541
+			'lname'         => 45,
542
+			'address'       => 255,
543
+			'address2'      => 255,
544
+			'city'          => 45,
545
+			'zip'           => 12,
546
+			'email'         => 255,
547
+			'email_confirm' => 255,
548
+			'phone'         => 45,
549
+		];
550
+	}
551
+
552
+
553
+	/**
554
+	 * Given a QST_system value, gets the question's largest allowable max input.
555
+	 *
556
+	 * @param string $system_question_value
557
+	 * @return int|float
558
+	 * @see Registration_Form_Admin_Page::system_question_maxes()
559
+	 */
560
+	public function absolute_max_for_system_question(string $system_question_value)
561
+	{
562
+		$maxes = $this->system_question_maxes();
563
+		return isset($maxes[ $system_question_value ]) ?
564
+			$maxes[ $system_question_value ]
565
+			: EE_INF;
566
+	}
567
+
568
+
569
+	/**
570
+	 * @return array
571
+	 */
572
+	public function question_descriptions(): array
573
+	{
574
+		return $this->_question_descriptions;
575
+	}
576
+
577
+
578
+	/**
579
+	 * Returns all the question types that should have an admin-defined max input length
580
+	 *
581
+	 * @return array
582
+	 */
583
+	public function questionTypesWithMaxLength(): array
584
+	{
585
+		return (array) $this->question_types_with_max_length;
586
+	}
587 587
 }
Please login to merge, or discard this patch.
core/db_models/EEM_WP_User.model.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -24,7 +24,7 @@
 block discarded – undo
24 24
     /**
25 25
      *    constructor
26 26
      *
27
-     * @param null              $timezone
27
+     * @param string|null              $timezone
28 28
      * @param ModelFieldFactory $model_field_factory
29 29
      * @throws EE_Error
30 30
      * @throws InvalidArgumentException
Please login to merge, or discard this patch.
Indentation   +123 added lines, -123 removed lines patch added patch discarded remove patch
@@ -13,133 +13,133 @@
 block discarded – undo
13 13
 class EEM_WP_User extends EEM_Base
14 14
 {
15 15
 
16
-    /**
17
-     * private instance of the EEM_WP_User object
18
-     *
19
-     * @type EEM_WP_User
20
-     */
21
-    protected static $_instance;
16
+	/**
17
+	 * private instance of the EEM_WP_User object
18
+	 *
19
+	 * @type EEM_WP_User
20
+	 */
21
+	protected static $_instance;
22 22
 
23 23
 
24
-    /**
25
-     *    constructor
26
-     *
27
-     * @param null              $timezone
28
-     * @param ModelFieldFactory $model_field_factory
29
-     * @throws EE_Error
30
-     * @throws InvalidArgumentException
31
-     */
32
-    protected function __construct($timezone = '', ModelFieldFactory $model_field_factory)
33
-    {
34
-        $this->singular_item = esc_html__('WP_User', 'event_espresso');
35
-        $this->plural_item = esc_html__('WP_Users', 'event_espresso');
36
-        global $wpdb;
37
-        $this->_tables = array(
38
-            'WP_User' => new EE_Primary_Table($wpdb->users, 'ID', true),
39
-        );
40
-        $this->_fields = array(
41
-            'WP_User' => array(
42
-                'ID'                  => $model_field_factory->createPrimaryKeyIntField(
43
-                    'ID',
44
-                    esc_html__('WP_User ID', 'event_espresso')
45
-                ),
46
-                'user_login'          => $model_field_factory->createPlainTextField(
47
-                    'user_login',
48
-                    esc_html__('User Login', 'event_espresso'),
49
-                    false
50
-                ),
51
-                'user_pass'           => $model_field_factory->createPlainTextField(
52
-                    'user_pass',
53
-                    esc_html__('User Password', 'event_espresso'),
54
-                    false
55
-                ),
56
-                'user_nicename'       => $model_field_factory->createPlainTextField(
57
-                    'user_nicename',
58
-                    esc_html__(' User Nice Name', 'event_espresso'),
59
-                    false
60
-                ),
61
-                'user_email'          => $model_field_factory->createEmailField(
62
-                    'user_email',
63
-                    esc_html__('User Email', 'event_espresso'),
64
-                    false,
65
-                    null
66
-                ),
67
-                'user_registered'     => $model_field_factory->createDatetimeField(
68
-                    'user_registered',
69
-                    esc_html__('Date User Registered', 'event_espresso'),
70
-                    $timezone
71
-                ),
72
-                'user_activation_key' => $model_field_factory->createPlainTextField(
73
-                    'user_activation_key',
74
-                    esc_html__('User Activation Key', 'event_espresso'),
75
-                    false
76
-                ),
77
-                'user_status'         => $model_field_factory->createIntegerField(
78
-                    'user_status',
79
-                    esc_html__('User Status', 'event_espresso')
80
-                ),
81
-                'display_name'        => $model_field_factory->createPlainTextField(
82
-                    'display_name',
83
-                    esc_html__('Display Name', 'event_espresso'),
84
-                    false
85
-                ),
86
-            ),
87
-        );
88
-        $this->_model_relations = array(
89
-            'Attendee'       => new EE_Has_Many_Relation(),
90
-            // all models are related to the change log
91
-            // 'Change_Log'     => new EE_Has_Many_Relation(),
92
-            'Event'          => new EE_Has_Many_Relation(),
93
-            'Message'        => new EE_Has_Many_Relation(),
94
-            'Payment_Method' => new EE_Has_Many_Relation(),
95
-            'Price'          => new EE_Has_Many_Relation(),
96
-            'Price_Type'     => new EE_Has_Many_Relation(),
97
-            'Question'       => new EE_Has_Many_Relation(),
98
-            'Question_Group' => new EE_Has_Many_Relation(),
99
-            'Ticket'         => new EE_Has_Many_Relation(),
100
-            'Venue'          => new EE_Has_Many_Relation(),
101
-        );
102
-        $this->foreign_key_aliases = [
103
-            'Event.EVT_wp_user'          => 'WP_User.ID',
104
-            'Payment_Method.PMD_wp_user' => 'WP_User.ID',
105
-            'Price.PRC_wp_user'          => 'WP_User.ID',
106
-            'Price_Type.PRT_wp_user'     => 'WP_User.ID',
107
-            'Question.QST_wp_user'       => 'WP_User.ID',
108
-            'Question_Group.QSG_wp_user' => 'WP_User.ID',
109
-            'Ticket.VNU_wp_user'         => 'WP_User.ID',
110
-            'Venue.TKT_wp_user'          => 'WP_User.ID',
111
-        ];
112
-        $this->_wp_core_model = true;
113
-        $this->_caps_slug = 'users';
114
-        $this->_cap_contexts_to_cap_action_map[ EEM_Base::caps_read ] = 'list';
115
-        $this->_cap_contexts_to_cap_action_map[ EEM_Base::caps_read_admin ] = 'list';
116
-        foreach ($this->_cap_contexts_to_cap_action_map as $context => $action) {
117
-            $this->_cap_restriction_generators[ $context ] = new EE_Restriction_Generator_WP_User();
118
-        }
119
-        // @todo: account for create_users controls whether they can create users at all
120
-        parent::__construct($timezone);
121
-    }
24
+	/**
25
+	 *    constructor
26
+	 *
27
+	 * @param null              $timezone
28
+	 * @param ModelFieldFactory $model_field_factory
29
+	 * @throws EE_Error
30
+	 * @throws InvalidArgumentException
31
+	 */
32
+	protected function __construct($timezone = '', ModelFieldFactory $model_field_factory)
33
+	{
34
+		$this->singular_item = esc_html__('WP_User', 'event_espresso');
35
+		$this->plural_item = esc_html__('WP_Users', 'event_espresso');
36
+		global $wpdb;
37
+		$this->_tables = array(
38
+			'WP_User' => new EE_Primary_Table($wpdb->users, 'ID', true),
39
+		);
40
+		$this->_fields = array(
41
+			'WP_User' => array(
42
+				'ID'                  => $model_field_factory->createPrimaryKeyIntField(
43
+					'ID',
44
+					esc_html__('WP_User ID', 'event_espresso')
45
+				),
46
+				'user_login'          => $model_field_factory->createPlainTextField(
47
+					'user_login',
48
+					esc_html__('User Login', 'event_espresso'),
49
+					false
50
+				),
51
+				'user_pass'           => $model_field_factory->createPlainTextField(
52
+					'user_pass',
53
+					esc_html__('User Password', 'event_espresso'),
54
+					false
55
+				),
56
+				'user_nicename'       => $model_field_factory->createPlainTextField(
57
+					'user_nicename',
58
+					esc_html__(' User Nice Name', 'event_espresso'),
59
+					false
60
+				),
61
+				'user_email'          => $model_field_factory->createEmailField(
62
+					'user_email',
63
+					esc_html__('User Email', 'event_espresso'),
64
+					false,
65
+					null
66
+				),
67
+				'user_registered'     => $model_field_factory->createDatetimeField(
68
+					'user_registered',
69
+					esc_html__('Date User Registered', 'event_espresso'),
70
+					$timezone
71
+				),
72
+				'user_activation_key' => $model_field_factory->createPlainTextField(
73
+					'user_activation_key',
74
+					esc_html__('User Activation Key', 'event_espresso'),
75
+					false
76
+				),
77
+				'user_status'         => $model_field_factory->createIntegerField(
78
+					'user_status',
79
+					esc_html__('User Status', 'event_espresso')
80
+				),
81
+				'display_name'        => $model_field_factory->createPlainTextField(
82
+					'display_name',
83
+					esc_html__('Display Name', 'event_espresso'),
84
+					false
85
+				),
86
+			),
87
+		);
88
+		$this->_model_relations = array(
89
+			'Attendee'       => new EE_Has_Many_Relation(),
90
+			// all models are related to the change log
91
+			// 'Change_Log'     => new EE_Has_Many_Relation(),
92
+			'Event'          => new EE_Has_Many_Relation(),
93
+			'Message'        => new EE_Has_Many_Relation(),
94
+			'Payment_Method' => new EE_Has_Many_Relation(),
95
+			'Price'          => new EE_Has_Many_Relation(),
96
+			'Price_Type'     => new EE_Has_Many_Relation(),
97
+			'Question'       => new EE_Has_Many_Relation(),
98
+			'Question_Group' => new EE_Has_Many_Relation(),
99
+			'Ticket'         => new EE_Has_Many_Relation(),
100
+			'Venue'          => new EE_Has_Many_Relation(),
101
+		);
102
+		$this->foreign_key_aliases = [
103
+			'Event.EVT_wp_user'          => 'WP_User.ID',
104
+			'Payment_Method.PMD_wp_user' => 'WP_User.ID',
105
+			'Price.PRC_wp_user'          => 'WP_User.ID',
106
+			'Price_Type.PRT_wp_user'     => 'WP_User.ID',
107
+			'Question.QST_wp_user'       => 'WP_User.ID',
108
+			'Question_Group.QSG_wp_user' => 'WP_User.ID',
109
+			'Ticket.VNU_wp_user'         => 'WP_User.ID',
110
+			'Venue.TKT_wp_user'          => 'WP_User.ID',
111
+		];
112
+		$this->_wp_core_model = true;
113
+		$this->_caps_slug = 'users';
114
+		$this->_cap_contexts_to_cap_action_map[ EEM_Base::caps_read ] = 'list';
115
+		$this->_cap_contexts_to_cap_action_map[ EEM_Base::caps_read_admin ] = 'list';
116
+		foreach ($this->_cap_contexts_to_cap_action_map as $context => $action) {
117
+			$this->_cap_restriction_generators[ $context ] = new EE_Restriction_Generator_WP_User();
118
+		}
119
+		// @todo: account for create_users controls whether they can create users at all
120
+		parent::__construct($timezone);
121
+	}
122 122
 
123 123
 
124
-    /**
125
-     * We don't need a foreign key to the WP_User model, we just need its primary key
126
-     *
127
-     * @return string
128
-     * @throws EE_Error
129
-     */
130
-    public function wp_user_field_name()
131
-    {
132
-        return $this->primary_key_name();
133
-    }
124
+	/**
125
+	 * We don't need a foreign key to the WP_User model, we just need its primary key
126
+	 *
127
+	 * @return string
128
+	 * @throws EE_Error
129
+	 */
130
+	public function wp_user_field_name()
131
+	{
132
+		return $this->primary_key_name();
133
+	}
134 134
 
135 135
 
136
-    /**
137
-     * This WP_User model IS owned, even though it doesn't have a foreign key to itself
138
-     *
139
-     * @return boolean
140
-     */
141
-    public function is_owned()
142
-    {
143
-        return true;
144
-    }
136
+	/**
137
+	 * This WP_User model IS owned, even though it doesn't have a foreign key to itself
138
+	 *
139
+	 * @return boolean
140
+	 */
141
+	public function is_owned()
142
+	{
143
+		return true;
144
+	}
145 145
 }
Please login to merge, or discard this patch.
core/db_models/relations/EE_Model_Relation_Base.php 3 patches
Doc Comments   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -149,9 +149,9 @@  discard block
 block discarded – undo
149 149
 
150 150
     /**
151 151
      * @param        $other_table
152
-     * @param        $other_table_alias
152
+     * @param        string $other_table_alias
153 153
      * @param        $other_table_column
154
-     * @param        $this_table_alias
154
+     * @param        string $this_table_alias
155 155
      * @param        $this_table_join_column
156 156
      * @param string $extra_join_sql
157 157
      * @return string
@@ -225,7 +225,7 @@  discard block
 block discarded – undo
225 225
      * Note: If the related model is extends EEM_Soft_Delete_Base, then the related
226 226
      * model objects will only be soft-deleted.
227 227
      *
228
-     * @param EE_Base_Class|int|string $model_object_or_id
228
+     * @param EE_Base_Class|null $model_object_or_id
229 229
      * @param array                    $query_params
230 230
      * @return int of how many related models got deleted
231 231
      * @throws EE_Error
@@ -259,7 +259,7 @@  discard block
 block discarded – undo
259 259
      * Note: If the related model is extends EEM_Soft_Delete_Base, then the related
260 260
      * model objects will only be soft-deleted.
261 261
      *
262
-     * @param EE_Base_Class|int|string $model_object_or_id
262
+     * @param EE_Base_Class|null $model_object_or_id
263 263
      * @param array                    $query_params
264 264
      * @return int of how many related models got deleted
265 265
      * @throws EE_Error
Please login to merge, or discard this patch.
Indentation   +507 added lines, -507 removed lines patch added patch discarded remove patch
@@ -16,512 +16,512 @@
 block discarded – undo
16 16
  */
17 17
 abstract class EE_Model_Relation_Base implements HasSchemaInterface
18 18
 {
19
-    /**
20
-     * The model name of which this relation is a component (ie, the model that called new EE_Model_Relation_Base)
21
-     *
22
-     * @var string eg Event, Question_Group, Registration
23
-     */
24
-    private $_this_model_name;
25
-    /**
26
-     * The model name pointed to by this relation (ie, the model we want to establish a relationship to)
27
-     *
28
-     * @var string eg Event, Question_Group, Registration
29
-     */
30
-    private $_other_model_name;
31
-
32
-    /**
33
-     * this is typically used when calling the relation models to make sure they inherit any set timezone from the
34
-     * initiating model.
35
-     *
36
-     * @var string
37
-     */
38
-    protected $_timezone;
39
-
40
-    /**
41
-     * If you try to delete "this_model", and there are related "other_models",
42
-     * and this isn't null, then abandon the deletion and add this warning.
43
-     * This effectively makes it impossible to delete "this_model" while there are
44
-     * related "other_models" along this relation.
45
-     *
46
-     * @var string (internationalized)
47
-     */
48
-    protected $_blocking_delete_error_message;
49
-
50
-    protected $_blocking_delete = false;
51
-
52
-    /**
53
-     * Object representing the relationship between two models. This knows how to join the models,
54
-     * get related models across the relation, and add-and-remove the relationships.
55
-     *
56
-     * @param boolean $block_deletes                 if there are related models across this relation, block (prevent
57
-     *                                               and add an error) the deletion of this model
58
-     * @param string  $blocking_delete_error_message a customized error message on blocking deletes instead of the
59
-     *                                               default
60
-     */
61
-    public function __construct($block_deletes, $blocking_delete_error_message)
62
-    {
63
-        $this->_blocking_delete               = $block_deletes;
64
-        $this->_blocking_delete_error_message = $blocking_delete_error_message;
65
-    }
66
-
67
-
68
-    /**
69
-     * @param $this_model_name
70
-     * @param $other_model_name
71
-     * @throws EE_Error
72
-     */
73
-    public function _construct_finalize_set_models($this_model_name, $other_model_name)
74
-    {
75
-        $this->_this_model_name  = $this_model_name;
76
-        $this->_other_model_name = $other_model_name;
77
-        if (is_string($this->_blocking_delete)) {
78
-            throw new EE_Error(sprintf(
79
-                __(
80
-                    "When instantiating the relation of type %s from %s to %s, the \$block_deletes argument should be a boolean, not a string (%s)",
81
-                    "event_espresso"
82
-                ),
83
-                get_class($this),
84
-                $this_model_name,
85
-                $other_model_name,
86
-                $this->_blocking_delete
87
-            ));
88
-        }
89
-    }
90
-
91
-
92
-    /**
93
-     * Gets the model where this relation is defined.
94
-     *
95
-     * @return EEM_Base
96
-     */
97
-    public function get_this_model()
98
-    {
99
-        return $this->_get_model($this->_this_model_name);
100
-    }
101
-
102
-
103
-    /**
104
-     * Gets the model which this relation establishes the relation TO (ie,
105
-     * this relation object was defined on get_this_model(), get_other_model() is the other one)
106
-     *
107
-     * @return EEM_Base
108
-     */
109
-    public function get_other_model()
110
-    {
111
-        return $this->_get_model($this->_other_model_name);
112
-    }
113
-
114
-
115
-    /**
116
-     * Internally used by get_this_model() and get_other_model()
117
-     *
118
-     * @param string $model_name like Event, Question_Group, etc. omit the EEM_
119
-     * @return EEM_Base
120
-     * @throws EE_Error
121
-     * @throws ReflectionException
122
-     */
123
-    protected function _get_model($model_name)
124
-    {
125
-        $modelInstance = EE_Registry::instance()->load_model($model_name);
126
-        // if the timezone is NOT set on the model but IS set for this relation
127
-        // (which seems really unlikely to ever happen, but whatever)
128
-        // make sure the model timezone is set
129
-        if ($this->_timezone && ! $modelInstance->get_timezone()) {
130
-            $modelInstance->set_timezone($this->_timezone);
131
-        }
132
-        return $modelInstance;
133
-    }
134
-
135
-
136
-    /**
137
-     * entirely possible that relations may be called from a model and we need to make sure those relations have their
138
-     * timezone set correctly.
139
-     *
140
-     * @param string $timezone timezone to set.
141
-     */
142
-    public function set_timezone($timezone)
143
-    {
144
-        if (! empty($timezone)) {
145
-            $this->_timezone = $timezone;
146
-        }
147
-    }
148
-
149
-
150
-    /**
151
-     * @param        $other_table
152
-     * @param        $other_table_alias
153
-     * @param        $other_table_column
154
-     * @param        $this_table_alias
155
-     * @param        $this_table_join_column
156
-     * @param string $extra_join_sql
157
-     * @return string
158
-     */
159
-    protected function _left_join(
160
-        $other_table,
161
-        $other_table_alias,
162
-        $other_table_column,
163
-        $this_table_alias,
164
-        $this_table_join_column,
165
-        $extra_join_sql = ''
166
-    ) {
167
-        return " LEFT JOIN " . $other_table . " AS " . $other_table_alias . " ON " . $other_table_alias . "." . $other_table_column . "=" . $this_table_alias . "." . $this_table_join_column . ($extra_join_sql ? " AND $extra_join_sql" : '');
168
-    }
169
-
170
-
171
-    /**
172
-     * Gets all the model objects of type of other model related to $model_object,
173
-     * according to this relation. This is the same code for EE_HABTM_Relation and EE_Has_Many_Relation.
174
-     * For both of those child classes, $model_object must be saved so that it has an ID before querying,
175
-     * otherwise an error will be thrown. Note: by default we disable default_where_conditions
176
-     * EE_Belongs_To_Relation doesn't need to be saved before querying.
177
-     *
178
-     * @param EE_Base_Class|int $model_object_or_id                      or the primary key of this model
179
-     * @param array             $query_params                            @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
180
-     * @param boolean           $values_already_prepared_by_model_object @deprecated since 4.8.1
181
-     * @return EE_Base_Class[]
182
-     * @throws EE_Error
183
-     * @throws ReflectionException
184
-     */
185
-    public function get_all_related(
186
-        $model_object_or_id,
187
-        $query_params = array(),
188
-        $values_already_prepared_by_model_object = false
189
-    ) {
190
-        if ($values_already_prepared_by_model_object !== false) {
191
-            EE_Error::doing_it_wrong(
192
-                'EE_Model_Relation_Base::get_all_related',
193
-                __('The argument $values_already_prepared_by_model_object is no longer used.', 'event_espresso'),
194
-                '4.8.1'
195
-            );
196
-        }
197
-        $query_params                                      = $this->_disable_default_where_conditions_on_query_param($query_params);
198
-        $query_param_where_this_model_pk                   = $this->get_this_model()->get_this_model_name()
199
-                                                             . "."
200
-                                                             . $this->get_this_model()->get_primary_key_field()->get_name();
201
-        $model_object_id                                   = $this->_get_model_object_id($model_object_or_id);
202
-        $query_params[0][ $query_param_where_this_model_pk ] = $model_object_id;
203
-        return $this->get_other_model()->get_all($query_params);
204
-    }
205
-
206
-
207
-    /**
208
-     * Alters the $query_params to disable default where conditions, unless otherwise specified
209
-     *
210
-     * @param array $query_params
211
-     * @return array
212
-     */
213
-    protected function _disable_default_where_conditions_on_query_param($query_params)
214
-    {
215
-        if (! isset($query_params['default_where_conditions'])) {
216
-            $query_params['default_where_conditions'] = 'none';
217
-        }
218
-        return $query_params;
219
-    }
220
-
221
-
222
-    /**
223
-     * Deletes the related model objects which meet the query parameters. If no
224
-     * parameters are specified, then all related model objects will be deleted.
225
-     * Note: If the related model is extends EEM_Soft_Delete_Base, then the related
226
-     * model objects will only be soft-deleted.
227
-     *
228
-     * @param EE_Base_Class|int|string $model_object_or_id
229
-     * @param array                    $query_params
230
-     * @return int of how many related models got deleted
231
-     * @throws EE_Error
232
-     * @throws ReflectionException
233
-     */
234
-    public function delete_all_related($model_object_or_id, $query_params = array())
235
-    {
236
-        // for each thing we would delete,
237
-        $related_model_objects = $this->get_all_related($model_object_or_id, $query_params);
238
-        // determine if it's blocked by anything else before it can be deleted
239
-        $deleted_count = 0;
240
-        foreach ($related_model_objects as $related_model_object) {
241
-            $delete_is_blocked = $this->get_other_model()->delete_is_blocked_by_related_models(
242
-                $related_model_object,
243
-                $model_object_or_id
244
-            );
245
-            /* @var $model_object_or_id EE_Base_Class */
246
-            if (! $delete_is_blocked) {
247
-                $this->remove_relation_to($model_object_or_id, $related_model_object);
248
-                $related_model_object->delete();
249
-                $deleted_count++;
250
-            }
251
-        }
252
-        return $deleted_count;
253
-    }
254
-
255
-
256
-    /**
257
-     * Deletes the related model objects which meet the query parameters. If no
258
-     * parameters are specified, then all related model objects will be deleted.
259
-     * Note: If the related model is extends EEM_Soft_Delete_Base, then the related
260
-     * model objects will only be soft-deleted.
261
-     *
262
-     * @param EE_Base_Class|int|string $model_object_or_id
263
-     * @param array                    $query_params
264
-     * @return int of how many related models got deleted
265
-     * @throws EE_Error
266
-     * @throws ReflectionException
267
-     */
268
-    public function delete_related_permanently($model_object_or_id, $query_params = array())
269
-    {
270
-        // for each thing we would delete,
271
-        $related_model_objects = $this->get_all_related($model_object_or_id, $query_params);
272
-        // determine if it's blocked by anything else before it can be deleted
273
-        $deleted_count = 0;
274
-        foreach ($related_model_objects as $related_model_object) {
275
-            $delete_is_blocked = $this->get_other_model()->delete_is_blocked_by_related_models(
276
-                $related_model_object,
277
-                $model_object_or_id
278
-            );
279
-            /* @var $model_object_or_id EE_Base_Class */
280
-            if ($related_model_object instanceof EE_Soft_Delete_Base_Class) {
281
-                $this->remove_relation_to($model_object_or_id, $related_model_object);
282
-                $deleted_count++;
283
-                if (! $delete_is_blocked) {
284
-                    $related_model_object->delete_permanently();
285
-                } else {
286
-                    // delete is blocked
287
-                    // brent and darren, in this case, wanted to just soft delete it then
288
-                    $related_model_object->delete();
289
-                }
290
-            } else {
291
-                // its not a soft-deletable thing anyways. do the normal logic.
292
-                if (! $delete_is_blocked) {
293
-                    $this->remove_relation_to($model_object_or_id, $related_model_object);
294
-                    $related_model_object->delete();
295
-                    $deleted_count++;
296
-                }
297
-            }
298
-        }
299
-        return $deleted_count;
300
-    }
301
-
302
-
303
-    /**
304
-     * this just returns a model_object_id for incoming item that could be an object or id.
305
-     *
306
-     * @param  EE_Base_Class|int $model_object_or_id model object or the primary key of this model
307
-     * @throws EE_Error
308
-     * @return int
309
-     */
310
-    protected function _get_model_object_id($model_object_or_id)
311
-    {
312
-        $model_object_id = $model_object_or_id;
313
-        if ($model_object_or_id instanceof EE_Base_Class) {
314
-            $model_object_id = $model_object_or_id->ID();
315
-        }
316
-        if (! $model_object_id) {
317
-            throw new EE_Error(sprintf(
318
-                __(
319
-                    "Sorry, we cant get the related %s model objects to %s model object before it has an ID. You can solve that by just saving it before trying to get its related model objects",
320
-                    "event_espresso"
321
-                ),
322
-                $this->get_other_model()->get_this_model_name(),
323
-                $this->get_this_model()->get_this_model_name()
324
-            ));
325
-        }
326
-        return $model_object_id;
327
-    }
328
-
329
-
330
-    /**
331
-     * Gets the SQL string for performing the join between this model and the other model.
332
-     *
333
-     * @param string $model_relation_chain like 'Event.Event_Venue.Venue'
334
-     * @return string of SQL, eg "LEFT JOIN table_name AS table_alias ON this_model_primary_table.pk =
335
-     *                other_model_primary_table.fk" etc
336
-     */
337
-    abstract public function get_join_statement($model_relation_chain);
338
-
339
-
340
-    /**
341
-     * Adds a relationships between the two model objects provided. Each type of relationship handles this differently
342
-     * (EE_Belongs_To is a slight exception, it should more accurately be called set_relation_to(...), as this
343
-     * relationship only allows this model to be related to a single other model of this type)
344
-     *
345
-     * @param       $this_obj_or_id
346
-     * @param       $other_obj_or_id
347
-     * @param array $extra_join_model_fields_n_values
348
-     * @return \EE_Base_Class the EE_Base_Class which was added as a relation. (Convenient if you only pass an ID for
349
-     *                        $other_obj_or_id)
350
-     */
351
-    abstract public function add_relation_to(
352
-        $this_obj_or_id,
353
-        $other_obj_or_id,
354
-        $extra_join_model_fields_n_values = array()
355
-    );
356
-
357
-
358
-    /**
359
-     * Similar to 'add_relation_to(...)', performs the opposite action of removing the relationship between the two
360
-     * model objects
361
-     *
362
-     * @param       $this_obj_or_id
363
-     * @param       $other_obj_or_id
364
-     * @param array $where_query
365
-     * @return bool
366
-     */
367
-    abstract public function remove_relation_to($this_obj_or_id, $other_obj_or_id, $where_query = array());
368
-
369
-
370
-    /**
371
-     * Removes ALL relation instances for this relation obj
372
-     *
373
-     * @param EE_Base_Class|int $this_obj_or_id
374
-     * @param array             $where_query_param @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
375
-     * @return EE_Base_Class[]
376
-     * @throws \EE_Error
377
-     */
378
-    public function remove_relations($this_obj_or_id, $where_query_param = array())
379
-    {
380
-        $related_things = $this->get_all_related($this_obj_or_id, array($where_query_param));
381
-        $objs_removed   = array();
382
-        foreach ($related_things as $related_thing) {
383
-            $objs_removed[] = $this->remove_relation_to($this_obj_or_id, $related_thing);
384
-        }
385
-        return $objs_removed;
386
-    }
387
-
388
-
389
-    /**
390
-     * If you aren't allowed to delete this model when there are related models across this
391
-     * relation object, return true. Otherwise, if you can delete this model even though
392
-     * related objects exist, returns false.
393
-     *
394
-     * @return boolean
395
-     */
396
-    public function block_delete_if_related_models_exist()
397
-    {
398
-        return $this->_blocking_delete;
399
-    }
400
-
401
-
402
-    /**
403
-     * Gets the error message to show
404
-     *
405
-     * @return string
406
-     */
407
-    public function get_deletion_error_message()
408
-    {
409
-        if ($this->_blocking_delete_error_message) {
410
-            return $this->_blocking_delete_error_message;
411
-        } else {
19
+	/**
20
+	 * The model name of which this relation is a component (ie, the model that called new EE_Model_Relation_Base)
21
+	 *
22
+	 * @var string eg Event, Question_Group, Registration
23
+	 */
24
+	private $_this_model_name;
25
+	/**
26
+	 * The model name pointed to by this relation (ie, the model we want to establish a relationship to)
27
+	 *
28
+	 * @var string eg Event, Question_Group, Registration
29
+	 */
30
+	private $_other_model_name;
31
+
32
+	/**
33
+	 * this is typically used when calling the relation models to make sure they inherit any set timezone from the
34
+	 * initiating model.
35
+	 *
36
+	 * @var string
37
+	 */
38
+	protected $_timezone;
39
+
40
+	/**
41
+	 * If you try to delete "this_model", and there are related "other_models",
42
+	 * and this isn't null, then abandon the deletion and add this warning.
43
+	 * This effectively makes it impossible to delete "this_model" while there are
44
+	 * related "other_models" along this relation.
45
+	 *
46
+	 * @var string (internationalized)
47
+	 */
48
+	protected $_blocking_delete_error_message;
49
+
50
+	protected $_blocking_delete = false;
51
+
52
+	/**
53
+	 * Object representing the relationship between two models. This knows how to join the models,
54
+	 * get related models across the relation, and add-and-remove the relationships.
55
+	 *
56
+	 * @param boolean $block_deletes                 if there are related models across this relation, block (prevent
57
+	 *                                               and add an error) the deletion of this model
58
+	 * @param string  $blocking_delete_error_message a customized error message on blocking deletes instead of the
59
+	 *                                               default
60
+	 */
61
+	public function __construct($block_deletes, $blocking_delete_error_message)
62
+	{
63
+		$this->_blocking_delete               = $block_deletes;
64
+		$this->_blocking_delete_error_message = $blocking_delete_error_message;
65
+	}
66
+
67
+
68
+	/**
69
+	 * @param $this_model_name
70
+	 * @param $other_model_name
71
+	 * @throws EE_Error
72
+	 */
73
+	public function _construct_finalize_set_models($this_model_name, $other_model_name)
74
+	{
75
+		$this->_this_model_name  = $this_model_name;
76
+		$this->_other_model_name = $other_model_name;
77
+		if (is_string($this->_blocking_delete)) {
78
+			throw new EE_Error(sprintf(
79
+				__(
80
+					"When instantiating the relation of type %s from %s to %s, the \$block_deletes argument should be a boolean, not a string (%s)",
81
+					"event_espresso"
82
+				),
83
+				get_class($this),
84
+				$this_model_name,
85
+				$other_model_name,
86
+				$this->_blocking_delete
87
+			));
88
+		}
89
+	}
90
+
91
+
92
+	/**
93
+	 * Gets the model where this relation is defined.
94
+	 *
95
+	 * @return EEM_Base
96
+	 */
97
+	public function get_this_model()
98
+	{
99
+		return $this->_get_model($this->_this_model_name);
100
+	}
101
+
102
+
103
+	/**
104
+	 * Gets the model which this relation establishes the relation TO (ie,
105
+	 * this relation object was defined on get_this_model(), get_other_model() is the other one)
106
+	 *
107
+	 * @return EEM_Base
108
+	 */
109
+	public function get_other_model()
110
+	{
111
+		return $this->_get_model($this->_other_model_name);
112
+	}
113
+
114
+
115
+	/**
116
+	 * Internally used by get_this_model() and get_other_model()
117
+	 *
118
+	 * @param string $model_name like Event, Question_Group, etc. omit the EEM_
119
+	 * @return EEM_Base
120
+	 * @throws EE_Error
121
+	 * @throws ReflectionException
122
+	 */
123
+	protected function _get_model($model_name)
124
+	{
125
+		$modelInstance = EE_Registry::instance()->load_model($model_name);
126
+		// if the timezone is NOT set on the model but IS set for this relation
127
+		// (which seems really unlikely to ever happen, but whatever)
128
+		// make sure the model timezone is set
129
+		if ($this->_timezone && ! $modelInstance->get_timezone()) {
130
+			$modelInstance->set_timezone($this->_timezone);
131
+		}
132
+		return $modelInstance;
133
+	}
134
+
135
+
136
+	/**
137
+	 * entirely possible that relations may be called from a model and we need to make sure those relations have their
138
+	 * timezone set correctly.
139
+	 *
140
+	 * @param string $timezone timezone to set.
141
+	 */
142
+	public function set_timezone($timezone)
143
+	{
144
+		if (! empty($timezone)) {
145
+			$this->_timezone = $timezone;
146
+		}
147
+	}
148
+
149
+
150
+	/**
151
+	 * @param        $other_table
152
+	 * @param        $other_table_alias
153
+	 * @param        $other_table_column
154
+	 * @param        $this_table_alias
155
+	 * @param        $this_table_join_column
156
+	 * @param string $extra_join_sql
157
+	 * @return string
158
+	 */
159
+	protected function _left_join(
160
+		$other_table,
161
+		$other_table_alias,
162
+		$other_table_column,
163
+		$this_table_alias,
164
+		$this_table_join_column,
165
+		$extra_join_sql = ''
166
+	) {
167
+		return " LEFT JOIN " . $other_table . " AS " . $other_table_alias . " ON " . $other_table_alias . "." . $other_table_column . "=" . $this_table_alias . "." . $this_table_join_column . ($extra_join_sql ? " AND $extra_join_sql" : '');
168
+	}
169
+
170
+
171
+	/**
172
+	 * Gets all the model objects of type of other model related to $model_object,
173
+	 * according to this relation. This is the same code for EE_HABTM_Relation and EE_Has_Many_Relation.
174
+	 * For both of those child classes, $model_object must be saved so that it has an ID before querying,
175
+	 * otherwise an error will be thrown. Note: by default we disable default_where_conditions
176
+	 * EE_Belongs_To_Relation doesn't need to be saved before querying.
177
+	 *
178
+	 * @param EE_Base_Class|int $model_object_or_id                      or the primary key of this model
179
+	 * @param array             $query_params                            @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
180
+	 * @param boolean           $values_already_prepared_by_model_object @deprecated since 4.8.1
181
+	 * @return EE_Base_Class[]
182
+	 * @throws EE_Error
183
+	 * @throws ReflectionException
184
+	 */
185
+	public function get_all_related(
186
+		$model_object_or_id,
187
+		$query_params = array(),
188
+		$values_already_prepared_by_model_object = false
189
+	) {
190
+		if ($values_already_prepared_by_model_object !== false) {
191
+			EE_Error::doing_it_wrong(
192
+				'EE_Model_Relation_Base::get_all_related',
193
+				__('The argument $values_already_prepared_by_model_object is no longer used.', 'event_espresso'),
194
+				'4.8.1'
195
+			);
196
+		}
197
+		$query_params                                      = $this->_disable_default_where_conditions_on_query_param($query_params);
198
+		$query_param_where_this_model_pk                   = $this->get_this_model()->get_this_model_name()
199
+															 . "."
200
+															 . $this->get_this_model()->get_primary_key_field()->get_name();
201
+		$model_object_id                                   = $this->_get_model_object_id($model_object_or_id);
202
+		$query_params[0][ $query_param_where_this_model_pk ] = $model_object_id;
203
+		return $this->get_other_model()->get_all($query_params);
204
+	}
205
+
206
+
207
+	/**
208
+	 * Alters the $query_params to disable default where conditions, unless otherwise specified
209
+	 *
210
+	 * @param array $query_params
211
+	 * @return array
212
+	 */
213
+	protected function _disable_default_where_conditions_on_query_param($query_params)
214
+	{
215
+		if (! isset($query_params['default_where_conditions'])) {
216
+			$query_params['default_where_conditions'] = 'none';
217
+		}
218
+		return $query_params;
219
+	}
220
+
221
+
222
+	/**
223
+	 * Deletes the related model objects which meet the query parameters. If no
224
+	 * parameters are specified, then all related model objects will be deleted.
225
+	 * Note: If the related model is extends EEM_Soft_Delete_Base, then the related
226
+	 * model objects will only be soft-deleted.
227
+	 *
228
+	 * @param EE_Base_Class|int|string $model_object_or_id
229
+	 * @param array                    $query_params
230
+	 * @return int of how many related models got deleted
231
+	 * @throws EE_Error
232
+	 * @throws ReflectionException
233
+	 */
234
+	public function delete_all_related($model_object_or_id, $query_params = array())
235
+	{
236
+		// for each thing we would delete,
237
+		$related_model_objects = $this->get_all_related($model_object_or_id, $query_params);
238
+		// determine if it's blocked by anything else before it can be deleted
239
+		$deleted_count = 0;
240
+		foreach ($related_model_objects as $related_model_object) {
241
+			$delete_is_blocked = $this->get_other_model()->delete_is_blocked_by_related_models(
242
+				$related_model_object,
243
+				$model_object_or_id
244
+			);
245
+			/* @var $model_object_or_id EE_Base_Class */
246
+			if (! $delete_is_blocked) {
247
+				$this->remove_relation_to($model_object_or_id, $related_model_object);
248
+				$related_model_object->delete();
249
+				$deleted_count++;
250
+			}
251
+		}
252
+		return $deleted_count;
253
+	}
254
+
255
+
256
+	/**
257
+	 * Deletes the related model objects which meet the query parameters. If no
258
+	 * parameters are specified, then all related model objects will be deleted.
259
+	 * Note: If the related model is extends EEM_Soft_Delete_Base, then the related
260
+	 * model objects will only be soft-deleted.
261
+	 *
262
+	 * @param EE_Base_Class|int|string $model_object_or_id
263
+	 * @param array                    $query_params
264
+	 * @return int of how many related models got deleted
265
+	 * @throws EE_Error
266
+	 * @throws ReflectionException
267
+	 */
268
+	public function delete_related_permanently($model_object_or_id, $query_params = array())
269
+	{
270
+		// for each thing we would delete,
271
+		$related_model_objects = $this->get_all_related($model_object_or_id, $query_params);
272
+		// determine if it's blocked by anything else before it can be deleted
273
+		$deleted_count = 0;
274
+		foreach ($related_model_objects as $related_model_object) {
275
+			$delete_is_blocked = $this->get_other_model()->delete_is_blocked_by_related_models(
276
+				$related_model_object,
277
+				$model_object_or_id
278
+			);
279
+			/* @var $model_object_or_id EE_Base_Class */
280
+			if ($related_model_object instanceof EE_Soft_Delete_Base_Class) {
281
+				$this->remove_relation_to($model_object_or_id, $related_model_object);
282
+				$deleted_count++;
283
+				if (! $delete_is_blocked) {
284
+					$related_model_object->delete_permanently();
285
+				} else {
286
+					// delete is blocked
287
+					// brent and darren, in this case, wanted to just soft delete it then
288
+					$related_model_object->delete();
289
+				}
290
+			} else {
291
+				// its not a soft-deletable thing anyways. do the normal logic.
292
+				if (! $delete_is_blocked) {
293
+					$this->remove_relation_to($model_object_or_id, $related_model_object);
294
+					$related_model_object->delete();
295
+					$deleted_count++;
296
+				}
297
+			}
298
+		}
299
+		return $deleted_count;
300
+	}
301
+
302
+
303
+	/**
304
+	 * this just returns a model_object_id for incoming item that could be an object or id.
305
+	 *
306
+	 * @param  EE_Base_Class|int $model_object_or_id model object or the primary key of this model
307
+	 * @throws EE_Error
308
+	 * @return int
309
+	 */
310
+	protected function _get_model_object_id($model_object_or_id)
311
+	{
312
+		$model_object_id = $model_object_or_id;
313
+		if ($model_object_or_id instanceof EE_Base_Class) {
314
+			$model_object_id = $model_object_or_id->ID();
315
+		}
316
+		if (! $model_object_id) {
317
+			throw new EE_Error(sprintf(
318
+				__(
319
+					"Sorry, we cant get the related %s model objects to %s model object before it has an ID. You can solve that by just saving it before trying to get its related model objects",
320
+					"event_espresso"
321
+				),
322
+				$this->get_other_model()->get_this_model_name(),
323
+				$this->get_this_model()->get_this_model_name()
324
+			));
325
+		}
326
+		return $model_object_id;
327
+	}
328
+
329
+
330
+	/**
331
+	 * Gets the SQL string for performing the join between this model and the other model.
332
+	 *
333
+	 * @param string $model_relation_chain like 'Event.Event_Venue.Venue'
334
+	 * @return string of SQL, eg "LEFT JOIN table_name AS table_alias ON this_model_primary_table.pk =
335
+	 *                other_model_primary_table.fk" etc
336
+	 */
337
+	abstract public function get_join_statement($model_relation_chain);
338
+
339
+
340
+	/**
341
+	 * Adds a relationships between the two model objects provided. Each type of relationship handles this differently
342
+	 * (EE_Belongs_To is a slight exception, it should more accurately be called set_relation_to(...), as this
343
+	 * relationship only allows this model to be related to a single other model of this type)
344
+	 *
345
+	 * @param       $this_obj_or_id
346
+	 * @param       $other_obj_or_id
347
+	 * @param array $extra_join_model_fields_n_values
348
+	 * @return \EE_Base_Class the EE_Base_Class which was added as a relation. (Convenient if you only pass an ID for
349
+	 *                        $other_obj_or_id)
350
+	 */
351
+	abstract public function add_relation_to(
352
+		$this_obj_or_id,
353
+		$other_obj_or_id,
354
+		$extra_join_model_fields_n_values = array()
355
+	);
356
+
357
+
358
+	/**
359
+	 * Similar to 'add_relation_to(...)', performs the opposite action of removing the relationship between the two
360
+	 * model objects
361
+	 *
362
+	 * @param       $this_obj_or_id
363
+	 * @param       $other_obj_or_id
364
+	 * @param array $where_query
365
+	 * @return bool
366
+	 */
367
+	abstract public function remove_relation_to($this_obj_or_id, $other_obj_or_id, $where_query = array());
368
+
369
+
370
+	/**
371
+	 * Removes ALL relation instances for this relation obj
372
+	 *
373
+	 * @param EE_Base_Class|int $this_obj_or_id
374
+	 * @param array             $where_query_param @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
375
+	 * @return EE_Base_Class[]
376
+	 * @throws \EE_Error
377
+	 */
378
+	public function remove_relations($this_obj_or_id, $where_query_param = array())
379
+	{
380
+		$related_things = $this->get_all_related($this_obj_or_id, array($where_query_param));
381
+		$objs_removed   = array();
382
+		foreach ($related_things as $related_thing) {
383
+			$objs_removed[] = $this->remove_relation_to($this_obj_or_id, $related_thing);
384
+		}
385
+		return $objs_removed;
386
+	}
387
+
388
+
389
+	/**
390
+	 * If you aren't allowed to delete this model when there are related models across this
391
+	 * relation object, return true. Otherwise, if you can delete this model even though
392
+	 * related objects exist, returns false.
393
+	 *
394
+	 * @return boolean
395
+	 */
396
+	public function block_delete_if_related_models_exist()
397
+	{
398
+		return $this->_blocking_delete;
399
+	}
400
+
401
+
402
+	/**
403
+	 * Gets the error message to show
404
+	 *
405
+	 * @return string
406
+	 */
407
+	public function get_deletion_error_message()
408
+	{
409
+		if ($this->_blocking_delete_error_message) {
410
+			return $this->_blocking_delete_error_message;
411
+		} else {
412 412
 //          return sprintf(__('Cannot delete %1$s when there are related %2$s', "event_espresso"),$this->get_this_model()->item_name(2),$this->get_other_model()->item_name(2));
413
-            return sprintf(
414
-                __(
415
-                    'This %1$s is currently linked to one or more %2$s records. If this %1$s is incorrect, then please remove it from all %3$s before attempting to delete it.',
416
-                    "event_espresso"
417
-                ),
418
-                $this->get_this_model()->item_name(1),
419
-                $this->get_other_model()->item_name(1),
420
-                $this->get_other_model()->item_name(2)
421
-            );
422
-        }
423
-    }
424
-
425
-    /**
426
-     * Returns whatever is set as the nicename for the object.
427
-     *
428
-     * @return string
429
-     */
430
-    public function getSchemaDescription()
431
-    {
432
-        $description = $this instanceof EE_Belongs_To_Relation
433
-            ? esc_html__('The related %1$s entity to the %2$s.', 'event_espresso')
434
-            : esc_html__('The related %1$s entities to the %2$s.', 'event_espresso');
435
-        return sprintf(
436
-            $description,
437
-            $this->get_other_model()->get_this_model_name(),
438
-            $this->get_this_model()->get_this_model_name()
439
-        );
440
-    }
441
-
442
-    /**
443
-     * Returns whatever is set as the $_schema_type property for the object.
444
-     * Note: this will automatically add 'null' to the schema if the object is_nullable()
445
-     *
446
-     * @return string|array
447
-     */
448
-    public function getSchemaType()
449
-    {
450
-        return $this instanceof EE_Belongs_To_Relation ? 'object' : 'array';
451
-    }
452
-
453
-    /**
454
-     * This is usually present when the $_schema_type property is 'object'.  Any child classes will need to override
455
-     * this method and return the properties for the schema.
456
-     * The reason this is not a property on the class is because there may be filters set on the values for the property
457
-     * that won't be exposed on construct.  For example enum type schemas may have the enum values filtered.
458
-     *
459
-     * @return array
460
-     */
461
-    public function getSchemaProperties()
462
-    {
463
-        return array();
464
-    }
465
-
466
-    /**
467
-     * If a child class has enum values, they should override this method and provide a simple array
468
-     * of the enum values.
469
-     * The reason this is not a property on the class is because there may be filterable enum values that
470
-     * are set on the instantiated object that could be filtered after construct.
471
-     *
472
-     * @return array
473
-     */
474
-    public function getSchemaEnum()
475
-    {
476
-        return array();
477
-    }
478
-
479
-    /**
480
-     * This returns the value of the $_schema_format property on the object.
481
-     *
482
-     * @return string
483
-     */
484
-    public function getSchemaFormat()
485
-    {
486
-        return array();
487
-    }
488
-
489
-    /**
490
-     * This returns the value of the $_schema_readonly property on the object.
491
-     *
492
-     * @return bool
493
-     */
494
-    public function getSchemaReadonly()
495
-    {
496
-        return true;
497
-    }
498
-
499
-    /**
500
-     * This returns elements used to represent this field in the json schema.
501
-     *
502
-     * @link http://json-schema.org/
503
-     * @return array
504
-     */
505
-    public function getSchema()
506
-    {
507
-        $schema = array(
508
-            'description' => $this->getSchemaDescription(),
509
-            'type' => $this->getSchemaType(),
510
-            'relation' => true,
511
-            'relation_type' => get_class($this),
512
-            'readonly' => $this->getSchemaReadonly()
513
-        );
514
-
515
-        if ($this instanceof EE_HABTM_Relation) {
516
-            $schema['joining_model_name'] = $this->get_join_model()->get_this_model_name();
517
-        }
518
-
519
-        if ($this->getSchemaType() === 'array') {
520
-            $schema['items'] = array(
521
-                'type' => 'object'
522
-            );
523
-        }
524
-
525
-        return $schema;
526
-    }
413
+			return sprintf(
414
+				__(
415
+					'This %1$s is currently linked to one or more %2$s records. If this %1$s is incorrect, then please remove it from all %3$s before attempting to delete it.',
416
+					"event_espresso"
417
+				),
418
+				$this->get_this_model()->item_name(1),
419
+				$this->get_other_model()->item_name(1),
420
+				$this->get_other_model()->item_name(2)
421
+			);
422
+		}
423
+	}
424
+
425
+	/**
426
+	 * Returns whatever is set as the nicename for the object.
427
+	 *
428
+	 * @return string
429
+	 */
430
+	public function getSchemaDescription()
431
+	{
432
+		$description = $this instanceof EE_Belongs_To_Relation
433
+			? esc_html__('The related %1$s entity to the %2$s.', 'event_espresso')
434
+			: esc_html__('The related %1$s entities to the %2$s.', 'event_espresso');
435
+		return sprintf(
436
+			$description,
437
+			$this->get_other_model()->get_this_model_name(),
438
+			$this->get_this_model()->get_this_model_name()
439
+		);
440
+	}
441
+
442
+	/**
443
+	 * Returns whatever is set as the $_schema_type property for the object.
444
+	 * Note: this will automatically add 'null' to the schema if the object is_nullable()
445
+	 *
446
+	 * @return string|array
447
+	 */
448
+	public function getSchemaType()
449
+	{
450
+		return $this instanceof EE_Belongs_To_Relation ? 'object' : 'array';
451
+	}
452
+
453
+	/**
454
+	 * This is usually present when the $_schema_type property is 'object'.  Any child classes will need to override
455
+	 * this method and return the properties for the schema.
456
+	 * The reason this is not a property on the class is because there may be filters set on the values for the property
457
+	 * that won't be exposed on construct.  For example enum type schemas may have the enum values filtered.
458
+	 *
459
+	 * @return array
460
+	 */
461
+	public function getSchemaProperties()
462
+	{
463
+		return array();
464
+	}
465
+
466
+	/**
467
+	 * If a child class has enum values, they should override this method and provide a simple array
468
+	 * of the enum values.
469
+	 * The reason this is not a property on the class is because there may be filterable enum values that
470
+	 * are set on the instantiated object that could be filtered after construct.
471
+	 *
472
+	 * @return array
473
+	 */
474
+	public function getSchemaEnum()
475
+	{
476
+		return array();
477
+	}
478
+
479
+	/**
480
+	 * This returns the value of the $_schema_format property on the object.
481
+	 *
482
+	 * @return string
483
+	 */
484
+	public function getSchemaFormat()
485
+	{
486
+		return array();
487
+	}
488
+
489
+	/**
490
+	 * This returns the value of the $_schema_readonly property on the object.
491
+	 *
492
+	 * @return bool
493
+	 */
494
+	public function getSchemaReadonly()
495
+	{
496
+		return true;
497
+	}
498
+
499
+	/**
500
+	 * This returns elements used to represent this field in the json schema.
501
+	 *
502
+	 * @link http://json-schema.org/
503
+	 * @return array
504
+	 */
505
+	public function getSchema()
506
+	{
507
+		$schema = array(
508
+			'description' => $this->getSchemaDescription(),
509
+			'type' => $this->getSchemaType(),
510
+			'relation' => true,
511
+			'relation_type' => get_class($this),
512
+			'readonly' => $this->getSchemaReadonly()
513
+		);
514
+
515
+		if ($this instanceof EE_HABTM_Relation) {
516
+			$schema['joining_model_name'] = $this->get_join_model()->get_this_model_name();
517
+		}
518
+
519
+		if ($this->getSchemaType() === 'array') {
520
+			$schema['items'] = array(
521
+				'type' => 'object'
522
+			);
523
+		}
524
+
525
+		return $schema;
526
+	}
527 527
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -141,7 +141,7 @@  discard block
 block discarded – undo
141 141
      */
142 142
     public function set_timezone($timezone)
143 143
     {
144
-        if (! empty($timezone)) {
144
+        if ( ! empty($timezone)) {
145 145
             $this->_timezone = $timezone;
146 146
         }
147 147
     }
@@ -164,7 +164,7 @@  discard block
 block discarded – undo
164 164
         $this_table_join_column,
165 165
         $extra_join_sql = ''
166 166
     ) {
167
-        return " LEFT JOIN " . $other_table . " AS " . $other_table_alias . " ON " . $other_table_alias . "." . $other_table_column . "=" . $this_table_alias . "." . $this_table_join_column . ($extra_join_sql ? " AND $extra_join_sql" : '');
167
+        return " LEFT JOIN ".$other_table." AS ".$other_table_alias." ON ".$other_table_alias.".".$other_table_column."=".$this_table_alias.".".$this_table_join_column.($extra_join_sql ? " AND $extra_join_sql" : '');
168 168
     }
169 169
 
170 170
 
@@ -199,7 +199,7 @@  discard block
 block discarded – undo
199 199
                                                              . "."
200 200
                                                              . $this->get_this_model()->get_primary_key_field()->get_name();
201 201
         $model_object_id                                   = $this->_get_model_object_id($model_object_or_id);
202
-        $query_params[0][ $query_param_where_this_model_pk ] = $model_object_id;
202
+        $query_params[0][$query_param_where_this_model_pk] = $model_object_id;
203 203
         return $this->get_other_model()->get_all($query_params);
204 204
     }
205 205
 
@@ -212,7 +212,7 @@  discard block
 block discarded – undo
212 212
      */
213 213
     protected function _disable_default_where_conditions_on_query_param($query_params)
214 214
     {
215
-        if (! isset($query_params['default_where_conditions'])) {
215
+        if ( ! isset($query_params['default_where_conditions'])) {
216 216
             $query_params['default_where_conditions'] = 'none';
217 217
         }
218 218
         return $query_params;
@@ -243,7 +243,7 @@  discard block
 block discarded – undo
243 243
                 $model_object_or_id
244 244
             );
245 245
             /* @var $model_object_or_id EE_Base_Class */
246
-            if (! $delete_is_blocked) {
246
+            if ( ! $delete_is_blocked) {
247 247
                 $this->remove_relation_to($model_object_or_id, $related_model_object);
248 248
                 $related_model_object->delete();
249 249
                 $deleted_count++;
@@ -280,7 +280,7 @@  discard block
 block discarded – undo
280 280
             if ($related_model_object instanceof EE_Soft_Delete_Base_Class) {
281 281
                 $this->remove_relation_to($model_object_or_id, $related_model_object);
282 282
                 $deleted_count++;
283
-                if (! $delete_is_blocked) {
283
+                if ( ! $delete_is_blocked) {
284 284
                     $related_model_object->delete_permanently();
285 285
                 } else {
286 286
                     // delete is blocked
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
                 }
290 290
             } else {
291 291
                 // its not a soft-deletable thing anyways. do the normal logic.
292
-                if (! $delete_is_blocked) {
292
+                if ( ! $delete_is_blocked) {
293 293
                     $this->remove_relation_to($model_object_or_id, $related_model_object);
294 294
                     $related_model_object->delete();
295 295
                     $deleted_count++;
@@ -313,7 +313,7 @@  discard block
 block discarded – undo
313 313
         if ($model_object_or_id instanceof EE_Base_Class) {
314 314
             $model_object_id = $model_object_or_id->ID();
315 315
         }
316
-        if (! $model_object_id) {
316
+        if ( ! $model_object_id) {
317 317
             throw new EE_Error(sprintf(
318 318
                 __(
319 319
                     "Sorry, we cant get the related %s model objects to %s model object before it has an ID. You can solve that by just saving it before trying to get its related model objects",
Please login to merge, or discard this patch.
core/services/helpers/datetime/PhpCompatLessFiveSixHelper.php 1 patch
Indentation   +213 added lines, -213 removed lines patch added patch discarded remove patch
@@ -19,222 +19,222 @@
 block discarded – undo
19 19
 class PhpCompatLessFiveSixHelper extends AbstractHelper
20 20
 {
21 21
 
22
-    /**
23
-     * PhpCompatLessFiveSixHelper constructor.
24
-     *
25
-     * @throws DomainException
26
-     */
27
-    public function __construct()
28
-    {
29
-        if (PHP_VERSION_ID >= 50600) {
30
-            throw new DomainException(
31
-                sprintf(
32
-                    esc_html__(
33
-                        'The %1$s is only usable on php versions less than 5.6.  You\'ll want to use %2$s instead.',
34
-                        'event_espresso'
35
-                    ),
36
-                    __CLASS__,
37
-                    'EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper'
38
-                )
39
-            );
40
-        }
41
-        parent::__construct();
42
-    }
22
+	/**
23
+	 * PhpCompatLessFiveSixHelper constructor.
24
+	 *
25
+	 * @throws DomainException
26
+	 */
27
+	public function __construct()
28
+	{
29
+		if (PHP_VERSION_ID >= 50600) {
30
+			throw new DomainException(
31
+				sprintf(
32
+					esc_html__(
33
+						'The %1$s is only usable on php versions less than 5.6.  You\'ll want to use %2$s instead.',
34
+						'event_espresso'
35
+					),
36
+					__CLASS__,
37
+					'EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper'
38
+				)
39
+			);
40
+		}
41
+		parent::__construct();
42
+	}
43 43
 
44
-    /**
45
-     * Returns a timezone string for the provided gmt_offset.
46
-     *
47
-     * @param float|string $gmt_offset
48
-     * @return string
49
-     * @throws EE_Error
50
-     */
51
-    public function getTimezoneStringFromGmtOffset($gmt_offset = '')
52
-    {
53
-        $gmt_offset_or_timezone_string = $this->sanitizeInitialIncomingGmtOffsetForGettingTimezoneString($gmt_offset);
54
-        if (is_string($gmt_offset_or_timezone_string)) {
55
-            return $gmt_offset_or_timezone_string;
56
-        }
57
-        // well we know its a float, so let's roll with it.
58
-        $gmt_offset = $gmt_offset_or_timezone_string;
59
-        // convert GMT offset to seconds
60
-        $gmt_offset *= HOUR_IN_SECONDS;
61
-        // although we don't know the TZ abbreviation, we know the UTC offset
62
-        $timezone_string = timezone_name_from_abbr(null, $gmt_offset);
63
-        // only use this timezone_string IF it's current offset matches the given offset
64
-        if (! empty($timezone_string)) {
65
-            $offset = null;
66
-            try {
67
-                $offset = $this->getTimezoneOffset(new DateTimeZone($timezone_string));
68
-                if ($offset !== $gmt_offset) {
69
-                    $timezone_string = false;
70
-                }
71
-            } catch (Exception $e) {
72
-                $timezone_string = false;
73
-            }
74
-        }
75
-        // better have a valid timezone string by now, but if not, sigh... loop thru  the timezone_abbreviations_list()
76
-        // ...
77
-        $timezone_string = $timezone_string !== false
78
-            ? $timezone_string
79
-            : $this->getTimezoneStringFromAbbreviationsList($gmt_offset);
80
-        return $timezone_string;
81
-    }
44
+	/**
45
+	 * Returns a timezone string for the provided gmt_offset.
46
+	 *
47
+	 * @param float|string $gmt_offset
48
+	 * @return string
49
+	 * @throws EE_Error
50
+	 */
51
+	public function getTimezoneStringFromGmtOffset($gmt_offset = '')
52
+	{
53
+		$gmt_offset_or_timezone_string = $this->sanitizeInitialIncomingGmtOffsetForGettingTimezoneString($gmt_offset);
54
+		if (is_string($gmt_offset_or_timezone_string)) {
55
+			return $gmt_offset_or_timezone_string;
56
+		}
57
+		// well we know its a float, so let's roll with it.
58
+		$gmt_offset = $gmt_offset_or_timezone_string;
59
+		// convert GMT offset to seconds
60
+		$gmt_offset *= HOUR_IN_SECONDS;
61
+		// although we don't know the TZ abbreviation, we know the UTC offset
62
+		$timezone_string = timezone_name_from_abbr(null, $gmt_offset);
63
+		// only use this timezone_string IF it's current offset matches the given offset
64
+		if (! empty($timezone_string)) {
65
+			$offset = null;
66
+			try {
67
+				$offset = $this->getTimezoneOffset(new DateTimeZone($timezone_string));
68
+				if ($offset !== $gmt_offset) {
69
+					$timezone_string = false;
70
+				}
71
+			} catch (Exception $e) {
72
+				$timezone_string = false;
73
+			}
74
+		}
75
+		// better have a valid timezone string by now, but if not, sigh... loop thru  the timezone_abbreviations_list()
76
+		// ...
77
+		$timezone_string = $timezone_string !== false
78
+			? $timezone_string
79
+			: $this->getTimezoneStringFromAbbreviationsList($gmt_offset);
80
+		return $timezone_string;
81
+	}
82 82
 
83 83
 
84
-    /**
85
-     * @param int  $gmt_offset
86
-     * @param bool $coerce If true, we attempt to coerce with our adjustment table
87
-     * @see self::adjustInvalidGmtOffset
88
-     * @return string
89
-     * @throws EE_Error
90
-     */
91
-    protected function getTimezoneStringFromAbbreviationsList($gmt_offset = 0, $coerce = true)
92
-    {
93
-        $gmt_offset = (int) $gmt_offset;
94
-        /** @var array[] $abbreviations */
95
-        $abbreviations = DateTimeZone::listAbbreviations();
96
-        foreach ($abbreviations as $abbreviation) {
97
-            foreach ($abbreviation as $timezone) {
98
-                if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) {
99
-                    try {
100
-                        $offset = $this->getTimezoneOffset(new DateTimeZone($timezone['timezone_id']));
101
-                        if ($offset !== $gmt_offset) {
102
-                            continue;
103
-                        }
104
-                        return $timezone['timezone_id'];
105
-                    } catch (Exception $e) {
106
-                        continue;
107
-                    }
108
-                }
109
-            }
110
-        }
111
-        // if $coerce is true, let's see if we can get a timezone string after the offset is adjusted
112
-        if ($coerce === true) {
113
-            $timezone_string = $this->getTimezoneStringFromAbbreviationsList(
114
-                $this->adjustInvalidGmtOffsets($gmt_offset),
115
-                false
116
-            );
117
-            if ($timezone_string) {
118
-                return $timezone_string;
119
-            }
120
-        }
121
-        throw new EE_Error(
122
-            sprintf(
123
-                esc_html__(
124
-                    'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
125
-                    'event_espresso'
126
-                ),
127
-                $gmt_offset / HOUR_IN_SECONDS,
128
-                '<a href="http://www.php.net/manual/en/timezones.php">',
129
-                '</a>'
130
-            )
131
-        );
132
-    }
84
+	/**
85
+	 * @param int  $gmt_offset
86
+	 * @param bool $coerce If true, we attempt to coerce with our adjustment table
87
+	 * @see self::adjustInvalidGmtOffset
88
+	 * @return string
89
+	 * @throws EE_Error
90
+	 */
91
+	protected function getTimezoneStringFromAbbreviationsList($gmt_offset = 0, $coerce = true)
92
+	{
93
+		$gmt_offset = (int) $gmt_offset;
94
+		/** @var array[] $abbreviations */
95
+		$abbreviations = DateTimeZone::listAbbreviations();
96
+		foreach ($abbreviations as $abbreviation) {
97
+			foreach ($abbreviation as $timezone) {
98
+				if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) {
99
+					try {
100
+						$offset = $this->getTimezoneOffset(new DateTimeZone($timezone['timezone_id']));
101
+						if ($offset !== $gmt_offset) {
102
+							continue;
103
+						}
104
+						return $timezone['timezone_id'];
105
+					} catch (Exception $e) {
106
+						continue;
107
+					}
108
+				}
109
+			}
110
+		}
111
+		// if $coerce is true, let's see if we can get a timezone string after the offset is adjusted
112
+		if ($coerce === true) {
113
+			$timezone_string = $this->getTimezoneStringFromAbbreviationsList(
114
+				$this->adjustInvalidGmtOffsets($gmt_offset),
115
+				false
116
+			);
117
+			if ($timezone_string) {
118
+				return $timezone_string;
119
+			}
120
+		}
121
+		throw new EE_Error(
122
+			sprintf(
123
+				esc_html__(
124
+					'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
125
+					'event_espresso'
126
+				),
127
+				$gmt_offset / HOUR_IN_SECONDS,
128
+				'<a href="http://www.php.net/manual/en/timezones.php">',
129
+				'</a>'
130
+			)
131
+		);
132
+	}
133 133
 
134 134
 
135
-    /**
136
-     * Depending on PHP version,
137
-     * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
138
-     * To get around that, for these fringe timezones we bump them to a known valid offset.
139
-     * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
140
-     *
141
-     * @param int $gmt_offset
142
-     * @return int
143
-     */
144
-    public function adjustInvalidGmtOffsets($gmt_offset = 0)
145
-    {
146
-        // make sure $gmt_offset is int
147
-        $gmt_offset = (int) $gmt_offset;
148
-        switch ($gmt_offset) {
149
-            // -12
150
-            case -43200:
151
-                $gmt_offset = -39600;
152
-                break;
153
-            // -11.5
154
-            case -41400:
155
-                $gmt_offset = -39600;
156
-                break;
157
-            // -10.5
158
-            case -37800:
159
-                $gmt_offset = -39600;
160
-                break;
161
-            // -8.5
162
-            case -30600:
163
-                $gmt_offset = -28800;
164
-                break;
165
-            // -7.5
166
-            case -27000:
167
-                $gmt_offset = -25200;
168
-                break;
169
-            // -6.5
170
-            case -23400:
171
-                $gmt_offset = -21600;
172
-                break;
173
-            // -5.5
174
-            case -19800:
175
-                $gmt_offset = -18000;
176
-                break;
177
-            // -4.5
178
-            case -16200:
179
-                $gmt_offset = -14400;
180
-                break;
181
-            // -3.5
182
-            case -12600:
183
-                $gmt_offset = -10800;
184
-                break;
185
-            // -2.5
186
-            case -9000:
187
-                $gmt_offset = -7200;
188
-                break;
189
-            // -1.5
190
-            case -5400:
191
-                $gmt_offset = -3600;
192
-                break;
193
-            // -0.5
194
-            case -1800:
195
-                $gmt_offset = 0;
196
-                break;
197
-            // .5
198
-            case 1800:
199
-                $gmt_offset = 3600;
200
-                break;
201
-            // 1.5
202
-            case 5400:
203
-                $gmt_offset = 7200;
204
-                break;
205
-            // 2.5
206
-            case 9000:
207
-                $gmt_offset = 10800;
208
-                break;
209
-            // 3.5
210
-            case 12600:
211
-                $gmt_offset = 14400;
212
-                break;
213
-            // 7.5
214
-            case 27000:
215
-                $gmt_offset = 28800;
216
-                break;
217
-            // 8.5
218
-            case 30600:
219
-                $gmt_offset = 31500;
220
-                break;
221
-            // 10.5
222
-            case 37800:
223
-                $gmt_offset = 39600;
224
-                break;
225
-            // 11.5
226
-            case 41400:
227
-                $gmt_offset = 43200;
228
-                break;
229
-            // 12.75
230
-            case 45900:
231
-                $gmt_offset = 46800;
232
-                break;
233
-            // 13.75
234
-            case 49500:
235
-                $gmt_offset = 50400;
236
-                break;
237
-        }
238
-        return $gmt_offset;
239
-    }
135
+	/**
136
+	 * Depending on PHP version,
137
+	 * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
138
+	 * To get around that, for these fringe timezones we bump them to a known valid offset.
139
+	 * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
140
+	 *
141
+	 * @param int $gmt_offset
142
+	 * @return int
143
+	 */
144
+	public function adjustInvalidGmtOffsets($gmt_offset = 0)
145
+	{
146
+		// make sure $gmt_offset is int
147
+		$gmt_offset = (int) $gmt_offset;
148
+		switch ($gmt_offset) {
149
+			// -12
150
+			case -43200:
151
+				$gmt_offset = -39600;
152
+				break;
153
+			// -11.5
154
+			case -41400:
155
+				$gmt_offset = -39600;
156
+				break;
157
+			// -10.5
158
+			case -37800:
159
+				$gmt_offset = -39600;
160
+				break;
161
+			// -8.5
162
+			case -30600:
163
+				$gmt_offset = -28800;
164
+				break;
165
+			// -7.5
166
+			case -27000:
167
+				$gmt_offset = -25200;
168
+				break;
169
+			// -6.5
170
+			case -23400:
171
+				$gmt_offset = -21600;
172
+				break;
173
+			// -5.5
174
+			case -19800:
175
+				$gmt_offset = -18000;
176
+				break;
177
+			// -4.5
178
+			case -16200:
179
+				$gmt_offset = -14400;
180
+				break;
181
+			// -3.5
182
+			case -12600:
183
+				$gmt_offset = -10800;
184
+				break;
185
+			// -2.5
186
+			case -9000:
187
+				$gmt_offset = -7200;
188
+				break;
189
+			// -1.5
190
+			case -5400:
191
+				$gmt_offset = -3600;
192
+				break;
193
+			// -0.5
194
+			case -1800:
195
+				$gmt_offset = 0;
196
+				break;
197
+			// .5
198
+			case 1800:
199
+				$gmt_offset = 3600;
200
+				break;
201
+			// 1.5
202
+			case 5400:
203
+				$gmt_offset = 7200;
204
+				break;
205
+			// 2.5
206
+			case 9000:
207
+				$gmt_offset = 10800;
208
+				break;
209
+			// 3.5
210
+			case 12600:
211
+				$gmt_offset = 14400;
212
+				break;
213
+			// 7.5
214
+			case 27000:
215
+				$gmt_offset = 28800;
216
+				break;
217
+			// 8.5
218
+			case 30600:
219
+				$gmt_offset = 31500;
220
+				break;
221
+			// 10.5
222
+			case 37800:
223
+				$gmt_offset = 39600;
224
+				break;
225
+			// 11.5
226
+			case 41400:
227
+				$gmt_offset = 43200;
228
+				break;
229
+			// 12.75
230
+			case 45900:
231
+				$gmt_offset = 46800;
232
+				break;
233
+			// 13.75
234
+			case 49500:
235
+				$gmt_offset = 50400;
236
+				break;
237
+		}
238
+		return $gmt_offset;
239
+	}
240 240
 }
Please login to merge, or discard this patch.
core/services/helpers/datetime/HelperInterface.php 1 patch
Indentation   +91 added lines, -91 removed lines patch added patch discarded remove patch
@@ -16,95 +16,95 @@
 block discarded – undo
16 16
 interface HelperInterface
17 17
 {
18 18
 
19
-    /**
20
-     * Ensures that a valid timezone string is returned.
21
-     *
22
-     * @param string $timezone_string  When not provided then attempt to use the timezone_string set in the WP Time
23
-     *                                 settings (or derive from set UTC offset).
24
-     * @param bool   $throw_error
25
-     * @return string
26
-     */
27
-    public function getValidTimezoneString($timezone_string = '', $throw_error = false);
28
-
29
-
30
-    /**
31
-     * The only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
32
-     *
33
-     * @param string $timezone_string
34
-     * @param bool   $throw_error
35
-     * @return bool
36
-     */
37
-    public function validateTimezone($timezone_string, $throw_error = true);
38
-
39
-
40
-    /**
41
-     * Returns a timezone string for the provided gmt_offset.
42
-     * @param float|string $gmt_offset
43
-     * @return string
44
-     */
45
-    public function getTimezoneStringFromGmtOffset($gmt_offset = '');
46
-
47
-
48
-    /**
49
-     * Gets the site's GMT offset based on either the timezone string
50
-     * (in which case the gmt offset will vary depending on the location's
51
-     * observance of daylight savings time) or the gmt_offset wp option
52
-     *
53
-     * @return int  seconds offset
54
-     */
55
-    public function getSiteTimezoneGmtOffset();
56
-
57
-
58
-    /**
59
-     * Get timezone transitions
60
-     * @param DateTimeZone $date_time_zone
61
-     * @param int|null     $time
62
-     * @param bool         $first_only
63
-     * @return array
64
-     */
65
-    public function getTimezoneTransitions(DateTimeZone $date_time_zone, $time = null, $first_only = true);
66
-
67
-
68
-    /**
69
-     * Get Timezone offset for given timezone object
70
-     * @param DateTimeZone $date_time_zone
71
-     * @param null|int         $time
72
-     * @return int
73
-     */
74
-    public function getTimezoneOffset(DateTimeZone $date_time_zone, $time = null);
75
-
76
-
77
-    /**
78
-     * Provide a timezone select input
79
-     * @param string $timezone_string
80
-     * @return string
81
-     */
82
-    public function timezoneSelectInput($timezone_string = '');
83
-
84
-
85
-    /**
86
-     * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
87
-     * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
88
-     * the site is used.
89
-     * This is used typically when using a Unix timestamp any core WP functions that expect their specially
90
-     * computed timestamp (i.e. date_i18n() )
91
-     *
92
-     * @param int    $unix_timestamp    if 0, then time() will be used.
93
-     * @param string $timezone_string timezone_string. If empty, then the current set timezone for the
94
-     *                                site will be used.
95
-     * @return int      unix_timestamp value with the offset applied for the given timezone.
96
-     */
97
-    public function getTimestampWithOffset($unix_timestamp = 0, $timezone_string = '');
98
-
99
-
100
-    /**
101
-     * Depending on PHP version,
102
-     * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
103
-     * To get around that, for these fringe timezones we bump them to a known valid offset.
104
-     * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
105
-     *
106
-     * @param int $gmt_offset
107
-     * @return int
108
-     */
109
-    public function adjustInvalidGmtOffsets($gmt_offset);
19
+	/**
20
+	 * Ensures that a valid timezone string is returned.
21
+	 *
22
+	 * @param string $timezone_string  When not provided then attempt to use the timezone_string set in the WP Time
23
+	 *                                 settings (or derive from set UTC offset).
24
+	 * @param bool   $throw_error
25
+	 * @return string
26
+	 */
27
+	public function getValidTimezoneString($timezone_string = '', $throw_error = false);
28
+
29
+
30
+	/**
31
+	 * The only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
32
+	 *
33
+	 * @param string $timezone_string
34
+	 * @param bool   $throw_error
35
+	 * @return bool
36
+	 */
37
+	public function validateTimezone($timezone_string, $throw_error = true);
38
+
39
+
40
+	/**
41
+	 * Returns a timezone string for the provided gmt_offset.
42
+	 * @param float|string $gmt_offset
43
+	 * @return string
44
+	 */
45
+	public function getTimezoneStringFromGmtOffset($gmt_offset = '');
46
+
47
+
48
+	/**
49
+	 * Gets the site's GMT offset based on either the timezone string
50
+	 * (in which case the gmt offset will vary depending on the location's
51
+	 * observance of daylight savings time) or the gmt_offset wp option
52
+	 *
53
+	 * @return int  seconds offset
54
+	 */
55
+	public function getSiteTimezoneGmtOffset();
56
+
57
+
58
+	/**
59
+	 * Get timezone transitions
60
+	 * @param DateTimeZone $date_time_zone
61
+	 * @param int|null     $time
62
+	 * @param bool         $first_only
63
+	 * @return array
64
+	 */
65
+	public function getTimezoneTransitions(DateTimeZone $date_time_zone, $time = null, $first_only = true);
66
+
67
+
68
+	/**
69
+	 * Get Timezone offset for given timezone object
70
+	 * @param DateTimeZone $date_time_zone
71
+	 * @param null|int         $time
72
+	 * @return int
73
+	 */
74
+	public function getTimezoneOffset(DateTimeZone $date_time_zone, $time = null);
75
+
76
+
77
+	/**
78
+	 * Provide a timezone select input
79
+	 * @param string $timezone_string
80
+	 * @return string
81
+	 */
82
+	public function timezoneSelectInput($timezone_string = '');
83
+
84
+
85
+	/**
86
+	 * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
87
+	 * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
88
+	 * the site is used.
89
+	 * This is used typically when using a Unix timestamp any core WP functions that expect their specially
90
+	 * computed timestamp (i.e. date_i18n() )
91
+	 *
92
+	 * @param int    $unix_timestamp    if 0, then time() will be used.
93
+	 * @param string $timezone_string timezone_string. If empty, then the current set timezone for the
94
+	 *                                site will be used.
95
+	 * @return int      unix_timestamp value with the offset applied for the given timezone.
96
+	 */
97
+	public function getTimestampWithOffset($unix_timestamp = 0, $timezone_string = '');
98
+
99
+
100
+	/**
101
+	 * Depending on PHP version,
102
+	 * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
103
+	 * To get around that, for these fringe timezones we bump them to a known valid offset.
104
+	 * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
105
+	 *
106
+	 * @param int $gmt_offset
107
+	 * @return int
108
+	 */
109
+	public function adjustInvalidGmtOffsets($gmt_offset);
110 110
 }
Please login to merge, or discard this patch.
core/services/helpers/datetime/PhpCompatGreaterFiveSixHelper.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -9,92 +9,92 @@
 block discarded – undo
9 9
 
10 10
 class PhpCompatGreaterFiveSixHelper extends AbstractHelper
11 11
 {
12
-    /**
13
-     * PhpCompatLessFiveSixHelper constructor.
14
-     *
15
-     * @throws DomainException
16
-     */
17
-    public function __construct()
18
-    {
19
-        if (PHP_VERSION_ID < 50600) {
20
-            throw new DomainException(
21
-                sprintf(
22
-                    esc_html__(
23
-                        'The %1$s is only usable on php versions greater than 5.6.  You\'ll want to use %2$s instead.',
24
-                        'event_espresso'
25
-                    ),
26
-                    __CLASS__,
27
-                    'EventEspresso\core\services\helpers\datetime\PhpCompatLessFiveSixHelper'
28
-                )
29
-            );
30
-        }
31
-        parent::__construct();
32
-    }
12
+	/**
13
+	 * PhpCompatLessFiveSixHelper constructor.
14
+	 *
15
+	 * @throws DomainException
16
+	 */
17
+	public function __construct()
18
+	{
19
+		if (PHP_VERSION_ID < 50600) {
20
+			throw new DomainException(
21
+				sprintf(
22
+					esc_html__(
23
+						'The %1$s is only usable on php versions greater than 5.6.  You\'ll want to use %2$s instead.',
24
+						'event_espresso'
25
+					),
26
+					__CLASS__,
27
+					'EventEspresso\core\services\helpers\datetime\PhpCompatLessFiveSixHelper'
28
+				)
29
+			);
30
+		}
31
+		parent::__construct();
32
+	}
33 33
 
34
-    /**
35
-     * Returns a timezone string for the provided gmt_offset.
36
-     * This is a valid timezone string that can be sent into DateTimeZone
37
-     *
38
-     * @param float|string $gmt_offset
39
-     * @return string
40
-     */
41
-    public function getTimezoneStringFromGmtOffset($gmt_offset = '')
42
-    {
43
-        $gmt_offset_or_timezone_string = $this->sanitizeInitialIncomingGmtOffsetForGettingTimezoneString($gmt_offset);
44
-        return is_float($gmt_offset_or_timezone_string)
45
-            ? $this->convertWpGmtOffsetForDateTimeZone($gmt_offset_or_timezone_string)
46
-            : $gmt_offset_or_timezone_string;
47
-    }
34
+	/**
35
+	 * Returns a timezone string for the provided gmt_offset.
36
+	 * This is a valid timezone string that can be sent into DateTimeZone
37
+	 *
38
+	 * @param float|string $gmt_offset
39
+	 * @return string
40
+	 */
41
+	public function getTimezoneStringFromGmtOffset($gmt_offset = '')
42
+	{
43
+		$gmt_offset_or_timezone_string = $this->sanitizeInitialIncomingGmtOffsetForGettingTimezoneString($gmt_offset);
44
+		return is_float($gmt_offset_or_timezone_string)
45
+			? $this->convertWpGmtOffsetForDateTimeZone($gmt_offset_or_timezone_string)
46
+			: $gmt_offset_or_timezone_string;
47
+	}
48 48
 
49 49
 
50 50
 
51
-    /**
52
-     * Returns a formatted offset for use as an argument for constructing DateTimeZone
53
-     * @param float $gmt_offset This should be a float representing the gmt_offset.
54
-     * @return string
55
-     */
56
-    protected function convertWpGmtOffsetForDateTimeZone($gmt_offset)
57
-    {
58
-        $gmt_offset = (float) $gmt_offset;
59
-        $is_negative = $gmt_offset < 0;
60
-        $gmt_offset *= 100;
61
-        $gmt_offset = absint($gmt_offset);
62
-        // negative and need zero padding?
63
-        if (strlen($gmt_offset) < 4) {
64
-            $gmt_offset = str_pad($gmt_offset, 4, '0', STR_PAD_LEFT);
65
-        }
66
-        $gmt_offset = $this->convertToTimeFraction($gmt_offset);
67
-        // return something like -1300, -0200 or +1300, +0200
68
-        return $is_negative ? '-' . $gmt_offset : '+' . $gmt_offset;
69
-    }
51
+	/**
52
+	 * Returns a formatted offset for use as an argument for constructing DateTimeZone
53
+	 * @param float $gmt_offset This should be a float representing the gmt_offset.
54
+	 * @return string
55
+	 */
56
+	protected function convertWpGmtOffsetForDateTimeZone($gmt_offset)
57
+	{
58
+		$gmt_offset = (float) $gmt_offset;
59
+		$is_negative = $gmt_offset < 0;
60
+		$gmt_offset *= 100;
61
+		$gmt_offset = absint($gmt_offset);
62
+		// negative and need zero padding?
63
+		if (strlen($gmt_offset) < 4) {
64
+			$gmt_offset = str_pad($gmt_offset, 4, '0', STR_PAD_LEFT);
65
+		}
66
+		$gmt_offset = $this->convertToTimeFraction($gmt_offset);
67
+		// return something like -1300, -0200 or +1300, +0200
68
+		return $is_negative ? '-' . $gmt_offset : '+' . $gmt_offset;
69
+	}
70 70
 
71 71
 
72
-    /**
73
-     * Converts something like `1550` to `1530` or `0275` to `0245`
74
-     * Incoming offset should be a positive value, this will mutate negative values. Be aware!
75
-     * @param int $offset
76
-     * @return mixed
77
-     */
78
-    protected function convertToTimeFraction($offset)
79
-    {
80
-        $first_part = substr($offset, 0, 2);
81
-        $second_part = substr($offset, 2, 2);
82
-        $second_part = str_replace(array('25', '50', '75'), array('15', '30', '45'), $second_part);
83
-        return $first_part . $second_part;
84
-    }
72
+	/**
73
+	 * Converts something like `1550` to `1530` or `0275` to `0245`
74
+	 * Incoming offset should be a positive value, this will mutate negative values. Be aware!
75
+	 * @param int $offset
76
+	 * @return mixed
77
+	 */
78
+	protected function convertToTimeFraction($offset)
79
+	{
80
+		$first_part = substr($offset, 0, 2);
81
+		$second_part = substr($offset, 2, 2);
82
+		$second_part = str_replace(array('25', '50', '75'), array('15', '30', '45'), $second_part);
83
+		return $first_part . $second_part;
84
+	}
85 85
 
86 86
 
87
-    /**
88
-     * Get Timezone offset for given timezone object
89
-     *
90
-     * @param DateTimeZone $date_time_zone
91
-     * @param null|int     $time
92
-     * @return int
93
-     */
94
-    public function getTimezoneOffset(DateTimezone $date_time_zone, $time = null)
95
-    {
96
-        $time = is_int($time) || $time === null ? $time : (int) strtotime($time);
97
-        $time = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
98
-        return $date_time_zone->getOffset(new DateTime('@' . $time));
99
-    }
87
+	/**
88
+	 * Get Timezone offset for given timezone object
89
+	 *
90
+	 * @param DateTimeZone $date_time_zone
91
+	 * @param null|int     $time
92
+	 * @return int
93
+	 */
94
+	public function getTimezoneOffset(DateTimezone $date_time_zone, $time = null)
95
+	{
96
+		$time = is_int($time) || $time === null ? $time : (int) strtotime($time);
97
+		$time = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
98
+		return $date_time_zone->getOffset(new DateTime('@' . $time));
99
+	}
100 100
 }
Please login to merge, or discard this patch.
core/services/helpers/datetime/AbstractHelper.php 2 patches
Indentation   +323 added lines, -323 removed lines patch added patch discarded remove patch
@@ -11,195 +11,195 @@  discard block
 block discarded – undo
11 11
 
12 12
 abstract class AbstractHelper implements HelperInterface
13 13
 {
14
-    /**
15
-     * @var string
16
-     */
17
-    private $default_timezone_string = '';
18
-
19
-
20
-    /**
21
-     * AbstractHelper constructor.
22
-     */
23
-    public function __construct()
24
-    {
25
-        add_action('update_option_timezone_string', [$this, 'updateDefaultTimezoneString'], 10, 2);
26
-    }
27
-    /**
28
-     * AbstractHelper destructor.
29
-     */
30
-    public function __destruct()
31
-    {
32
-        remove_action('update_option_timezone_string', [$this, 'updateDefaultTimezoneString']);
33
-    }
34
-
35
-
36
-
37
-
38
-    /**
39
-     * Ensures that a valid timezone string is returned.
40
-     *
41
-     * @param string $timezone_string  When not provided then attempt to use the timezone_string set in the WP Time
42
-     *                                 settings (or derive from set UTC offset).
43
-     * @param bool   $throw_error
44
-     * @return string
45
-     * @throws EE_Error
46
-     */
47
-    public function getValidTimezoneString($timezone_string = '', $throw_error = false)
48
-    {
49
-        // if a valid TZ is supplied, then just use that, but don't throw errors if it's invalid
50
-        if (! empty($timezone_string) && $this->validateTimezone($timezone_string, $throw_error)) {
51
-            return $timezone_string;
52
-        }
53
-        // cache whatever gets set as the site default
54
-        // no default set yet? then let's get to it!
55
-        if ($this->default_timezone_string === '') {
56
-            // ignore the incoming TZ string because we already know it's invalid
57
-            // and just pull the default set for the site
58
-            $timezone_string = (string) get_option('timezone_string');
59
-            // if the site admin has not set a valid default,
60
-            // then derive the TZ from the UTC offset (and hope that that is set)
61
-            $timezone_string = ! empty($timezone_string)
62
-                ? $timezone_string
63
-                : $this->getTimezoneStringFromGmtOffset();
64
-            // make sure it's all good (and this time blow things up if no TZ can be determined)
65
-            $this->validateTimezone($timezone_string);
66
-            // cache the default so that we don't do this a Brazilian times
67
-            $this->default_timezone_string = $timezone_string;
68
-        }
69
-        return $this->default_timezone_string;
70
-    }
71
-
72
-
73
-    public function resetDefaultTimezoneString()
74
-    {
75
-        $this->default_timezone_string = '';
76
-    }
77
-
78
-
79
-    /**
80
-     * @param $old_value
81
-     * @param $value
82
-     * @throws EE_Error
83
-     * @since   $VID:$
84
-     */
85
-    public function updateDefaultTimezoneString($old_value, $value)
86
-    {
87
-        if ($value && $value !== $old_value && $value !== $this->default_timezone_string) {
88
-            $this->resetDefaultTimezoneString();
89
-            $this->getValidTimezoneString($value);
90
-        }
91
-    }
92
-
93
-    /**
94
-     * The only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
95
-     *
96
-     * @param string $timezone_string
97
-     * @param bool   $throw_error
98
-     * @return bool
99
-     * @throws EE_Error
100
-     */
101
-    public function validateTimezone($timezone_string, $throw_error = true)
102
-    {
103
-        // easiest way to test a timezone string is just see if it throws an error when you try to create a
104
-        // DateTimeZone object with it
105
-        try {
106
-            new DateTimeZone($timezone_string);
107
-        } catch (Exception $e) {
108
-            // sometimes we take exception to exceptions
109
-            if (! $throw_error) {
110
-                return false;
111
-            }
112
-            throw new EE_Error(
113
-                sprintf(
114
-                    esc_html__(
115
-                        'The timezone given (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
116
-                        'event_espresso'
117
-                    ),
118
-                    $timezone_string,
119
-                    '<a href="http://www.php.net/manual/en/timezones.php">',
120
-                    '</a>'
121
-                )
122
-            );
123
-        }
124
-        return true;
125
-    }
126
-
127
-
128
-    /**
129
-     * Gets the site's GMT offset based on either the timezone string
130
-     * (in which case the gmt offset will vary depending on the location's
131
-     * observance of daylight savings time) or the gmt_offset wp option
132
-     *
133
-     * @return int  seconds offset
134
-     */
135
-    public function getSiteTimezoneGmtOffset()
136
-    {
137
-        $timezone_string = (string) get_option('timezone_string');
138
-        if ($timezone_string) {
139
-            try {
140
-                $timezone = new DateTimeZone($timezone_string);
141
-                return $timezone->getOffset(new DateTime()); // in WordPress DateTime defaults to UTC
142
-            } catch (Exception $e) {
143
-            }
144
-        }
145
-        $offset = get_option('gmt_offset');
146
-        return (int) ($offset * HOUR_IN_SECONDS);
147
-    }
148
-
149
-
150
-    /**
151
-     * Get Timezone offset for given timezone object
152
-     *
153
-     * @param DateTimeZone $date_time_zone
154
-     * @param null|int     $time
155
-     * @return int
156
-     * @throws DomainException
157
-     */
158
-    public function getTimezoneOffset(DateTimeZone $date_time_zone, $time = null)
159
-    {
160
-        $transition = $this->getTimezoneTransitions($date_time_zone, $time);
161
-        if (! isset($transition['offset'])) {
162
-            throw new DomainException(
163
-                sprintf(
164
-                    esc_html__('An invalid timezone transition was received %1$s', 'event_espresso'),
165
-                    print_r($transition, true)
166
-                )
167
-            );
168
-        }
169
-        return $transition['offset'];
170
-    }
171
-
172
-
173
-    /**
174
-     * Provide a timezone select input
175
-     *
176
-     * @param string $timezone_string
177
-     * @return string
178
-     * @throws EE_Error
179
-     */
180
-    public function timezoneSelectInput($timezone_string = '')
181
-    {
182
-        // get WP date time format
183
-        $datetime_format = get_option('date_format') . ' ' . get_option('time_format');
184
-        // if passed a value, then use that, else get WP option
185
-        $timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
186
-        // check if the timezone is valid but don't throw any errors if it isn't
187
-        $timezone_string = $this->validateTimezone($timezone_string, false)
188
-            ? $timezone_string
189
-            : '';
190
-        $gmt_offset      = get_option('gmt_offset');
191
-        $check_zone_info = true;
192
-        if (empty($timezone_string)) {
193
-            // Create a UTC+- zone if no timezone string exists
194
-            $timezone_string = 'UTC';
195
-            $check_zone_info = false;
196
-            if ($gmt_offset > 0) {
197
-                $timezone_string = 'UTC+' . $gmt_offset;
198
-            } elseif ($gmt_offset < 0) {
199
-                $timezone_string = 'UTC' . $gmt_offset;
200
-            }
201
-        }
202
-        ?>
14
+	/**
15
+	 * @var string
16
+	 */
17
+	private $default_timezone_string = '';
18
+
19
+
20
+	/**
21
+	 * AbstractHelper constructor.
22
+	 */
23
+	public function __construct()
24
+	{
25
+		add_action('update_option_timezone_string', [$this, 'updateDefaultTimezoneString'], 10, 2);
26
+	}
27
+	/**
28
+	 * AbstractHelper destructor.
29
+	 */
30
+	public function __destruct()
31
+	{
32
+		remove_action('update_option_timezone_string', [$this, 'updateDefaultTimezoneString']);
33
+	}
34
+
35
+
36
+
37
+
38
+	/**
39
+	 * Ensures that a valid timezone string is returned.
40
+	 *
41
+	 * @param string $timezone_string  When not provided then attempt to use the timezone_string set in the WP Time
42
+	 *                                 settings (or derive from set UTC offset).
43
+	 * @param bool   $throw_error
44
+	 * @return string
45
+	 * @throws EE_Error
46
+	 */
47
+	public function getValidTimezoneString($timezone_string = '', $throw_error = false)
48
+	{
49
+		// if a valid TZ is supplied, then just use that, but don't throw errors if it's invalid
50
+		if (! empty($timezone_string) && $this->validateTimezone($timezone_string, $throw_error)) {
51
+			return $timezone_string;
52
+		}
53
+		// cache whatever gets set as the site default
54
+		// no default set yet? then let's get to it!
55
+		if ($this->default_timezone_string === '') {
56
+			// ignore the incoming TZ string because we already know it's invalid
57
+			// and just pull the default set for the site
58
+			$timezone_string = (string) get_option('timezone_string');
59
+			// if the site admin has not set a valid default,
60
+			// then derive the TZ from the UTC offset (and hope that that is set)
61
+			$timezone_string = ! empty($timezone_string)
62
+				? $timezone_string
63
+				: $this->getTimezoneStringFromGmtOffset();
64
+			// make sure it's all good (and this time blow things up if no TZ can be determined)
65
+			$this->validateTimezone($timezone_string);
66
+			// cache the default so that we don't do this a Brazilian times
67
+			$this->default_timezone_string = $timezone_string;
68
+		}
69
+		return $this->default_timezone_string;
70
+	}
71
+
72
+
73
+	public function resetDefaultTimezoneString()
74
+	{
75
+		$this->default_timezone_string = '';
76
+	}
77
+
78
+
79
+	/**
80
+	 * @param $old_value
81
+	 * @param $value
82
+	 * @throws EE_Error
83
+	 * @since   $VID:$
84
+	 */
85
+	public function updateDefaultTimezoneString($old_value, $value)
86
+	{
87
+		if ($value && $value !== $old_value && $value !== $this->default_timezone_string) {
88
+			$this->resetDefaultTimezoneString();
89
+			$this->getValidTimezoneString($value);
90
+		}
91
+	}
92
+
93
+	/**
94
+	 * The only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
95
+	 *
96
+	 * @param string $timezone_string
97
+	 * @param bool   $throw_error
98
+	 * @return bool
99
+	 * @throws EE_Error
100
+	 */
101
+	public function validateTimezone($timezone_string, $throw_error = true)
102
+	{
103
+		// easiest way to test a timezone string is just see if it throws an error when you try to create a
104
+		// DateTimeZone object with it
105
+		try {
106
+			new DateTimeZone($timezone_string);
107
+		} catch (Exception $e) {
108
+			// sometimes we take exception to exceptions
109
+			if (! $throw_error) {
110
+				return false;
111
+			}
112
+			throw new EE_Error(
113
+				sprintf(
114
+					esc_html__(
115
+						'The timezone given (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
116
+						'event_espresso'
117
+					),
118
+					$timezone_string,
119
+					'<a href="http://www.php.net/manual/en/timezones.php">',
120
+					'</a>'
121
+				)
122
+			);
123
+		}
124
+		return true;
125
+	}
126
+
127
+
128
+	/**
129
+	 * Gets the site's GMT offset based on either the timezone string
130
+	 * (in which case the gmt offset will vary depending on the location's
131
+	 * observance of daylight savings time) or the gmt_offset wp option
132
+	 *
133
+	 * @return int  seconds offset
134
+	 */
135
+	public function getSiteTimezoneGmtOffset()
136
+	{
137
+		$timezone_string = (string) get_option('timezone_string');
138
+		if ($timezone_string) {
139
+			try {
140
+				$timezone = new DateTimeZone($timezone_string);
141
+				return $timezone->getOffset(new DateTime()); // in WordPress DateTime defaults to UTC
142
+			} catch (Exception $e) {
143
+			}
144
+		}
145
+		$offset = get_option('gmt_offset');
146
+		return (int) ($offset * HOUR_IN_SECONDS);
147
+	}
148
+
149
+
150
+	/**
151
+	 * Get Timezone offset for given timezone object
152
+	 *
153
+	 * @param DateTimeZone $date_time_zone
154
+	 * @param null|int     $time
155
+	 * @return int
156
+	 * @throws DomainException
157
+	 */
158
+	public function getTimezoneOffset(DateTimeZone $date_time_zone, $time = null)
159
+	{
160
+		$transition = $this->getTimezoneTransitions($date_time_zone, $time);
161
+		if (! isset($transition['offset'])) {
162
+			throw new DomainException(
163
+				sprintf(
164
+					esc_html__('An invalid timezone transition was received %1$s', 'event_espresso'),
165
+					print_r($transition, true)
166
+				)
167
+			);
168
+		}
169
+		return $transition['offset'];
170
+	}
171
+
172
+
173
+	/**
174
+	 * Provide a timezone select input
175
+	 *
176
+	 * @param string $timezone_string
177
+	 * @return string
178
+	 * @throws EE_Error
179
+	 */
180
+	public function timezoneSelectInput($timezone_string = '')
181
+	{
182
+		// get WP date time format
183
+		$datetime_format = get_option('date_format') . ' ' . get_option('time_format');
184
+		// if passed a value, then use that, else get WP option
185
+		$timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
186
+		// check if the timezone is valid but don't throw any errors if it isn't
187
+		$timezone_string = $this->validateTimezone($timezone_string, false)
188
+			? $timezone_string
189
+			: '';
190
+		$gmt_offset      = get_option('gmt_offset');
191
+		$check_zone_info = true;
192
+		if (empty($timezone_string)) {
193
+			// Create a UTC+- zone if no timezone string exists
194
+			$timezone_string = 'UTC';
195
+			$check_zone_info = false;
196
+			if ($gmt_offset > 0) {
197
+				$timezone_string = 'UTC+' . $gmt_offset;
198
+			} elseif ($gmt_offset < 0) {
199
+				$timezone_string = 'UTC' . $gmt_offset;
200
+			}
201
+		}
202
+		?>
203 203
         <p>
204 204
             <label for="timezone_string"><?php _e('timezone', 'event_espresso'); ?></label>
205 205
             <select id="timezone_string" name="timezone_string">
@@ -212,150 +212,150 @@  discard block
 block discarded – undo
212 212
         <p>
213 213
         <span>
214 214
             <?php
215
-            printf(
216
-                __('%1$sUTC%2$s time is %3$s', 'event_espresso'),
217
-                '<abbr title="Coordinated Universal Time">',
218
-                '</abbr>',
219
-                '<code>' . date_i18n($datetime_format, false, true) . '</code>'
220
-            );
221
-            ?></span>
215
+			printf(
216
+				__('%1$sUTC%2$s time is %3$s', 'event_espresso'),
217
+				'<abbr title="Coordinated Universal Time">',
218
+				'</abbr>',
219
+				'<code>' . date_i18n($datetime_format, false, true) . '</code>'
220
+			);
221
+			?></span>
222 222
         <?php
223
-        if (! empty($timezone_string) || ! empty($gmt_offset)) : ?>
223
+		if (! empty($timezone_string) || ! empty($gmt_offset)) : ?>
224 224
         <br/><span><?php printf(__('Local time is %1$s', 'event_espresso'), '<code>' . date_i18n($datetime_format) . '</code>'); ?></span>
225 225
             <?php
226
-        endif; ?>
226
+		endif; ?>
227 227
 
228 228
         <?php
229
-        if ($check_zone_info && $timezone_string) : ?>
229
+		if ($check_zone_info && $timezone_string) : ?>
230 230
         <br/>
231 231
         <span>
232 232
                 <?php
233
-                // Set TZ so localtime works.
234
-                date_default_timezone_set($timezone_string);
235
-                $now = localtime(time(), true);
236
-                if ($now['tm_isdst']) {
237
-                    _e('This timezone is currently in daylight saving time.', 'event_espresso');
238
-                } else {
239
-                    _e('This timezone is currently in standard time.', 'event_espresso');
240
-                }
241
-                ?>
233
+				// Set TZ so localtime works.
234
+				date_default_timezone_set($timezone_string);
235
+				$now = localtime(time(), true);
236
+				if ($now['tm_isdst']) {
237
+					_e('This timezone is currently in daylight saving time.', 'event_espresso');
238
+				} else {
239
+					_e('This timezone is currently in standard time.', 'event_espresso');
240
+				}
241
+				?>
242 242
             <br/>
243 243
             <?php
244
-            if (function_exists('timezone_transitions_get')) {
245
-                $found                   = false;
246
-                $date_time_zone_selected = new DateTimeZone($timezone_string);
247
-                $tz_offset               = timezone_offset_get($date_time_zone_selected, date_create());
248
-                $right_now               = time();
249
-                $tr['isdst']             = false;
250
-                foreach (timezone_transitions_get($date_time_zone_selected) as $tr) {
251
-                    if ($tr['ts'] > $right_now) {
252
-                        $found = true;
253
-                        break;
254
-                    }
255
-                }
256
-                if ($found) {
257
-                    $message = $tr['isdst']
258
-                        ? __(' Daylight saving time begins on: %s.', 'event_espresso')
259
-                        : __(' Standard time begins  on: %s.', 'event_espresso');
260
-                    // Add the difference between the current offset and the new offset to ts to get the correct
261
-                    // transition time from date_i18n().
262
-                    printf(
263
-                        $message,
264
-                        '<code >' . date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])) . '</code >'
265
-                    );
266
-                } else {
267
-                    _e('This timezone does not observe daylight saving time.', 'event_espresso');
268
-                }
269
-            }
270
-            // Set back to UTC.
271
-            date_default_timezone_set('UTC');
272
-            ?>
244
+			if (function_exists('timezone_transitions_get')) {
245
+				$found                   = false;
246
+				$date_time_zone_selected = new DateTimeZone($timezone_string);
247
+				$tz_offset               = timezone_offset_get($date_time_zone_selected, date_create());
248
+				$right_now               = time();
249
+				$tr['isdst']             = false;
250
+				foreach (timezone_transitions_get($date_time_zone_selected) as $tr) {
251
+					if ($tr['ts'] > $right_now) {
252
+						$found = true;
253
+						break;
254
+					}
255
+				}
256
+				if ($found) {
257
+					$message = $tr['isdst']
258
+						? __(' Daylight saving time begins on: %s.', 'event_espresso')
259
+						: __(' Standard time begins  on: %s.', 'event_espresso');
260
+					// Add the difference between the current offset and the new offset to ts to get the correct
261
+					// transition time from date_i18n().
262
+					printf(
263
+						$message,
264
+						'<code >' . date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])) . '</code >'
265
+					);
266
+				} else {
267
+					_e('This timezone does not observe daylight saving time.', 'event_espresso');
268
+				}
269
+			}
270
+			// Set back to UTC.
271
+			date_default_timezone_set('UTC');
272
+			?>
273 273
         </span></p>
274 274
             <?php
275
-        endif;
276
-    }
277
-
278
-
279
-    /**
280
-     * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
281
-     * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
282
-     * the site is used.
283
-     * This is used typically when using a Unix timestamp any core WP functions that expect their specially
284
-     * computed timestamp (i.e. date_i18n() )
285
-     *
286
-     * @param int    $unix_timestamp  if 0, then time() will be used.
287
-     * @param string $timezone_string timezone_string. If empty, then the current set timezone for the
288
-     *                                site will be used.
289
-     * @return int      unix_timestamp value with the offset applied for the given timezone.
290
-     * @throws EE_Error
291
-     */
292
-    public function getTimestampWithOffset($unix_timestamp = 0, $timezone_string = '')
293
-    {
294
-        $unix_timestamp  = $unix_timestamp === 0 ? time() : (int) $unix_timestamp;
295
-        $timezone_string = $this->getValidTimezoneString($timezone_string);
296
-        $TimeZone        = new DateTimeZone($timezone_string);
297
-        $DateTime        = new DateTime('@' . $unix_timestamp, $TimeZone);
298
-        $offset          = timezone_offset_get($TimeZone, $DateTime);
299
-        return (int) $DateTime->format('U') + (int) $offset;
300
-    }
301
-
302
-
303
-    /**
304
-     * Get Timezone Transitions
305
-     *
306
-     * @param DateTimeZone $date_time_zone
307
-     * @param int|null     $time
308
-     * @param bool         $first_only
309
-     * @return array|mixed
310
-     */
311
-    public function getTimezoneTransitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
312
-    {
313
-        $time        = is_int($time) || $time === null ? $time : (int) strtotime($time);
314
-        $time        = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
315
-        $transitions = $date_time_zone->getTransitions($time);
316
-        return $first_only && ! isset($transitions['ts']) ? reset($transitions) : $transitions;
317
-    }
318
-
319
-
320
-
321
-    /**
322
-     * Default to just returning the provided $gmt_offset.  Children can override if adjustment needed.
323
-     *
324
-     * @param int $gmt_offset
325
-     * @return int
326
-     */
327
-    public function adjustInvalidGmtOffsets($gmt_offset = 0)
328
-    {
329
-        return $gmt_offset;
330
-    }
331
-
332
-
333
-
334
-    /**
335
-     * This receives an incoming gmt_offset and santizes it.  If the provide value is an empty string, then this will
336
-     * attempt to get the offset from the timezone string.  If this returns a string, then a timezone string was
337
-     * successfully derived from existing timezone_string in the db.  If not, then a float is returned for the provided
338
-     * offset.
339
-     * @param  float|string $gmt_offset
340
-     * @return float|string
341
-     */
342
-    protected function sanitizeInitialIncomingGmtOffsetForGettingTimezoneString($gmt_offset)
343
-    {
344
-        // if there is no incoming gmt_offset, then because WP hooks in on timezone_string, we need to see if that is
345
-        // set because it will override `gmt_offset` via `pre_get_option` filter.  If that's set, then let's just use
346
-        // that!  Otherwise we'll leave timezone_string at the default of 'UTC' before doing other logic.
347
-        if ($gmt_offset === '') {
348
-            // autoloaded so no need to set to a variable.  There will not be multiple hits to the db.
349
-            if (get_option('timezone_string')) {
350
-                return (string) get_option('timezone_string');
351
-            }
352
-        }
353
-        $gmt_offset = $gmt_offset !== '' ? $gmt_offset : (string) get_option('gmt_offset');
354
-        $gmt_offset = (float) $gmt_offset;
355
-        // if $gmt_offset is 0 or is still an empty string, then just return UTC
356
-        if ($gmt_offset === (float) 0) {
357
-            return 'UTC';
358
-        }
359
-        return $gmt_offset;
360
-    }
275
+		endif;
276
+	}
277
+
278
+
279
+	/**
280
+	 * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
281
+	 * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
282
+	 * the site is used.
283
+	 * This is used typically when using a Unix timestamp any core WP functions that expect their specially
284
+	 * computed timestamp (i.e. date_i18n() )
285
+	 *
286
+	 * @param int    $unix_timestamp  if 0, then time() will be used.
287
+	 * @param string $timezone_string timezone_string. If empty, then the current set timezone for the
288
+	 *                                site will be used.
289
+	 * @return int      unix_timestamp value with the offset applied for the given timezone.
290
+	 * @throws EE_Error
291
+	 */
292
+	public function getTimestampWithOffset($unix_timestamp = 0, $timezone_string = '')
293
+	{
294
+		$unix_timestamp  = $unix_timestamp === 0 ? time() : (int) $unix_timestamp;
295
+		$timezone_string = $this->getValidTimezoneString($timezone_string);
296
+		$TimeZone        = new DateTimeZone($timezone_string);
297
+		$DateTime        = new DateTime('@' . $unix_timestamp, $TimeZone);
298
+		$offset          = timezone_offset_get($TimeZone, $DateTime);
299
+		return (int) $DateTime->format('U') + (int) $offset;
300
+	}
301
+
302
+
303
+	/**
304
+	 * Get Timezone Transitions
305
+	 *
306
+	 * @param DateTimeZone $date_time_zone
307
+	 * @param int|null     $time
308
+	 * @param bool         $first_only
309
+	 * @return array|mixed
310
+	 */
311
+	public function getTimezoneTransitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
312
+	{
313
+		$time        = is_int($time) || $time === null ? $time : (int) strtotime($time);
314
+		$time        = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
315
+		$transitions = $date_time_zone->getTransitions($time);
316
+		return $first_only && ! isset($transitions['ts']) ? reset($transitions) : $transitions;
317
+	}
318
+
319
+
320
+
321
+	/**
322
+	 * Default to just returning the provided $gmt_offset.  Children can override if adjustment needed.
323
+	 *
324
+	 * @param int $gmt_offset
325
+	 * @return int
326
+	 */
327
+	public function adjustInvalidGmtOffsets($gmt_offset = 0)
328
+	{
329
+		return $gmt_offset;
330
+	}
331
+
332
+
333
+
334
+	/**
335
+	 * This receives an incoming gmt_offset and santizes it.  If the provide value is an empty string, then this will
336
+	 * attempt to get the offset from the timezone string.  If this returns a string, then a timezone string was
337
+	 * successfully derived from existing timezone_string in the db.  If not, then a float is returned for the provided
338
+	 * offset.
339
+	 * @param  float|string $gmt_offset
340
+	 * @return float|string
341
+	 */
342
+	protected function sanitizeInitialIncomingGmtOffsetForGettingTimezoneString($gmt_offset)
343
+	{
344
+		// if there is no incoming gmt_offset, then because WP hooks in on timezone_string, we need to see if that is
345
+		// set because it will override `gmt_offset` via `pre_get_option` filter.  If that's set, then let's just use
346
+		// that!  Otherwise we'll leave timezone_string at the default of 'UTC' before doing other logic.
347
+		if ($gmt_offset === '') {
348
+			// autoloaded so no need to set to a variable.  There will not be multiple hits to the db.
349
+			if (get_option('timezone_string')) {
350
+				return (string) get_option('timezone_string');
351
+			}
352
+		}
353
+		$gmt_offset = $gmt_offset !== '' ? $gmt_offset : (string) get_option('gmt_offset');
354
+		$gmt_offset = (float) $gmt_offset;
355
+		// if $gmt_offset is 0 or is still an empty string, then just return UTC
356
+		if ($gmt_offset === (float) 0) {
357
+			return 'UTC';
358
+		}
359
+		return $gmt_offset;
360
+	}
361 361
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -47,7 +47,7 @@  discard block
 block discarded – undo
47 47
     public function getValidTimezoneString($timezone_string = '', $throw_error = false)
48 48
     {
49 49
         // if a valid TZ is supplied, then just use that, but don't throw errors if it's invalid
50
-        if (! empty($timezone_string) && $this->validateTimezone($timezone_string, $throw_error)) {
50
+        if ( ! empty($timezone_string) && $this->validateTimezone($timezone_string, $throw_error)) {
51 51
             return $timezone_string;
52 52
         }
53 53
         // cache whatever gets set as the site default
@@ -106,7 +106,7 @@  discard block
 block discarded – undo
106 106
             new DateTimeZone($timezone_string);
107 107
         } catch (Exception $e) {
108 108
             // sometimes we take exception to exceptions
109
-            if (! $throw_error) {
109
+            if ( ! $throw_error) {
110 110
                 return false;
111 111
             }
112 112
             throw new EE_Error(
@@ -158,7 +158,7 @@  discard block
 block discarded – undo
158 158
     public function getTimezoneOffset(DateTimeZone $date_time_zone, $time = null)
159 159
     {
160 160
         $transition = $this->getTimezoneTransitions($date_time_zone, $time);
161
-        if (! isset($transition['offset'])) {
161
+        if ( ! isset($transition['offset'])) {
162 162
             throw new DomainException(
163 163
                 sprintf(
164 164
                     esc_html__('An invalid timezone transition was received %1$s', 'event_espresso'),
@@ -180,7 +180,7 @@  discard block
 block discarded – undo
180 180
     public function timezoneSelectInput($timezone_string = '')
181 181
     {
182 182
         // get WP date time format
183
-        $datetime_format = get_option('date_format') . ' ' . get_option('time_format');
183
+        $datetime_format = get_option('date_format').' '.get_option('time_format');
184 184
         // if passed a value, then use that, else get WP option
185 185
         $timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
186 186
         // check if the timezone is valid but don't throw any errors if it isn't
@@ -194,9 +194,9 @@  discard block
 block discarded – undo
194 194
             $timezone_string = 'UTC';
195 195
             $check_zone_info = false;
196 196
             if ($gmt_offset > 0) {
197
-                $timezone_string = 'UTC+' . $gmt_offset;
197
+                $timezone_string = 'UTC+'.$gmt_offset;
198 198
             } elseif ($gmt_offset < 0) {
199
-                $timezone_string = 'UTC' . $gmt_offset;
199
+                $timezone_string = 'UTC'.$gmt_offset;
200 200
             }
201 201
         }
202 202
         ?>
@@ -216,12 +216,12 @@  discard block
 block discarded – undo
216 216
                 __('%1$sUTC%2$s time is %3$s', 'event_espresso'),
217 217
                 '<abbr title="Coordinated Universal Time">',
218 218
                 '</abbr>',
219
-                '<code>' . date_i18n($datetime_format, false, true) . '</code>'
219
+                '<code>'.date_i18n($datetime_format, false, true).'</code>'
220 220
             );
221 221
             ?></span>
222 222
         <?php
223
-        if (! empty($timezone_string) || ! empty($gmt_offset)) : ?>
224
-        <br/><span><?php printf(__('Local time is %1$s', 'event_espresso'), '<code>' . date_i18n($datetime_format) . '</code>'); ?></span>
223
+        if ( ! empty($timezone_string) || ! empty($gmt_offset)) : ?>
224
+        <br/><span><?php printf(__('Local time is %1$s', 'event_espresso'), '<code>'.date_i18n($datetime_format).'</code>'); ?></span>
225 225
             <?php
226 226
         endif; ?>
227 227
 
@@ -261,7 +261,7 @@  discard block
 block discarded – undo
261 261
                     // transition time from date_i18n().
262 262
                     printf(
263 263
                         $message,
264
-                        '<code >' . date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])) . '</code >'
264
+                        '<code >'.date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])).'</code >'
265 265
                     );
266 266
                 } else {
267 267
                     _e('This timezone does not observe daylight saving time.', 'event_espresso');
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
         $unix_timestamp  = $unix_timestamp === 0 ? time() : (int) $unix_timestamp;
295 295
         $timezone_string = $this->getValidTimezoneString($timezone_string);
296 296
         $TimeZone        = new DateTimeZone($timezone_string);
297
-        $DateTime        = new DateTime('@' . $unix_timestamp, $TimeZone);
297
+        $DateTime        = new DateTime('@'.$unix_timestamp, $TimeZone);
298 298
         $offset          = timezone_offset_get($TimeZone, $DateTime);
299 299
         return (int) $DateTime->format('U') + (int) $offset;
300 300
     }
Please login to merge, or discard this patch.
core/EE_Registry.core.php 1 patch
Indentation   +1696 added lines, -1696 removed lines patch added patch discarded remove patch
@@ -23,1704 +23,1704 @@
 block discarded – undo
23 23
 class EE_Registry implements ResettableInterface
24 24
 {
25 25
 
26
-    /**
27
-     * @var EE_Registry $_instance
28
-     */
29
-    private static $_instance;
30
-
31
-    /**
32
-     * @var EE_Dependency_Map $_dependency_map
33
-     */
34
-    protected $_dependency_map;
35
-
36
-    /**
37
-     * @var Mirror
38
-     */
39
-    private $mirror;
40
-
41
-    /**
42
-     * @var ClassInterfaceCache $class_cache
43
-     */
44
-    private $class_cache;
45
-
46
-    /**
47
-     * @var array $_class_abbreviations
48
-     */
49
-    protected $_class_abbreviations = array();
50
-
51
-    /**
52
-     * @var CommandBusInterface $BUS
53
-     */
54
-    public $BUS;
55
-
56
-    /**
57
-     * @var EE_Cart $CART
58
-     */
59
-    public $CART;
60
-
61
-    /**
62
-     * @var EE_Config $CFG
63
-     */
64
-    public $CFG;
65
-
66
-    /**
67
-     * @var EE_Network_Config $NET_CFG
68
-     */
69
-    public $NET_CFG;
70
-
71
-    /**
72
-     * StdClass object for storing library classes in
73
-     *
74
-     * @var RegistryContainer $LIB
75
-     */
76
-    public $LIB;
77
-
78
-    /**
79
-     * @var EE_Request_Handler $REQ
80
-     */
81
-    public $REQ;
82
-
83
-    /**
84
-     * @var EE_Session $SSN
85
-     */
86
-    public $SSN;
87
-
88
-    /**
89
-     * @since 4.5.0
90
-     * @var EE_Capabilities $CAP
91
-     */
92
-    public $CAP;
93
-
94
-    /**
95
-     * @since 4.9.0
96
-     * @var EE_Message_Resource_Manager $MRM
97
-     */
98
-    public $MRM;
99
-
100
-    /**
101
-     * @var Registry $AssetsRegistry
102
-     */
103
-    public $AssetsRegistry;
104
-
105
-    /**
106
-     * StdClass object for holding addons which have registered themselves to work with EE core
107
-     *
108
-     * @var EE_Addon[] $addons
109
-     */
110
-    public $addons;
111
-
112
-    /**
113
-     * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
114
-     *
115
-     * @var EEM_Base[] $models
116
-     */
117
-    public $models = array();
118
-
119
-    /**
120
-     * @var EED_Module[] $modules
121
-     */
122
-    public $modules;
123
-
124
-    /**
125
-     * @var EES_Shortcode[] $shortcodes
126
-     */
127
-    public $shortcodes;
128
-
129
-    /**
130
-     * @var WP_Widget[] $widgets
131
-     */
132
-    public $widgets;
133
-
134
-    /**
135
-     * this is an array of all implemented model names (i.e. not the parent abstract models, or models
136
-     * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
137
-     * Keys are model "short names" (eg "Event") as used in model relations, and values are
138
-     * classnames (eg "EEM_Event")
139
-     *
140
-     * @var array $non_abstract_db_models
141
-     */
142
-    public $non_abstract_db_models = array();
143
-
144
-    /**
145
-     * internationalization for JS strings
146
-     *    usage:   EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' );
147
-     *    in js file:  var translatedString = eei18n.string_key;
148
-     *
149
-     * @var array $i18n_js_strings
150
-     */
151
-    public static $i18n_js_strings = array();
152
-
153
-    /**
154
-     * $main_file - path to espresso.php
155
-     *
156
-     * @var array $main_file
157
-     */
158
-    public $main_file;
159
-
160
-    /**
161
-     * array of ReflectionClass objects where the key is the class name
162
-     *
163
-     * @deprecated 4.9.62.p
164
-     * @var ReflectionClass[] $_reflectors
165
-     */
166
-    public $_reflectors;
167
-
168
-    /**
169
-     * boolean flag to indicate whether or not to load/save dependencies from/to the cache
170
-     *
171
-     * @var boolean $_cache_on
172
-     */
173
-    protected $_cache_on = true;
174
-
175
-    /**
176
-     * @var ObjectIdentifier
177
-     */
178
-    private $object_identifier;
179
-
180
-
181
-    /**
182
-     * @singleton method used to instantiate class object
183
-     * @param EE_Dependency_Map|null   $dependency_map
184
-     * @param Mirror|null              $mirror
185
-     * @param ClassInterfaceCache|null $class_cache
186
-     * @param ObjectIdentifier|null    $object_identifier
187
-     * @return EE_Registry instance
188
-     */
189
-    public static function instance(
190
-        EE_Dependency_Map $dependency_map = null,
191
-        Mirror $mirror = null,
192
-        ClassInterfaceCache $class_cache = null,
193
-        ObjectIdentifier $object_identifier = null
194
-    ) {
195
-        // check if class object is instantiated
196
-        if (
197
-            ! self::$_instance instanceof EE_Registry
198
-            && $dependency_map instanceof EE_Dependency_Map
199
-            && $mirror instanceof Mirror
200
-            && $class_cache instanceof ClassInterfaceCache
201
-            && $object_identifier instanceof ObjectIdentifier
202
-        ) {
203
-            self::$_instance = new self(
204
-                $dependency_map,
205
-                $mirror,
206
-                $class_cache,
207
-                $object_identifier
208
-            );
209
-        }
210
-        return self::$_instance;
211
-    }
212
-
213
-
214
-    /**
215
-     * protected constructor to prevent direct creation
216
-     *
217
-     * @Constructor
218
-     * @param  EE_Dependency_Map  $dependency_map
219
-     * @param Mirror              $mirror
220
-     * @param ClassInterfaceCache $class_cache
221
-     * @param ObjectIdentifier    $object_identifier
222
-     */
223
-    protected function __construct(
224
-        EE_Dependency_Map $dependency_map,
225
-        Mirror $mirror,
226
-        ClassInterfaceCache $class_cache,
227
-        ObjectIdentifier $object_identifier
228
-    ) {
229
-        $this->_dependency_map = $dependency_map;
230
-        $this->mirror = $mirror;
231
-        $this->class_cache = $class_cache;
232
-        $this->object_identifier = $object_identifier;
233
-        // $registry_container = new RegistryContainer();
234
-        $this->LIB = new RegistryContainer();
235
-        $this->addons = new RegistryContainer();
236
-        $this->modules = new RegistryContainer();
237
-        $this->shortcodes = new RegistryContainer();
238
-        $this->widgets = new RegistryContainer();
239
-        add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
240
-    }
241
-
242
-
243
-    /**
244
-     * initialize
245
-     *
246
-     * @throws OutOfBoundsException
247
-     * @throws InvalidArgumentException
248
-     * @throws InvalidInterfaceException
249
-     * @throws InvalidDataTypeException
250
-     * @throws EE_Error
251
-     * @throws ReflectionException
252
-     */
253
-    public function initialize()
254
-    {
255
-        $this->_class_abbreviations = apply_filters(
256
-            'FHEE__EE_Registry____construct___class_abbreviations',
257
-            array(
258
-                'EE_Config'                                       => 'CFG',
259
-                'EE_Session'                                      => 'SSN',
260
-                'EE_Capabilities'                                 => 'CAP',
261
-                'EE_Cart'                                         => 'CART',
262
-                'EE_Network_Config'                               => 'NET_CFG',
263
-                'EE_Request_Handler'                              => 'REQ',
264
-                'EE_Message_Resource_Manager'                     => 'MRM',
265
-                'EventEspresso\core\services\commands\CommandBus' => 'BUS',
266
-                'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
267
-            )
268
-        );
269
-        $this->load_core('Base', array(), true);
270
-        // add our request and response objects to the cache
271
-        $request_loader = $this->_dependency_map->class_loader(
272
-            'EventEspresso\core\services\request\Request'
273
-        );
274
-        $this->_set_cached_class(
275
-            $request_loader(),
276
-            'EventEspresso\core\services\request\Request'
277
-        );
278
-        $response_loader = $this->_dependency_map->class_loader(
279
-            'EventEspresso\core\services\request\Response'
280
-        );
281
-        $this->_set_cached_class(
282
-            $response_loader(),
283
-            'EventEspresso\core\services\request\Response'
284
-        );
285
-        add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
286
-    }
287
-
288
-
289
-    /**
290
-     * @return void
291
-     */
292
-    public function init()
293
-    {
294
-        // Get current page protocol
295
-        $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
296
-        // Output admin-ajax.php URL with same protocol as current page
297
-        self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
298
-        self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
299
-    }
300
-
301
-
302
-    /**
303
-     * localize_i18n_js_strings
304
-     *
305
-     * @return string
306
-     */
307
-    public static function localize_i18n_js_strings()
308
-    {
309
-        $i18n_js_strings = (array) self::$i18n_js_strings;
310
-        foreach ($i18n_js_strings as $key => $value) {
311
-            if (is_scalar($value)) {
312
-                $i18n_js_strings[ $key ] = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
313
-            }
314
-        }
315
-        return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
316
-    }
317
-
318
-
319
-    /**
320
-     * @param mixed string | EED_Module $module
321
-     * @throws OutOfBoundsException
322
-     * @throws InvalidArgumentException
323
-     * @throws InvalidInterfaceException
324
-     * @throws InvalidDataTypeException
325
-     * @throws EE_Error
326
-     * @throws ReflectionException
327
-     */
328
-    public function add_module($module)
329
-    {
330
-        if ($module instanceof EED_Module) {
331
-            $module_class = get_class($module);
332
-            $this->modules->{$module_class} = $module;
333
-        } else {
334
-            if (! class_exists('EE_Module_Request_Router', false)) {
335
-                $this->load_core('Module_Request_Router');
336
-            }
337
-            EE_Module_Request_Router::module_factory($module);
338
-        }
339
-    }
340
-
341
-
342
-    /**
343
-     * @param string $module_name
344
-     * @return mixed EED_Module | NULL
345
-     */
346
-    public function get_module($module_name = '')
347
-    {
348
-        return isset($this->modules->{$module_name})
349
-            ? $this->modules->{$module_name}
350
-            : null;
351
-    }
352
-
353
-
354
-    /**
355
-     * loads core classes - must be singletons
356
-     *
357
-     * @param string $class_name - simple class name ie: session
358
-     * @param mixed  $arguments
359
-     * @param bool   $load_only
360
-     * @return mixed
361
-     * @throws InvalidInterfaceException
362
-     * @throws InvalidDataTypeException
363
-     * @throws EE_Error
364
-     * @throws ReflectionException
365
-     * @throws InvalidArgumentException
366
-     */
367
-    public function load_core($class_name, $arguments = array(), $load_only = false)
368
-    {
369
-        $core_paths = apply_filters(
370
-            'FHEE__EE_Registry__load_core__core_paths',
371
-            array(
372
-                EE_CORE,
373
-                EE_ADMIN,
374
-                EE_CPTS,
375
-                EE_CORE . 'data_migration_scripts/',
376
-                EE_CORE . 'capabilities/',
377
-                EE_CORE . 'request_stack/',
378
-                EE_CORE . 'middleware/',
379
-            )
380
-        );
381
-        // retrieve instantiated class
382
-        return $this->_load(
383
-            $core_paths,
384
-            'EE_',
385
-            $class_name,
386
-            'core',
387
-            $arguments,
388
-            false,
389
-            true,
390
-            $load_only
391
-        );
392
-    }
393
-
394
-
395
-    /**
396
-     * loads service classes
397
-     *
398
-     * @param string $class_name - simple class name ie: session
399
-     * @param mixed  $arguments
400
-     * @param bool   $load_only
401
-     * @return mixed
402
-     * @throws InvalidInterfaceException
403
-     * @throws InvalidDataTypeException
404
-     * @throws EE_Error
405
-     * @throws ReflectionException
406
-     * @throws InvalidArgumentException
407
-     */
408
-    public function load_service($class_name, $arguments = array(), $load_only = false)
409
-    {
410
-        $service_paths = apply_filters(
411
-            'FHEE__EE_Registry__load_service__service_paths',
412
-            array(
413
-                EE_CORE . 'services/',
414
-            )
415
-        );
416
-        // retrieve instantiated class
417
-        return $this->_load(
418
-            $service_paths,
419
-            'EE_',
420
-            $class_name,
421
-            'class',
422
-            $arguments,
423
-            false,
424
-            true,
425
-            $load_only
426
-        );
427
-    }
428
-
429
-
430
-    /**
431
-     * loads data_migration_scripts
432
-     *
433
-     * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
434
-     * @param mixed  $arguments
435
-     * @return EE_Data_Migration_Script_Base|mixed
436
-     * @throws InvalidInterfaceException
437
-     * @throws InvalidDataTypeException
438
-     * @throws EE_Error
439
-     * @throws ReflectionException
440
-     * @throws InvalidArgumentException
441
-     */
442
-    public function load_dms($class_name, $arguments = array())
443
-    {
444
-        // retrieve instantiated class
445
-        return $this->_load(
446
-            EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
447
-            'EE_DMS_',
448
-            $class_name,
449
-            'dms',
450
-            $arguments,
451
-            false,
452
-            false
453
-        );
454
-    }
455
-
456
-
457
-    /**
458
-     * loads object creating classes - must be singletons
459
-     *
460
-     * @param string $class_name - simple class name ie: attendee
461
-     * @param mixed  $arguments  - an array of arguments to pass to the class
462
-     * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
463
-     *                           instantiate
464
-     * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
465
-     *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
466
-     * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
467
-     *                           (default)
468
-     * @return EE_Base_Class | bool
469
-     * @throws InvalidInterfaceException
470
-     * @throws InvalidDataTypeException
471
-     * @throws EE_Error
472
-     * @throws ReflectionException
473
-     * @throws InvalidArgumentException
474
-     */
475
-    public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
476
-    {
477
-        $paths = apply_filters(
478
-            'FHEE__EE_Registry__load_class__paths',
479
-            array(
480
-                EE_CORE,
481
-                EE_CLASSES,
482
-                EE_BUSINESS,
483
-            )
484
-        );
485
-        // retrieve instantiated class
486
-        return $this->_load(
487
-            $paths,
488
-            'EE_',
489
-            $class_name,
490
-            'class',
491
-            $arguments,
492
-            $from_db,
493
-            $cache,
494
-            $load_only
495
-        );
496
-    }
497
-
498
-
499
-    /**
500
-     * loads helper classes - must be singletons
501
-     *
502
-     * @param string $class_name - simple class name ie: price
503
-     * @param mixed  $arguments
504
-     * @param bool   $load_only
505
-     * @return EEH_Base | bool
506
-     * @throws InvalidInterfaceException
507
-     * @throws InvalidDataTypeException
508
-     * @throws EE_Error
509
-     * @throws ReflectionException
510
-     * @throws InvalidArgumentException
511
-     */
512
-    public function load_helper($class_name, $arguments = array(), $load_only = true)
513
-    {
514
-        // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
515
-        $helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
516
-        // retrieve instantiated class
517
-        return $this->_load(
518
-            $helper_paths,
519
-            'EEH_',
520
-            $class_name,
521
-            'helper',
522
-            $arguments,
523
-            false,
524
-            true,
525
-            $load_only
526
-        );
527
-    }
528
-
529
-
530
-    /**
531
-     * loads core classes - must be singletons
532
-     *
533
-     * @param string $class_name - simple class name ie: session
534
-     * @param mixed  $arguments
535
-     * @param bool   $load_only
536
-     * @param bool   $cache      whether to cache the object or not.
537
-     * @return mixed
538
-     * @throws InvalidInterfaceException
539
-     * @throws InvalidDataTypeException
540
-     * @throws EE_Error
541
-     * @throws ReflectionException
542
-     * @throws InvalidArgumentException
543
-     */
544
-    public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
545
-    {
546
-        $paths = array(
547
-            EE_LIBRARIES,
548
-            EE_LIBRARIES . 'messages/',
549
-            EE_LIBRARIES . 'shortcodes/',
550
-            EE_LIBRARIES . 'qtips/',
551
-            EE_LIBRARIES . 'payment_methods/',
552
-        );
553
-        // retrieve instantiated class
554
-        return $this->_load(
555
-            $paths,
556
-            'EE_',
557
-            $class_name,
558
-            'lib',
559
-            $arguments,
560
-            false,
561
-            $cache,
562
-            $load_only
563
-        );
564
-    }
565
-
566
-
567
-    /**
568
-     * loads model classes - must be singletons
569
-     *
570
-     * @param string $class_name - simple class name ie: price
571
-     * @param mixed  $arguments
572
-     * @param bool   $load_only
573
-     * @return EEM_Base | bool
574
-     * @throws InvalidInterfaceException
575
-     * @throws InvalidDataTypeException
576
-     * @throws EE_Error
577
-     * @throws ReflectionException
578
-     * @throws InvalidArgumentException
579
-     */
580
-    public function load_model($class_name, $arguments = array(), $load_only = false)
581
-    {
582
-        $paths = apply_filters(
583
-            'FHEE__EE_Registry__load_model__paths',
584
-            array(
585
-                EE_MODELS,
586
-                EE_CORE,
587
-            )
588
-        );
589
-        // retrieve instantiated class
590
-        return $this->_load(
591
-            $paths,
592
-            'EEM_',
593
-            $class_name,
594
-            'model',
595
-            $arguments,
596
-            false,
597
-            true,
598
-            $load_only
599
-        );
600
-    }
601
-
602
-
603
-    /**
604
-     * loads model classes - must be singletons
605
-     *
606
-     * @param string $class_name - simple class name ie: price
607
-     * @param mixed  $arguments
608
-     * @param bool   $load_only
609
-     * @return mixed | bool
610
-     * @throws InvalidInterfaceException
611
-     * @throws InvalidDataTypeException
612
-     * @throws EE_Error
613
-     * @throws ReflectionException
614
-     * @throws InvalidArgumentException
615
-     */
616
-    public function load_model_class($class_name, $arguments = array(), $load_only = true)
617
-    {
618
-        $paths = array(
619
-            EE_MODELS . 'fields/',
620
-            EE_MODELS . 'helpers/',
621
-            EE_MODELS . 'relations/',
622
-            EE_MODELS . 'strategies/',
623
-        );
624
-        // retrieve instantiated class
625
-        return $this->_load(
626
-            $paths,
627
-            'EE_',
628
-            $class_name,
629
-            '',
630
-            $arguments,
631
-            false,
632
-            true,
633
-            $load_only
634
-        );
635
-    }
636
-
637
-
638
-    /**
639
-     * Determines if $model_name is the name of an actual EE model.
640
-     *
641
-     * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
642
-     * @return boolean
643
-     */
644
-    public function is_model_name($model_name)
645
-    {
646
-        return isset($this->models[ $model_name ]);
647
-    }
648
-
649
-
650
-    /**
651
-     * generic class loader
652
-     *
653
-     * @param string $path_to_file - directory path to file location, not including filename
654
-     * @param string $file_name    - file name  ie:  my_file.php, including extension
655
-     * @param string $type         - file type - core? class? helper? model?
656
-     * @param mixed  $arguments
657
-     * @param bool   $load_only
658
-     * @return mixed
659
-     * @throws InvalidInterfaceException
660
-     * @throws InvalidDataTypeException
661
-     * @throws EE_Error
662
-     * @throws ReflectionException
663
-     * @throws InvalidArgumentException
664
-     */
665
-    public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
666
-    {
667
-        // retrieve instantiated class
668
-        return $this->_load(
669
-            $path_to_file,
670
-            '',
671
-            $file_name,
672
-            $type,
673
-            $arguments,
674
-            false,
675
-            true,
676
-            $load_only
677
-        );
678
-    }
679
-
680
-
681
-    /**
682
-     * @param string $path_to_file - directory path to file location, not including filename
683
-     * @param string $class_name   - full class name  ie:  My_Class
684
-     * @param string $type         - file type - core? class? helper? model?
685
-     * @param mixed  $arguments
686
-     * @param bool   $load_only
687
-     * @return bool|EE_Addon|object
688
-     * @throws InvalidInterfaceException
689
-     * @throws InvalidDataTypeException
690
-     * @throws EE_Error
691
-     * @throws ReflectionException
692
-     * @throws InvalidArgumentException
693
-     */
694
-    public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
695
-    {
696
-        // retrieve instantiated class
697
-        return $this->_load(
698
-            $path_to_file,
699
-            'addon',
700
-            $class_name,
701
-            $type,
702
-            $arguments,
703
-            false,
704
-            true,
705
-            $load_only
706
-        );
707
-    }
708
-
709
-
710
-    /**
711
-     * instantiates, caches, and automatically resolves dependencies
712
-     * for classes that use a Fully Qualified Class Name.
713
-     * if the class is not capable of being loaded using PSR-4 autoloading,
714
-     * then you need to use one of the existing load_*() methods
715
-     * which can resolve the classname and filepath from the passed arguments
716
-     *
717
-     * @param bool|string $class_name   Fully Qualified Class Name
718
-     * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
719
-     * @param bool        $cache        whether to cache the instantiated object for reuse
720
-     * @param bool        $from_db      some classes are instantiated from the db
721
-     *                                  and thus call a different method to instantiate
722
-     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
723
-     * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
724
-     * @return bool|null|mixed          null = failure to load or instantiate class object.
725
-     *                                  object = class loaded and instantiated successfully.
726
-     *                                  bool = fail or success when $load_only is true
727
-     * @throws InvalidInterfaceException
728
-     * @throws InvalidDataTypeException
729
-     * @throws EE_Error
730
-     * @throws ReflectionException
731
-     * @throws InvalidArgumentException
732
-     */
733
-    public function create(
734
-        $class_name = false,
735
-        $arguments = array(),
736
-        $cache = false,
737
-        $from_db = false,
738
-        $load_only = false,
739
-        $addon = false
740
-    ) {
741
-        $class_name = ltrim($class_name, '\\');
742
-        $class_name = $this->class_cache->getFqnForAlias($class_name);
743
-        $class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
744
-        // if a non-FQCN was passed, then
745
-        // verifyClassExists() might return an object
746
-        // or it could return null if the class just could not be found anywhere
747
-        if ($class_exists instanceof $class_name || $class_exists === null) {
748
-            // either way, return the results
749
-            return $class_exists;
750
-        }
751
-        $class_name = $class_exists;
752
-        // if we're only loading the class and it already exists, then let's just return true immediately
753
-        if ($load_only) {
754
-            return true;
755
-        }
756
-        $addon = $addon ? 'addon' : '';
757
-        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
758
-        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
759
-        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
760
-        if ($this->_cache_on && $cache && ! $load_only) {
761
-            // return object if it's already cached
762
-            $cached_class = $this->_get_cached_class($class_name, $addon, $arguments);
763
-            if ($cached_class !== null) {
764
-                return $cached_class;
765
-            }
766
-        }// obtain the loader method from the dependency map
767
-        $loader = $this->_dependency_map->class_loader($class_name);// instantiate the requested object
768
-        if ($loader instanceof Closure) {
769
-            $class_obj = $loader($arguments);
770
-        } else {
771
-            if ($loader && method_exists($this, $loader)) {
772
-                $class_obj = $this->{$loader}($class_name, $arguments);
773
-            } else {
774
-                $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
775
-            }
776
-        }
777
-        if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) {
778
-            // save it for later... kinda like gum  { : $
779
-            $this->_set_cached_class(
780
-                $class_obj,
781
-                $class_name,
782
-                $addon,
783
-                $from_db,
784
-                $arguments
785
-            );
786
-        }
787
-        $this->_cache_on = true;
788
-        return $class_obj;
789
-    }
790
-
791
-
792
-    /**
793
-     * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
794
-     *
795
-     * @param string|object $class_name
796
-     * @param array         $arguments
797
-     * @param int           $attempt
798
-     * @return mixed
799
-     */
800
-    private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1)
801
-    {
802
-        if (is_object($class_name) || class_exists($class_name)) {
803
-            return $class_name;
804
-        }
805
-        switch ($attempt) {
806
-            case 1:
807
-                // if it's a FQCN then maybe the class is registered with a preceding \
808
-                $class_name = strpos($class_name, '\\') !== false
809
-                    ? '\\' . ltrim($class_name, '\\')
810
-                    : $class_name;
811
-                break;
812
-            case 2:
813
-                //
814
-                $loader = $this->_dependency_map->class_loader($class_name);
815
-                if ($loader && method_exists($this, $loader)) {
816
-                    return $this->{$loader}($class_name, $arguments);
817
-                }
818
-                break;
819
-            case 3:
820
-            default:
821
-                return null;
822
-        }
823
-        $attempt++;
824
-        return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
825
-    }
826
-
827
-
828
-    /**
829
-     * instantiates, caches, and injects dependencies for classes
830
-     *
831
-     * @param array       $file_paths   an array of paths to folders to look in
832
-     * @param string      $class_prefix EE  or EEM or... ???
833
-     * @param bool|string $class_name   $class name
834
-     * @param string      $type         file type - core? class? helper? model?
835
-     * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
836
-     * @param bool        $from_db      some classes are instantiated from the db
837
-     *                                  and thus call a different method to instantiate
838
-     * @param bool        $cache        whether to cache the instantiated object for reuse
839
-     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
840
-     * @return bool|null|object null = failure to load or instantiate class object.
841
-     *                                  object = class loaded and instantiated successfully.
842
-     *                                  bool = fail or success when $load_only is true
843
-     * @throws EE_Error
844
-     * @throws ReflectionException
845
-     * @throws InvalidInterfaceException
846
-     * @throws InvalidDataTypeException
847
-     * @throws InvalidArgumentException
848
-     */
849
-    protected function _load(
850
-        $file_paths = array(),
851
-        $class_prefix = 'EE_',
852
-        $class_name = false,
853
-        $type = 'class',
854
-        $arguments = array(),
855
-        $from_db = false,
856
-        $cache = true,
857
-        $load_only = false
858
-    ) {
859
-        $class_name = ltrim($class_name, '\\');
860
-        // strip php file extension
861
-        $class_name = str_replace('.php', '', trim($class_name));
862
-        // does the class have a prefix ?
863
-        if (! empty($class_prefix) && $class_prefix !== 'addon') {
864
-            // make sure $class_prefix is uppercase
865
-            $class_prefix = strtoupper(trim($class_prefix));
866
-            // add class prefix ONCE!!!
867
-            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
868
-        }
869
-        $class_name = $this->class_cache->getFqnForAlias($class_name);
870
-        $class_exists = class_exists($class_name, false);
871
-        // if we're only loading the class and it already exists, then let's just return true immediately
872
-        if ($load_only && $class_exists) {
873
-            return true;
874
-        }
875
-        $arguments = is_array($arguments) ? $arguments : array($arguments);
876
-        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
877
-        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
878
-        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
879
-        if ($this->_cache_on && $cache && ! $load_only) {
880
-            // return object if it's already cached
881
-            $cached_class = $this->_get_cached_class($class_name, $class_prefix, $arguments);
882
-            if ($cached_class !== null) {
883
-                return $cached_class;
884
-            }
885
-        }
886
-        // if the class doesn't already exist.. then we need to try and find the file and load it
887
-        if (! $class_exists) {
888
-            // get full path to file
889
-            $path = $this->_resolve_path($class_name, $type, $file_paths);
890
-            // load the file
891
-            $loaded = $this->_require_file($path, $class_name, $type, $file_paths);
892
-            // if we are only loading a file but NOT instantiating an object
893
-            // then return boolean for whether class was loaded or not
894
-            if ($load_only) {
895
-                return $loaded;
896
-            }
897
-            // if an object was expected but loading failed, then return nothing
898
-            if (! $loaded) {
899
-                return null;
900
-            }
901
-        }
902
-        // instantiate the requested object
903
-        $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
904
-        if ($this->_cache_on && $cache) {
905
-            // save it for later... kinda like gum  { : $
906
-            $this->_set_cached_class(
907
-                $class_obj,
908
-                $class_name,
909
-                $class_prefix,
910
-                $from_db,
911
-                $arguments
912
-            );
913
-        }
914
-        $this->_cache_on = true;
915
-        return $class_obj;
916
-    }
917
-
918
-
919
-    /**
920
-     * @param string $class_name
921
-     * @param string $default have to specify something, but not anything that will conflict
922
-     * @return mixed|string
923
-     */
924
-    protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS')
925
-    {
926
-        return isset($this->_class_abbreviations[ $class_name ])
927
-            ? $this->_class_abbreviations[ $class_name ]
928
-            : $default;
929
-    }
930
-
931
-
932
-    /**
933
-     * attempts to find a cached version of the requested class
934
-     * by looking in the following places:
935
-     *        $this->{$class_abbreviation}            ie:    $this->CART
936
-     *        $this->{$class_name}                        ie:    $this->Some_Class
937
-     *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
938
-     *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
939
-     *
940
-     * @param string $class_name
941
-     * @param string $class_prefix
942
-     * @param array  $arguments
943
-     * @return mixed
944
-     */
945
-    protected function _get_cached_class(
946
-        $class_name,
947
-        $class_prefix = '',
948
-        $arguments = array()
949
-    ) {
950
-        if ($class_name === 'EE_Registry') {
951
-            return $this;
952
-        }
953
-        $class_abbreviation = $this->get_class_abbreviation($class_name);
954
-        // check if class has already been loaded, and return it if it has been
955
-        if (isset($this->{$class_abbreviation})) {
956
-            return $this->{$class_abbreviation};
957
-        }
958
-        $class_name = str_replace('\\', '_', $class_name);
959
-        if (isset($this->{$class_name})) {
960
-            return $this->{$class_name};
961
-        }
962
-        if ($class_prefix === 'addon' && isset($this->addons->{$class_name})) {
963
-            return $this->addons->{$class_name};
964
-        }
965
-        $object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments);
966
-        if (isset($this->LIB->{$object_identifier})) {
967
-            return $this->LIB->{$object_identifier};
968
-        }
969
-        foreach ($this->LIB as $key => $object) {
970
-            if (
26
+	/**
27
+	 * @var EE_Registry $_instance
28
+	 */
29
+	private static $_instance;
30
+
31
+	/**
32
+	 * @var EE_Dependency_Map $_dependency_map
33
+	 */
34
+	protected $_dependency_map;
35
+
36
+	/**
37
+	 * @var Mirror
38
+	 */
39
+	private $mirror;
40
+
41
+	/**
42
+	 * @var ClassInterfaceCache $class_cache
43
+	 */
44
+	private $class_cache;
45
+
46
+	/**
47
+	 * @var array $_class_abbreviations
48
+	 */
49
+	protected $_class_abbreviations = array();
50
+
51
+	/**
52
+	 * @var CommandBusInterface $BUS
53
+	 */
54
+	public $BUS;
55
+
56
+	/**
57
+	 * @var EE_Cart $CART
58
+	 */
59
+	public $CART;
60
+
61
+	/**
62
+	 * @var EE_Config $CFG
63
+	 */
64
+	public $CFG;
65
+
66
+	/**
67
+	 * @var EE_Network_Config $NET_CFG
68
+	 */
69
+	public $NET_CFG;
70
+
71
+	/**
72
+	 * StdClass object for storing library classes in
73
+	 *
74
+	 * @var RegistryContainer $LIB
75
+	 */
76
+	public $LIB;
77
+
78
+	/**
79
+	 * @var EE_Request_Handler $REQ
80
+	 */
81
+	public $REQ;
82
+
83
+	/**
84
+	 * @var EE_Session $SSN
85
+	 */
86
+	public $SSN;
87
+
88
+	/**
89
+	 * @since 4.5.0
90
+	 * @var EE_Capabilities $CAP
91
+	 */
92
+	public $CAP;
93
+
94
+	/**
95
+	 * @since 4.9.0
96
+	 * @var EE_Message_Resource_Manager $MRM
97
+	 */
98
+	public $MRM;
99
+
100
+	/**
101
+	 * @var Registry $AssetsRegistry
102
+	 */
103
+	public $AssetsRegistry;
104
+
105
+	/**
106
+	 * StdClass object for holding addons which have registered themselves to work with EE core
107
+	 *
108
+	 * @var EE_Addon[] $addons
109
+	 */
110
+	public $addons;
111
+
112
+	/**
113
+	 * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
114
+	 *
115
+	 * @var EEM_Base[] $models
116
+	 */
117
+	public $models = array();
118
+
119
+	/**
120
+	 * @var EED_Module[] $modules
121
+	 */
122
+	public $modules;
123
+
124
+	/**
125
+	 * @var EES_Shortcode[] $shortcodes
126
+	 */
127
+	public $shortcodes;
128
+
129
+	/**
130
+	 * @var WP_Widget[] $widgets
131
+	 */
132
+	public $widgets;
133
+
134
+	/**
135
+	 * this is an array of all implemented model names (i.e. not the parent abstract models, or models
136
+	 * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
137
+	 * Keys are model "short names" (eg "Event") as used in model relations, and values are
138
+	 * classnames (eg "EEM_Event")
139
+	 *
140
+	 * @var array $non_abstract_db_models
141
+	 */
142
+	public $non_abstract_db_models = array();
143
+
144
+	/**
145
+	 * internationalization for JS strings
146
+	 *    usage:   EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' );
147
+	 *    in js file:  var translatedString = eei18n.string_key;
148
+	 *
149
+	 * @var array $i18n_js_strings
150
+	 */
151
+	public static $i18n_js_strings = array();
152
+
153
+	/**
154
+	 * $main_file - path to espresso.php
155
+	 *
156
+	 * @var array $main_file
157
+	 */
158
+	public $main_file;
159
+
160
+	/**
161
+	 * array of ReflectionClass objects where the key is the class name
162
+	 *
163
+	 * @deprecated 4.9.62.p
164
+	 * @var ReflectionClass[] $_reflectors
165
+	 */
166
+	public $_reflectors;
167
+
168
+	/**
169
+	 * boolean flag to indicate whether or not to load/save dependencies from/to the cache
170
+	 *
171
+	 * @var boolean $_cache_on
172
+	 */
173
+	protected $_cache_on = true;
174
+
175
+	/**
176
+	 * @var ObjectIdentifier
177
+	 */
178
+	private $object_identifier;
179
+
180
+
181
+	/**
182
+	 * @singleton method used to instantiate class object
183
+	 * @param EE_Dependency_Map|null   $dependency_map
184
+	 * @param Mirror|null              $mirror
185
+	 * @param ClassInterfaceCache|null $class_cache
186
+	 * @param ObjectIdentifier|null    $object_identifier
187
+	 * @return EE_Registry instance
188
+	 */
189
+	public static function instance(
190
+		EE_Dependency_Map $dependency_map = null,
191
+		Mirror $mirror = null,
192
+		ClassInterfaceCache $class_cache = null,
193
+		ObjectIdentifier $object_identifier = null
194
+	) {
195
+		// check if class object is instantiated
196
+		if (
197
+			! self::$_instance instanceof EE_Registry
198
+			&& $dependency_map instanceof EE_Dependency_Map
199
+			&& $mirror instanceof Mirror
200
+			&& $class_cache instanceof ClassInterfaceCache
201
+			&& $object_identifier instanceof ObjectIdentifier
202
+		) {
203
+			self::$_instance = new self(
204
+				$dependency_map,
205
+				$mirror,
206
+				$class_cache,
207
+				$object_identifier
208
+			);
209
+		}
210
+		return self::$_instance;
211
+	}
212
+
213
+
214
+	/**
215
+	 * protected constructor to prevent direct creation
216
+	 *
217
+	 * @Constructor
218
+	 * @param  EE_Dependency_Map  $dependency_map
219
+	 * @param Mirror              $mirror
220
+	 * @param ClassInterfaceCache $class_cache
221
+	 * @param ObjectIdentifier    $object_identifier
222
+	 */
223
+	protected function __construct(
224
+		EE_Dependency_Map $dependency_map,
225
+		Mirror $mirror,
226
+		ClassInterfaceCache $class_cache,
227
+		ObjectIdentifier $object_identifier
228
+	) {
229
+		$this->_dependency_map = $dependency_map;
230
+		$this->mirror = $mirror;
231
+		$this->class_cache = $class_cache;
232
+		$this->object_identifier = $object_identifier;
233
+		// $registry_container = new RegistryContainer();
234
+		$this->LIB = new RegistryContainer();
235
+		$this->addons = new RegistryContainer();
236
+		$this->modules = new RegistryContainer();
237
+		$this->shortcodes = new RegistryContainer();
238
+		$this->widgets = new RegistryContainer();
239
+		add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
240
+	}
241
+
242
+
243
+	/**
244
+	 * initialize
245
+	 *
246
+	 * @throws OutOfBoundsException
247
+	 * @throws InvalidArgumentException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws InvalidDataTypeException
250
+	 * @throws EE_Error
251
+	 * @throws ReflectionException
252
+	 */
253
+	public function initialize()
254
+	{
255
+		$this->_class_abbreviations = apply_filters(
256
+			'FHEE__EE_Registry____construct___class_abbreviations',
257
+			array(
258
+				'EE_Config'                                       => 'CFG',
259
+				'EE_Session'                                      => 'SSN',
260
+				'EE_Capabilities'                                 => 'CAP',
261
+				'EE_Cart'                                         => 'CART',
262
+				'EE_Network_Config'                               => 'NET_CFG',
263
+				'EE_Request_Handler'                              => 'REQ',
264
+				'EE_Message_Resource_Manager'                     => 'MRM',
265
+				'EventEspresso\core\services\commands\CommandBus' => 'BUS',
266
+				'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
267
+			)
268
+		);
269
+		$this->load_core('Base', array(), true);
270
+		// add our request and response objects to the cache
271
+		$request_loader = $this->_dependency_map->class_loader(
272
+			'EventEspresso\core\services\request\Request'
273
+		);
274
+		$this->_set_cached_class(
275
+			$request_loader(),
276
+			'EventEspresso\core\services\request\Request'
277
+		);
278
+		$response_loader = $this->_dependency_map->class_loader(
279
+			'EventEspresso\core\services\request\Response'
280
+		);
281
+		$this->_set_cached_class(
282
+			$response_loader(),
283
+			'EventEspresso\core\services\request\Response'
284
+		);
285
+		add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
286
+	}
287
+
288
+
289
+	/**
290
+	 * @return void
291
+	 */
292
+	public function init()
293
+	{
294
+		// Get current page protocol
295
+		$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
296
+		// Output admin-ajax.php URL with same protocol as current page
297
+		self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
298
+		self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
299
+	}
300
+
301
+
302
+	/**
303
+	 * localize_i18n_js_strings
304
+	 *
305
+	 * @return string
306
+	 */
307
+	public static function localize_i18n_js_strings()
308
+	{
309
+		$i18n_js_strings = (array) self::$i18n_js_strings;
310
+		foreach ($i18n_js_strings as $key => $value) {
311
+			if (is_scalar($value)) {
312
+				$i18n_js_strings[ $key ] = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
313
+			}
314
+		}
315
+		return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
316
+	}
317
+
318
+
319
+	/**
320
+	 * @param mixed string | EED_Module $module
321
+	 * @throws OutOfBoundsException
322
+	 * @throws InvalidArgumentException
323
+	 * @throws InvalidInterfaceException
324
+	 * @throws InvalidDataTypeException
325
+	 * @throws EE_Error
326
+	 * @throws ReflectionException
327
+	 */
328
+	public function add_module($module)
329
+	{
330
+		if ($module instanceof EED_Module) {
331
+			$module_class = get_class($module);
332
+			$this->modules->{$module_class} = $module;
333
+		} else {
334
+			if (! class_exists('EE_Module_Request_Router', false)) {
335
+				$this->load_core('Module_Request_Router');
336
+			}
337
+			EE_Module_Request_Router::module_factory($module);
338
+		}
339
+	}
340
+
341
+
342
+	/**
343
+	 * @param string $module_name
344
+	 * @return mixed EED_Module | NULL
345
+	 */
346
+	public function get_module($module_name = '')
347
+	{
348
+		return isset($this->modules->{$module_name})
349
+			? $this->modules->{$module_name}
350
+			: null;
351
+	}
352
+
353
+
354
+	/**
355
+	 * loads core classes - must be singletons
356
+	 *
357
+	 * @param string $class_name - simple class name ie: session
358
+	 * @param mixed  $arguments
359
+	 * @param bool   $load_only
360
+	 * @return mixed
361
+	 * @throws InvalidInterfaceException
362
+	 * @throws InvalidDataTypeException
363
+	 * @throws EE_Error
364
+	 * @throws ReflectionException
365
+	 * @throws InvalidArgumentException
366
+	 */
367
+	public function load_core($class_name, $arguments = array(), $load_only = false)
368
+	{
369
+		$core_paths = apply_filters(
370
+			'FHEE__EE_Registry__load_core__core_paths',
371
+			array(
372
+				EE_CORE,
373
+				EE_ADMIN,
374
+				EE_CPTS,
375
+				EE_CORE . 'data_migration_scripts/',
376
+				EE_CORE . 'capabilities/',
377
+				EE_CORE . 'request_stack/',
378
+				EE_CORE . 'middleware/',
379
+			)
380
+		);
381
+		// retrieve instantiated class
382
+		return $this->_load(
383
+			$core_paths,
384
+			'EE_',
385
+			$class_name,
386
+			'core',
387
+			$arguments,
388
+			false,
389
+			true,
390
+			$load_only
391
+		);
392
+	}
393
+
394
+
395
+	/**
396
+	 * loads service classes
397
+	 *
398
+	 * @param string $class_name - simple class name ie: session
399
+	 * @param mixed  $arguments
400
+	 * @param bool   $load_only
401
+	 * @return mixed
402
+	 * @throws InvalidInterfaceException
403
+	 * @throws InvalidDataTypeException
404
+	 * @throws EE_Error
405
+	 * @throws ReflectionException
406
+	 * @throws InvalidArgumentException
407
+	 */
408
+	public function load_service($class_name, $arguments = array(), $load_only = false)
409
+	{
410
+		$service_paths = apply_filters(
411
+			'FHEE__EE_Registry__load_service__service_paths',
412
+			array(
413
+				EE_CORE . 'services/',
414
+			)
415
+		);
416
+		// retrieve instantiated class
417
+		return $this->_load(
418
+			$service_paths,
419
+			'EE_',
420
+			$class_name,
421
+			'class',
422
+			$arguments,
423
+			false,
424
+			true,
425
+			$load_only
426
+		);
427
+	}
428
+
429
+
430
+	/**
431
+	 * loads data_migration_scripts
432
+	 *
433
+	 * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
434
+	 * @param mixed  $arguments
435
+	 * @return EE_Data_Migration_Script_Base|mixed
436
+	 * @throws InvalidInterfaceException
437
+	 * @throws InvalidDataTypeException
438
+	 * @throws EE_Error
439
+	 * @throws ReflectionException
440
+	 * @throws InvalidArgumentException
441
+	 */
442
+	public function load_dms($class_name, $arguments = array())
443
+	{
444
+		// retrieve instantiated class
445
+		return $this->_load(
446
+			EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
447
+			'EE_DMS_',
448
+			$class_name,
449
+			'dms',
450
+			$arguments,
451
+			false,
452
+			false
453
+		);
454
+	}
455
+
456
+
457
+	/**
458
+	 * loads object creating classes - must be singletons
459
+	 *
460
+	 * @param string $class_name - simple class name ie: attendee
461
+	 * @param mixed  $arguments  - an array of arguments to pass to the class
462
+	 * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
463
+	 *                           instantiate
464
+	 * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
465
+	 *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
466
+	 * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
467
+	 *                           (default)
468
+	 * @return EE_Base_Class | bool
469
+	 * @throws InvalidInterfaceException
470
+	 * @throws InvalidDataTypeException
471
+	 * @throws EE_Error
472
+	 * @throws ReflectionException
473
+	 * @throws InvalidArgumentException
474
+	 */
475
+	public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
476
+	{
477
+		$paths = apply_filters(
478
+			'FHEE__EE_Registry__load_class__paths',
479
+			array(
480
+				EE_CORE,
481
+				EE_CLASSES,
482
+				EE_BUSINESS,
483
+			)
484
+		);
485
+		// retrieve instantiated class
486
+		return $this->_load(
487
+			$paths,
488
+			'EE_',
489
+			$class_name,
490
+			'class',
491
+			$arguments,
492
+			$from_db,
493
+			$cache,
494
+			$load_only
495
+		);
496
+	}
497
+
498
+
499
+	/**
500
+	 * loads helper classes - must be singletons
501
+	 *
502
+	 * @param string $class_name - simple class name ie: price
503
+	 * @param mixed  $arguments
504
+	 * @param bool   $load_only
505
+	 * @return EEH_Base | bool
506
+	 * @throws InvalidInterfaceException
507
+	 * @throws InvalidDataTypeException
508
+	 * @throws EE_Error
509
+	 * @throws ReflectionException
510
+	 * @throws InvalidArgumentException
511
+	 */
512
+	public function load_helper($class_name, $arguments = array(), $load_only = true)
513
+	{
514
+		// todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
515
+		$helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
516
+		// retrieve instantiated class
517
+		return $this->_load(
518
+			$helper_paths,
519
+			'EEH_',
520
+			$class_name,
521
+			'helper',
522
+			$arguments,
523
+			false,
524
+			true,
525
+			$load_only
526
+		);
527
+	}
528
+
529
+
530
+	/**
531
+	 * loads core classes - must be singletons
532
+	 *
533
+	 * @param string $class_name - simple class name ie: session
534
+	 * @param mixed  $arguments
535
+	 * @param bool   $load_only
536
+	 * @param bool   $cache      whether to cache the object or not.
537
+	 * @return mixed
538
+	 * @throws InvalidInterfaceException
539
+	 * @throws InvalidDataTypeException
540
+	 * @throws EE_Error
541
+	 * @throws ReflectionException
542
+	 * @throws InvalidArgumentException
543
+	 */
544
+	public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
545
+	{
546
+		$paths = array(
547
+			EE_LIBRARIES,
548
+			EE_LIBRARIES . 'messages/',
549
+			EE_LIBRARIES . 'shortcodes/',
550
+			EE_LIBRARIES . 'qtips/',
551
+			EE_LIBRARIES . 'payment_methods/',
552
+		);
553
+		// retrieve instantiated class
554
+		return $this->_load(
555
+			$paths,
556
+			'EE_',
557
+			$class_name,
558
+			'lib',
559
+			$arguments,
560
+			false,
561
+			$cache,
562
+			$load_only
563
+		);
564
+	}
565
+
566
+
567
+	/**
568
+	 * loads model classes - must be singletons
569
+	 *
570
+	 * @param string $class_name - simple class name ie: price
571
+	 * @param mixed  $arguments
572
+	 * @param bool   $load_only
573
+	 * @return EEM_Base | bool
574
+	 * @throws InvalidInterfaceException
575
+	 * @throws InvalidDataTypeException
576
+	 * @throws EE_Error
577
+	 * @throws ReflectionException
578
+	 * @throws InvalidArgumentException
579
+	 */
580
+	public function load_model($class_name, $arguments = array(), $load_only = false)
581
+	{
582
+		$paths = apply_filters(
583
+			'FHEE__EE_Registry__load_model__paths',
584
+			array(
585
+				EE_MODELS,
586
+				EE_CORE,
587
+			)
588
+		);
589
+		// retrieve instantiated class
590
+		return $this->_load(
591
+			$paths,
592
+			'EEM_',
593
+			$class_name,
594
+			'model',
595
+			$arguments,
596
+			false,
597
+			true,
598
+			$load_only
599
+		);
600
+	}
601
+
602
+
603
+	/**
604
+	 * loads model classes - must be singletons
605
+	 *
606
+	 * @param string $class_name - simple class name ie: price
607
+	 * @param mixed  $arguments
608
+	 * @param bool   $load_only
609
+	 * @return mixed | bool
610
+	 * @throws InvalidInterfaceException
611
+	 * @throws InvalidDataTypeException
612
+	 * @throws EE_Error
613
+	 * @throws ReflectionException
614
+	 * @throws InvalidArgumentException
615
+	 */
616
+	public function load_model_class($class_name, $arguments = array(), $load_only = true)
617
+	{
618
+		$paths = array(
619
+			EE_MODELS . 'fields/',
620
+			EE_MODELS . 'helpers/',
621
+			EE_MODELS . 'relations/',
622
+			EE_MODELS . 'strategies/',
623
+		);
624
+		// retrieve instantiated class
625
+		return $this->_load(
626
+			$paths,
627
+			'EE_',
628
+			$class_name,
629
+			'',
630
+			$arguments,
631
+			false,
632
+			true,
633
+			$load_only
634
+		);
635
+	}
636
+
637
+
638
+	/**
639
+	 * Determines if $model_name is the name of an actual EE model.
640
+	 *
641
+	 * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
642
+	 * @return boolean
643
+	 */
644
+	public function is_model_name($model_name)
645
+	{
646
+		return isset($this->models[ $model_name ]);
647
+	}
648
+
649
+
650
+	/**
651
+	 * generic class loader
652
+	 *
653
+	 * @param string $path_to_file - directory path to file location, not including filename
654
+	 * @param string $file_name    - file name  ie:  my_file.php, including extension
655
+	 * @param string $type         - file type - core? class? helper? model?
656
+	 * @param mixed  $arguments
657
+	 * @param bool   $load_only
658
+	 * @return mixed
659
+	 * @throws InvalidInterfaceException
660
+	 * @throws InvalidDataTypeException
661
+	 * @throws EE_Error
662
+	 * @throws ReflectionException
663
+	 * @throws InvalidArgumentException
664
+	 */
665
+	public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
666
+	{
667
+		// retrieve instantiated class
668
+		return $this->_load(
669
+			$path_to_file,
670
+			'',
671
+			$file_name,
672
+			$type,
673
+			$arguments,
674
+			false,
675
+			true,
676
+			$load_only
677
+		);
678
+	}
679
+
680
+
681
+	/**
682
+	 * @param string $path_to_file - directory path to file location, not including filename
683
+	 * @param string $class_name   - full class name  ie:  My_Class
684
+	 * @param string $type         - file type - core? class? helper? model?
685
+	 * @param mixed  $arguments
686
+	 * @param bool   $load_only
687
+	 * @return bool|EE_Addon|object
688
+	 * @throws InvalidInterfaceException
689
+	 * @throws InvalidDataTypeException
690
+	 * @throws EE_Error
691
+	 * @throws ReflectionException
692
+	 * @throws InvalidArgumentException
693
+	 */
694
+	public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
695
+	{
696
+		// retrieve instantiated class
697
+		return $this->_load(
698
+			$path_to_file,
699
+			'addon',
700
+			$class_name,
701
+			$type,
702
+			$arguments,
703
+			false,
704
+			true,
705
+			$load_only
706
+		);
707
+	}
708
+
709
+
710
+	/**
711
+	 * instantiates, caches, and automatically resolves dependencies
712
+	 * for classes that use a Fully Qualified Class Name.
713
+	 * if the class is not capable of being loaded using PSR-4 autoloading,
714
+	 * then you need to use one of the existing load_*() methods
715
+	 * which can resolve the classname and filepath from the passed arguments
716
+	 *
717
+	 * @param bool|string $class_name   Fully Qualified Class Name
718
+	 * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
719
+	 * @param bool        $cache        whether to cache the instantiated object for reuse
720
+	 * @param bool        $from_db      some classes are instantiated from the db
721
+	 *                                  and thus call a different method to instantiate
722
+	 * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
723
+	 * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
724
+	 * @return bool|null|mixed          null = failure to load or instantiate class object.
725
+	 *                                  object = class loaded and instantiated successfully.
726
+	 *                                  bool = fail or success when $load_only is true
727
+	 * @throws InvalidInterfaceException
728
+	 * @throws InvalidDataTypeException
729
+	 * @throws EE_Error
730
+	 * @throws ReflectionException
731
+	 * @throws InvalidArgumentException
732
+	 */
733
+	public function create(
734
+		$class_name = false,
735
+		$arguments = array(),
736
+		$cache = false,
737
+		$from_db = false,
738
+		$load_only = false,
739
+		$addon = false
740
+	) {
741
+		$class_name = ltrim($class_name, '\\');
742
+		$class_name = $this->class_cache->getFqnForAlias($class_name);
743
+		$class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
744
+		// if a non-FQCN was passed, then
745
+		// verifyClassExists() might return an object
746
+		// or it could return null if the class just could not be found anywhere
747
+		if ($class_exists instanceof $class_name || $class_exists === null) {
748
+			// either way, return the results
749
+			return $class_exists;
750
+		}
751
+		$class_name = $class_exists;
752
+		// if we're only loading the class and it already exists, then let's just return true immediately
753
+		if ($load_only) {
754
+			return true;
755
+		}
756
+		$addon = $addon ? 'addon' : '';
757
+		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
758
+		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
759
+		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
760
+		if ($this->_cache_on && $cache && ! $load_only) {
761
+			// return object if it's already cached
762
+			$cached_class = $this->_get_cached_class($class_name, $addon, $arguments);
763
+			if ($cached_class !== null) {
764
+				return $cached_class;
765
+			}
766
+		}// obtain the loader method from the dependency map
767
+		$loader = $this->_dependency_map->class_loader($class_name);// instantiate the requested object
768
+		if ($loader instanceof Closure) {
769
+			$class_obj = $loader($arguments);
770
+		} else {
771
+			if ($loader && method_exists($this, $loader)) {
772
+				$class_obj = $this->{$loader}($class_name, $arguments);
773
+			} else {
774
+				$class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
775
+			}
776
+		}
777
+		if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) {
778
+			// save it for later... kinda like gum  { : $
779
+			$this->_set_cached_class(
780
+				$class_obj,
781
+				$class_name,
782
+				$addon,
783
+				$from_db,
784
+				$arguments
785
+			);
786
+		}
787
+		$this->_cache_on = true;
788
+		return $class_obj;
789
+	}
790
+
791
+
792
+	/**
793
+	 * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
794
+	 *
795
+	 * @param string|object $class_name
796
+	 * @param array         $arguments
797
+	 * @param int           $attempt
798
+	 * @return mixed
799
+	 */
800
+	private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1)
801
+	{
802
+		if (is_object($class_name) || class_exists($class_name)) {
803
+			return $class_name;
804
+		}
805
+		switch ($attempt) {
806
+			case 1:
807
+				// if it's a FQCN then maybe the class is registered with a preceding \
808
+				$class_name = strpos($class_name, '\\') !== false
809
+					? '\\' . ltrim($class_name, '\\')
810
+					: $class_name;
811
+				break;
812
+			case 2:
813
+				//
814
+				$loader = $this->_dependency_map->class_loader($class_name);
815
+				if ($loader && method_exists($this, $loader)) {
816
+					return $this->{$loader}($class_name, $arguments);
817
+				}
818
+				break;
819
+			case 3:
820
+			default:
821
+				return null;
822
+		}
823
+		$attempt++;
824
+		return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
825
+	}
826
+
827
+
828
+	/**
829
+	 * instantiates, caches, and injects dependencies for classes
830
+	 *
831
+	 * @param array       $file_paths   an array of paths to folders to look in
832
+	 * @param string      $class_prefix EE  or EEM or... ???
833
+	 * @param bool|string $class_name   $class name
834
+	 * @param string      $type         file type - core? class? helper? model?
835
+	 * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
836
+	 * @param bool        $from_db      some classes are instantiated from the db
837
+	 *                                  and thus call a different method to instantiate
838
+	 * @param bool        $cache        whether to cache the instantiated object for reuse
839
+	 * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
840
+	 * @return bool|null|object null = failure to load or instantiate class object.
841
+	 *                                  object = class loaded and instantiated successfully.
842
+	 *                                  bool = fail or success when $load_only is true
843
+	 * @throws EE_Error
844
+	 * @throws ReflectionException
845
+	 * @throws InvalidInterfaceException
846
+	 * @throws InvalidDataTypeException
847
+	 * @throws InvalidArgumentException
848
+	 */
849
+	protected function _load(
850
+		$file_paths = array(),
851
+		$class_prefix = 'EE_',
852
+		$class_name = false,
853
+		$type = 'class',
854
+		$arguments = array(),
855
+		$from_db = false,
856
+		$cache = true,
857
+		$load_only = false
858
+	) {
859
+		$class_name = ltrim($class_name, '\\');
860
+		// strip php file extension
861
+		$class_name = str_replace('.php', '', trim($class_name));
862
+		// does the class have a prefix ?
863
+		if (! empty($class_prefix) && $class_prefix !== 'addon') {
864
+			// make sure $class_prefix is uppercase
865
+			$class_prefix = strtoupper(trim($class_prefix));
866
+			// add class prefix ONCE!!!
867
+			$class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
868
+		}
869
+		$class_name = $this->class_cache->getFqnForAlias($class_name);
870
+		$class_exists = class_exists($class_name, false);
871
+		// if we're only loading the class and it already exists, then let's just return true immediately
872
+		if ($load_only && $class_exists) {
873
+			return true;
874
+		}
875
+		$arguments = is_array($arguments) ? $arguments : array($arguments);
876
+		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
877
+		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
878
+		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
879
+		if ($this->_cache_on && $cache && ! $load_only) {
880
+			// return object if it's already cached
881
+			$cached_class = $this->_get_cached_class($class_name, $class_prefix, $arguments);
882
+			if ($cached_class !== null) {
883
+				return $cached_class;
884
+			}
885
+		}
886
+		// if the class doesn't already exist.. then we need to try and find the file and load it
887
+		if (! $class_exists) {
888
+			// get full path to file
889
+			$path = $this->_resolve_path($class_name, $type, $file_paths);
890
+			// load the file
891
+			$loaded = $this->_require_file($path, $class_name, $type, $file_paths);
892
+			// if we are only loading a file but NOT instantiating an object
893
+			// then return boolean for whether class was loaded or not
894
+			if ($load_only) {
895
+				return $loaded;
896
+			}
897
+			// if an object was expected but loading failed, then return nothing
898
+			if (! $loaded) {
899
+				return null;
900
+			}
901
+		}
902
+		// instantiate the requested object
903
+		$class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
904
+		if ($this->_cache_on && $cache) {
905
+			// save it for later... kinda like gum  { : $
906
+			$this->_set_cached_class(
907
+				$class_obj,
908
+				$class_name,
909
+				$class_prefix,
910
+				$from_db,
911
+				$arguments
912
+			);
913
+		}
914
+		$this->_cache_on = true;
915
+		return $class_obj;
916
+	}
917
+
918
+
919
+	/**
920
+	 * @param string $class_name
921
+	 * @param string $default have to specify something, but not anything that will conflict
922
+	 * @return mixed|string
923
+	 */
924
+	protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS')
925
+	{
926
+		return isset($this->_class_abbreviations[ $class_name ])
927
+			? $this->_class_abbreviations[ $class_name ]
928
+			: $default;
929
+	}
930
+
931
+
932
+	/**
933
+	 * attempts to find a cached version of the requested class
934
+	 * by looking in the following places:
935
+	 *        $this->{$class_abbreviation}            ie:    $this->CART
936
+	 *        $this->{$class_name}                        ie:    $this->Some_Class
937
+	 *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
938
+	 *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
939
+	 *
940
+	 * @param string $class_name
941
+	 * @param string $class_prefix
942
+	 * @param array  $arguments
943
+	 * @return mixed
944
+	 */
945
+	protected function _get_cached_class(
946
+		$class_name,
947
+		$class_prefix = '',
948
+		$arguments = array()
949
+	) {
950
+		if ($class_name === 'EE_Registry') {
951
+			return $this;
952
+		}
953
+		$class_abbreviation = $this->get_class_abbreviation($class_name);
954
+		// check if class has already been loaded, and return it if it has been
955
+		if (isset($this->{$class_abbreviation})) {
956
+			return $this->{$class_abbreviation};
957
+		}
958
+		$class_name = str_replace('\\', '_', $class_name);
959
+		if (isset($this->{$class_name})) {
960
+			return $this->{$class_name};
961
+		}
962
+		if ($class_prefix === 'addon' && isset($this->addons->{$class_name})) {
963
+			return $this->addons->{$class_name};
964
+		}
965
+		$object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments);
966
+		if (isset($this->LIB->{$object_identifier})) {
967
+			return $this->LIB->{$object_identifier};
968
+		}
969
+		foreach ($this->LIB as $key => $object) {
970
+			if (
971 971
 // request does not contain new arguments and therefore no args identifier
972
-                ! $this->object_identifier->hasArguments($object_identifier)
973
-                // but previously cached class with args was found
974
-                && $this->object_identifier->fqcnMatchesObjectIdentifier($class_name, $key)
975
-            ) {
976
-                return $object;
977
-            }
978
-        }
979
-        return null;
980
-    }
981
-
982
-
983
-    /**
984
-     * removes a cached version of the requested class
985
-     *
986
-     * @param string  $class_name
987
-     * @param boolean $addon
988
-     * @param array   $arguments
989
-     * @return boolean
990
-     */
991
-    public function clear_cached_class(
992
-        $class_name,
993
-        $addon = false,
994
-        $arguments = array()
995
-    ) {
996
-        $class_abbreviation = $this->get_class_abbreviation($class_name);
997
-        // check if class has already been loaded, and return it if it has been
998
-        if (isset($this->{$class_abbreviation})) {
999
-            $this->{$class_abbreviation} = null;
1000
-            return true;
1001
-        }
1002
-        $class_name = str_replace('\\', '_', $class_name);
1003
-        if (isset($this->{$class_name})) {
1004
-            $this->{$class_name} = null;
1005
-            return true;
1006
-        }
1007
-        if ($addon && isset($this->addons->{$class_name})) {
1008
-            unset($this->addons->{$class_name});
1009
-            return true;
1010
-        }
1011
-        $class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1012
-        if (isset($this->LIB->{$class_name})) {
1013
-            unset($this->LIB->{$class_name});
1014
-            return true;
1015
-        }
1016
-        return false;
1017
-    }
1018
-
1019
-
1020
-    /**
1021
-     * _set_cached_class
1022
-     * attempts to cache the instantiated class locally
1023
-     * in one of the following places, in the following order:
1024
-     *        $this->{class_abbreviation}   ie:    $this->CART
1025
-     *        $this->{$class_name}          ie:    $this->Some_Class
1026
-     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1027
-     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1028
-     *
1029
-     * @param object $class_obj
1030
-     * @param string $class_name
1031
-     * @param string $class_prefix
1032
-     * @param bool   $from_db
1033
-     * @param array  $arguments
1034
-     * @return void
1035
-     */
1036
-    protected function _set_cached_class(
1037
-        $class_obj,
1038
-        $class_name,
1039
-        $class_prefix = '',
1040
-        $from_db = false,
1041
-        $arguments = array()
1042
-    ) {
1043
-        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1044
-            return;
1045
-        }
1046
-        // return newly instantiated class
1047
-        $class_abbreviation = $this->get_class_abbreviation($class_name, '');
1048
-        if ($class_abbreviation) {
1049
-            $this->{$class_abbreviation} = $class_obj;
1050
-            return;
1051
-        }
1052
-        $class_name = str_replace('\\', '_', $class_name);
1053
-        if (property_exists($this, $class_name)) {
1054
-            $this->{$class_name} = $class_obj;
1055
-            return;
1056
-        }
1057
-        if ($class_prefix === 'addon') {
1058
-            $this->addons->{$class_name} = $class_obj;
1059
-            return;
1060
-        }
1061
-        if (! $from_db) {
1062
-            $class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1063
-            $this->LIB->{$class_name} = $class_obj;
1064
-        }
1065
-    }
1066
-
1067
-
1068
-    /**
1069
-     * attempts to find a full valid filepath for the requested class.
1070
-     * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
1071
-     * then returns that path if the target file has been found and is readable
1072
-     *
1073
-     * @param string $class_name
1074
-     * @param string $type
1075
-     * @param array  $file_paths
1076
-     * @return string | bool
1077
-     */
1078
-    protected function _resolve_path($class_name, $type = '', $file_paths = array())
1079
-    {
1080
-        // make sure $file_paths is an array
1081
-        $file_paths = is_array($file_paths)
1082
-            ? $file_paths
1083
-            : array($file_paths);
1084
-        // cycle thru paths
1085
-        foreach ($file_paths as $key => $file_path) {
1086
-            // convert all separators to proper /, if no filepath, then use EE_CLASSES
1087
-            $file_path = $file_path
1088
-                ? str_replace(array('/', '\\'), '/', $file_path)
1089
-                : EE_CLASSES;
1090
-            // prep file type
1091
-            $type = ! empty($type)
1092
-                ? trim($type, '.') . '.'
1093
-                : '';
1094
-            // build full file path
1095
-            $file_paths[ $key ] = rtrim($file_path, '/') . '/' . $class_name . '.' . $type . 'php';
1096
-            // does the file exist and can be read ?
1097
-            if (is_readable($file_paths[ $key ])) {
1098
-                return $file_paths[ $key ];
1099
-            }
1100
-        }
1101
-        return false;
1102
-    }
1103
-
1104
-
1105
-    /**
1106
-     * basically just performs a require_once()
1107
-     * but with some error handling
1108
-     *
1109
-     * @param  string $path
1110
-     * @param  string $class_name
1111
-     * @param  string $type
1112
-     * @param  array  $file_paths
1113
-     * @return bool
1114
-     * @throws EE_Error
1115
-     * @throws ReflectionException
1116
-     */
1117
-    protected function _require_file($path, $class_name, $type = '', $file_paths = array())
1118
-    {
1119
-        $this->resolve_legacy_class_parent($class_name);
1120
-        // don't give up! you gotta...
1121
-        try {
1122
-            // does the file exist and can it be read ?
1123
-            if (! $path) {
1124
-                // just in case the file has already been autoloaded,
1125
-                // but discrepancies in the naming schema are preventing it from
1126
-                // being loaded via one of the EE_Registry::load_*() methods,
1127
-                // then let's try one last hail mary before throwing an exception
1128
-                // and call class_exists() again, but with autoloading turned ON
1129
-                if (class_exists($class_name)) {
1130
-                    return true;
1131
-                }
1132
-                // so sorry, can't find the file
1133
-                throw new EE_Error(
1134
-                    sprintf(
1135
-                        esc_html__(
1136
-                            'The %1$s file %2$s could not be located or is not readable due to file permissions. Please ensure that the following filepath(s) are correct: %3$s',
1137
-                            'event_espresso'
1138
-                        ),
1139
-                        trim($type, '.'),
1140
-                        $class_name,
1141
-                        '<br />' . implode(',<br />', $file_paths)
1142
-                    )
1143
-                );
1144
-            }
1145
-            // get the file
1146
-            require_once($path);
1147
-            // if the class isn't already declared somewhere
1148
-            if (class_exists($class_name, false) === false) {
1149
-                // so sorry, not a class
1150
-                throw new EE_Error(
1151
-                    sprintf(
1152
-                        esc_html__(
1153
-                            'The %s file %s does not appear to contain the %s Class.',
1154
-                            'event_espresso'
1155
-                        ),
1156
-                        $type,
1157
-                        $path,
1158
-                        $class_name
1159
-                    )
1160
-                );
1161
-            }
1162
-        } catch (EE_Error $e) {
1163
-            $e->get_error();
1164
-            return false;
1165
-        }
1166
-        return true;
1167
-    }
1168
-
1169
-
1170
-    /**
1171
-     * Some of our legacy classes that extended a parent class would simply use a require() statement
1172
-     * before their class declaration in order to ensure that the parent class was loaded.
1173
-     * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1174
-     * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1175
-     *
1176
-     * @param string $class_name
1177
-     */
1178
-    protected function resolve_legacy_class_parent($class_name = '')
1179
-    {
1180
-        try {
1181
-            $legacy_parent_class_map = array(
1182
-                'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php',
1183
-            );
1184
-            if (isset($legacy_parent_class_map[ $class_name ])) {
1185
-                require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ];
1186
-            }
1187
-        } catch (Exception $exception) {
1188
-        }
1189
-    }
1190
-
1191
-
1192
-    /**
1193
-     * _create_object
1194
-     * Attempts to instantiate the requested class via any of the
1195
-     * commonly used instantiation methods employed throughout EE.
1196
-     * The priority for instantiation is as follows:
1197
-     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1198
-     *        - model objects via their 'new_instance_from_db' method
1199
-     *        - model objects via their 'new_instance' method
1200
-     *        - "singleton" classes" via their 'instance' method
1201
-     *    - standard instantiable classes via their __constructor
1202
-     * Prior to instantiation, if the classname exists in the dependency_map,
1203
-     * then the constructor for the requested class will be examined to determine
1204
-     * if any dependencies exist, and if they can be injected.
1205
-     * If so, then those classes will be added to the array of arguments passed to the constructor
1206
-     *
1207
-     * @param string $class_name
1208
-     * @param array  $arguments
1209
-     * @param string $type
1210
-     * @param bool   $from_db
1211
-     * @return null|object|bool
1212
-     * @throws InvalidArgumentException
1213
-     * @throws InvalidInterfaceException
1214
-     * @throws EE_Error
1215
-     * @throws ReflectionException
1216
-     * @throws InvalidDataTypeException
1217
-     */
1218
-    protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
1219
-    {
1220
-        // create reflection
1221
-        $reflector = $this->mirror->getReflectionClass($class_name);
1222
-        // make sure arguments are an array
1223
-        $arguments = is_array($arguments)
1224
-            ? $arguments
1225
-            : array($arguments);
1226
-        // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1227
-        // else wrap it in an additional array so that it doesn't get split into multiple parameters
1228
-        $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1229
-            ? $arguments
1230
-            : array($arguments);
1231
-        // attempt to inject dependencies ?
1232
-        if ($this->_dependency_map->has($class_name)) {
1233
-            $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1234
-        }
1235
-        // instantiate the class if possible
1236
-        if ($reflector->isAbstract()) {
1237
-            // nothing to instantiate, loading file was enough
1238
-            // does not throw an exception so $instantiation_mode is unused
1239
-            // $instantiation_mode = "1) no constructor abstract class";
1240
-            return true;
1241
-        }
1242
-        if (
1243
-            empty($arguments)
1244
-            && $this->mirror->getConstructorFromReflection($reflector) === null
1245
-            && $reflector->isInstantiable()
1246
-        ) {
1247
-            // no constructor = static methods only... nothing to instantiate, loading file was enough
1248
-            // $instantiation_mode = "2) no constructor but instantiable";
1249
-            return $reflector->newInstance();
1250
-        }
1251
-        if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1252
-            // $instantiation_mode = "3) new_instance_from_db()";
1253
-            return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1254
-        }
1255
-        if (method_exists($class_name, 'new_instance')) {
1256
-            // $instantiation_mode = "4) new_instance()";
1257
-            return call_user_func_array(array($class_name, 'new_instance'), $arguments);
1258
-        }
1259
-        if (method_exists($class_name, 'instance')) {
1260
-            // $instantiation_mode = "5) instance()";
1261
-            return call_user_func_array(array($class_name, 'instance'), $arguments);
1262
-        }
1263
-        if ($reflector->isInstantiable()) {
1264
-            $args_passed_count = count($arguments);
1265
-            $args_required_count = count($this->mirror->getRequiredParameters($class_name));
1266
-            if ($args_passed_count < $args_required_count) {
1267
-                throw new RuntimeException(
1268
-                    sprintf(
1269
-                        __(
1270
-                            'Invalid arguments supplied for the %1$s class, %2$s were required but %3$s were passed.',
1271
-                            'event_espresso'
1272
-                        ),
1273
-                        $class_name,
1274
-                        $args_required_count,
1275
-                        $args_passed_count
1276
-                    )
1277
-                );
1278
-            }
1279
-            // $instantiation_mode = "6) constructor";
1280
-            return $reflector->newInstanceArgs($arguments);
1281
-        }
1282
-        // heh ? something's not right !
1283
-        throw new EE_Error(
1284
-            sprintf(
1285
-                __('The %s file %s could not be instantiated.', 'event_espresso'),
1286
-                $type,
1287
-                $class_name
1288
-            )
1289
-        );
1290
-    }
1291
-
1292
-
1293
-    /**
1294
-     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1295
-     * @param array $array
1296
-     * @return bool
1297
-     */
1298
-    protected function _array_is_numerically_and_sequentially_indexed(array $array)
1299
-    {
1300
-        return ! empty($array)
1301
-            ? array_keys($array) === range(0, count($array) - 1)
1302
-            : true;
1303
-    }
1304
-
1305
-
1306
-    /**
1307
-     * _resolve_dependencies
1308
-     * examines the constructor for the requested class to determine
1309
-     * if any dependencies exist, and if they can be injected.
1310
-     * If so, then those classes will be added to the array of arguments passed to the constructor
1311
-     * PLZ NOTE: this is achieved by type hinting the constructor params
1312
-     * For example:
1313
-     *        if attempting to load a class "Foo" with the following constructor:
1314
-     *        __construct( Bar $bar_class, Fighter $grohl_class )
1315
-     *        then $bar_class and $grohl_class will be added to the $arguments array,
1316
-     *        but only IF they are NOT already present in the incoming arguments array,
1317
-     *        and the correct classes can be loaded
1318
-     *
1319
-     * @param ReflectionClass $reflector
1320
-     * @param string          $class_name
1321
-     * @param array           $arguments
1322
-     * @return array
1323
-     * @throws InvalidArgumentException
1324
-     * @throws InvalidDataTypeException
1325
-     * @throws InvalidInterfaceException
1326
-     * @throws ReflectionException
1327
-     */
1328
-    protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, array $arguments = array())
1329
-    {
1330
-        // let's examine the constructor
1331
-        $constructor = $this->mirror->getConstructorFromReflection($reflector);
1332
-        // whu? huh? nothing?
1333
-        if (! $constructor) {
1334
-            return $arguments;
1335
-        }
1336
-        // get constructor parameters
1337
-        $params = $this->mirror->getParametersFromReflection($reflector);
1338
-        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1339
-        $argument_keys = array_keys($arguments);
1340
-        // now loop thru all of the constructors expected parameters
1341
-        foreach ($params as $index => $param) {
1342
-            try {
1343
-                // is this a dependency for a specific class ?
1344
-                $param_class = $this->mirror->getParameterClassName($param, $class_name, $index);
1345
-            } catch (ReflectionException $exception) {
1346
-                // uh-oh... most likely a legacy class that has not been autoloaded
1347
-                // let's try to derive the classname from what we have now
1348
-                // and hope that the property var name is close to the class name
1349
-                $param_class = $param->getName();
1350
-                $param_class = str_replace('_', ' ', $param_class);
1351
-                $param_class = ucwords($param_class);
1352
-                $param_class = str_replace(' ', '_', $param_class);
1353
-            }
1354
-            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1355
-            $param_class = $this->class_cache->isAlias($param_class, $class_name)
1356
-                ? $this->class_cache->getFqnForAlias($param_class, $class_name)
1357
-                : $param_class;
1358
-            if (
972
+				! $this->object_identifier->hasArguments($object_identifier)
973
+				// but previously cached class with args was found
974
+				&& $this->object_identifier->fqcnMatchesObjectIdentifier($class_name, $key)
975
+			) {
976
+				return $object;
977
+			}
978
+		}
979
+		return null;
980
+	}
981
+
982
+
983
+	/**
984
+	 * removes a cached version of the requested class
985
+	 *
986
+	 * @param string  $class_name
987
+	 * @param boolean $addon
988
+	 * @param array   $arguments
989
+	 * @return boolean
990
+	 */
991
+	public function clear_cached_class(
992
+		$class_name,
993
+		$addon = false,
994
+		$arguments = array()
995
+	) {
996
+		$class_abbreviation = $this->get_class_abbreviation($class_name);
997
+		// check if class has already been loaded, and return it if it has been
998
+		if (isset($this->{$class_abbreviation})) {
999
+			$this->{$class_abbreviation} = null;
1000
+			return true;
1001
+		}
1002
+		$class_name = str_replace('\\', '_', $class_name);
1003
+		if (isset($this->{$class_name})) {
1004
+			$this->{$class_name} = null;
1005
+			return true;
1006
+		}
1007
+		if ($addon && isset($this->addons->{$class_name})) {
1008
+			unset($this->addons->{$class_name});
1009
+			return true;
1010
+		}
1011
+		$class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1012
+		if (isset($this->LIB->{$class_name})) {
1013
+			unset($this->LIB->{$class_name});
1014
+			return true;
1015
+		}
1016
+		return false;
1017
+	}
1018
+
1019
+
1020
+	/**
1021
+	 * _set_cached_class
1022
+	 * attempts to cache the instantiated class locally
1023
+	 * in one of the following places, in the following order:
1024
+	 *        $this->{class_abbreviation}   ie:    $this->CART
1025
+	 *        $this->{$class_name}          ie:    $this->Some_Class
1026
+	 *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1027
+	 *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1028
+	 *
1029
+	 * @param object $class_obj
1030
+	 * @param string $class_name
1031
+	 * @param string $class_prefix
1032
+	 * @param bool   $from_db
1033
+	 * @param array  $arguments
1034
+	 * @return void
1035
+	 */
1036
+	protected function _set_cached_class(
1037
+		$class_obj,
1038
+		$class_name,
1039
+		$class_prefix = '',
1040
+		$from_db = false,
1041
+		$arguments = array()
1042
+	) {
1043
+		if ($class_name === 'EE_Registry' || empty($class_obj)) {
1044
+			return;
1045
+		}
1046
+		// return newly instantiated class
1047
+		$class_abbreviation = $this->get_class_abbreviation($class_name, '');
1048
+		if ($class_abbreviation) {
1049
+			$this->{$class_abbreviation} = $class_obj;
1050
+			return;
1051
+		}
1052
+		$class_name = str_replace('\\', '_', $class_name);
1053
+		if (property_exists($this, $class_name)) {
1054
+			$this->{$class_name} = $class_obj;
1055
+			return;
1056
+		}
1057
+		if ($class_prefix === 'addon') {
1058
+			$this->addons->{$class_name} = $class_obj;
1059
+			return;
1060
+		}
1061
+		if (! $from_db) {
1062
+			$class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1063
+			$this->LIB->{$class_name} = $class_obj;
1064
+		}
1065
+	}
1066
+
1067
+
1068
+	/**
1069
+	 * attempts to find a full valid filepath for the requested class.
1070
+	 * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
1071
+	 * then returns that path if the target file has been found and is readable
1072
+	 *
1073
+	 * @param string $class_name
1074
+	 * @param string $type
1075
+	 * @param array  $file_paths
1076
+	 * @return string | bool
1077
+	 */
1078
+	protected function _resolve_path($class_name, $type = '', $file_paths = array())
1079
+	{
1080
+		// make sure $file_paths is an array
1081
+		$file_paths = is_array($file_paths)
1082
+			? $file_paths
1083
+			: array($file_paths);
1084
+		// cycle thru paths
1085
+		foreach ($file_paths as $key => $file_path) {
1086
+			// convert all separators to proper /, if no filepath, then use EE_CLASSES
1087
+			$file_path = $file_path
1088
+				? str_replace(array('/', '\\'), '/', $file_path)
1089
+				: EE_CLASSES;
1090
+			// prep file type
1091
+			$type = ! empty($type)
1092
+				? trim($type, '.') . '.'
1093
+				: '';
1094
+			// build full file path
1095
+			$file_paths[ $key ] = rtrim($file_path, '/') . '/' . $class_name . '.' . $type . 'php';
1096
+			// does the file exist and can be read ?
1097
+			if (is_readable($file_paths[ $key ])) {
1098
+				return $file_paths[ $key ];
1099
+			}
1100
+		}
1101
+		return false;
1102
+	}
1103
+
1104
+
1105
+	/**
1106
+	 * basically just performs a require_once()
1107
+	 * but with some error handling
1108
+	 *
1109
+	 * @param  string $path
1110
+	 * @param  string $class_name
1111
+	 * @param  string $type
1112
+	 * @param  array  $file_paths
1113
+	 * @return bool
1114
+	 * @throws EE_Error
1115
+	 * @throws ReflectionException
1116
+	 */
1117
+	protected function _require_file($path, $class_name, $type = '', $file_paths = array())
1118
+	{
1119
+		$this->resolve_legacy_class_parent($class_name);
1120
+		// don't give up! you gotta...
1121
+		try {
1122
+			// does the file exist and can it be read ?
1123
+			if (! $path) {
1124
+				// just in case the file has already been autoloaded,
1125
+				// but discrepancies in the naming schema are preventing it from
1126
+				// being loaded via one of the EE_Registry::load_*() methods,
1127
+				// then let's try one last hail mary before throwing an exception
1128
+				// and call class_exists() again, but with autoloading turned ON
1129
+				if (class_exists($class_name)) {
1130
+					return true;
1131
+				}
1132
+				// so sorry, can't find the file
1133
+				throw new EE_Error(
1134
+					sprintf(
1135
+						esc_html__(
1136
+							'The %1$s file %2$s could not be located or is not readable due to file permissions. Please ensure that the following filepath(s) are correct: %3$s',
1137
+							'event_espresso'
1138
+						),
1139
+						trim($type, '.'),
1140
+						$class_name,
1141
+						'<br />' . implode(',<br />', $file_paths)
1142
+					)
1143
+				);
1144
+			}
1145
+			// get the file
1146
+			require_once($path);
1147
+			// if the class isn't already declared somewhere
1148
+			if (class_exists($class_name, false) === false) {
1149
+				// so sorry, not a class
1150
+				throw new EE_Error(
1151
+					sprintf(
1152
+						esc_html__(
1153
+							'The %s file %s does not appear to contain the %s Class.',
1154
+							'event_espresso'
1155
+						),
1156
+						$type,
1157
+						$path,
1158
+						$class_name
1159
+					)
1160
+				);
1161
+			}
1162
+		} catch (EE_Error $e) {
1163
+			$e->get_error();
1164
+			return false;
1165
+		}
1166
+		return true;
1167
+	}
1168
+
1169
+
1170
+	/**
1171
+	 * Some of our legacy classes that extended a parent class would simply use a require() statement
1172
+	 * before their class declaration in order to ensure that the parent class was loaded.
1173
+	 * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1174
+	 * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1175
+	 *
1176
+	 * @param string $class_name
1177
+	 */
1178
+	protected function resolve_legacy_class_parent($class_name = '')
1179
+	{
1180
+		try {
1181
+			$legacy_parent_class_map = array(
1182
+				'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php',
1183
+			);
1184
+			if (isset($legacy_parent_class_map[ $class_name ])) {
1185
+				require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ];
1186
+			}
1187
+		} catch (Exception $exception) {
1188
+		}
1189
+	}
1190
+
1191
+
1192
+	/**
1193
+	 * _create_object
1194
+	 * Attempts to instantiate the requested class via any of the
1195
+	 * commonly used instantiation methods employed throughout EE.
1196
+	 * The priority for instantiation is as follows:
1197
+	 *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1198
+	 *        - model objects via their 'new_instance_from_db' method
1199
+	 *        - model objects via their 'new_instance' method
1200
+	 *        - "singleton" classes" via their 'instance' method
1201
+	 *    - standard instantiable classes via their __constructor
1202
+	 * Prior to instantiation, if the classname exists in the dependency_map,
1203
+	 * then the constructor for the requested class will be examined to determine
1204
+	 * if any dependencies exist, and if they can be injected.
1205
+	 * If so, then those classes will be added to the array of arguments passed to the constructor
1206
+	 *
1207
+	 * @param string $class_name
1208
+	 * @param array  $arguments
1209
+	 * @param string $type
1210
+	 * @param bool   $from_db
1211
+	 * @return null|object|bool
1212
+	 * @throws InvalidArgumentException
1213
+	 * @throws InvalidInterfaceException
1214
+	 * @throws EE_Error
1215
+	 * @throws ReflectionException
1216
+	 * @throws InvalidDataTypeException
1217
+	 */
1218
+	protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
1219
+	{
1220
+		// create reflection
1221
+		$reflector = $this->mirror->getReflectionClass($class_name);
1222
+		// make sure arguments are an array
1223
+		$arguments = is_array($arguments)
1224
+			? $arguments
1225
+			: array($arguments);
1226
+		// and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1227
+		// else wrap it in an additional array so that it doesn't get split into multiple parameters
1228
+		$arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1229
+			? $arguments
1230
+			: array($arguments);
1231
+		// attempt to inject dependencies ?
1232
+		if ($this->_dependency_map->has($class_name)) {
1233
+			$arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1234
+		}
1235
+		// instantiate the class if possible
1236
+		if ($reflector->isAbstract()) {
1237
+			// nothing to instantiate, loading file was enough
1238
+			// does not throw an exception so $instantiation_mode is unused
1239
+			// $instantiation_mode = "1) no constructor abstract class";
1240
+			return true;
1241
+		}
1242
+		if (
1243
+			empty($arguments)
1244
+			&& $this->mirror->getConstructorFromReflection($reflector) === null
1245
+			&& $reflector->isInstantiable()
1246
+		) {
1247
+			// no constructor = static methods only... nothing to instantiate, loading file was enough
1248
+			// $instantiation_mode = "2) no constructor but instantiable";
1249
+			return $reflector->newInstance();
1250
+		}
1251
+		if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1252
+			// $instantiation_mode = "3) new_instance_from_db()";
1253
+			return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1254
+		}
1255
+		if (method_exists($class_name, 'new_instance')) {
1256
+			// $instantiation_mode = "4) new_instance()";
1257
+			return call_user_func_array(array($class_name, 'new_instance'), $arguments);
1258
+		}
1259
+		if (method_exists($class_name, 'instance')) {
1260
+			// $instantiation_mode = "5) instance()";
1261
+			return call_user_func_array(array($class_name, 'instance'), $arguments);
1262
+		}
1263
+		if ($reflector->isInstantiable()) {
1264
+			$args_passed_count = count($arguments);
1265
+			$args_required_count = count($this->mirror->getRequiredParameters($class_name));
1266
+			if ($args_passed_count < $args_required_count) {
1267
+				throw new RuntimeException(
1268
+					sprintf(
1269
+						__(
1270
+							'Invalid arguments supplied for the %1$s class, %2$s were required but %3$s were passed.',
1271
+							'event_espresso'
1272
+						),
1273
+						$class_name,
1274
+						$args_required_count,
1275
+						$args_passed_count
1276
+					)
1277
+				);
1278
+			}
1279
+			// $instantiation_mode = "6) constructor";
1280
+			return $reflector->newInstanceArgs($arguments);
1281
+		}
1282
+		// heh ? something's not right !
1283
+		throw new EE_Error(
1284
+			sprintf(
1285
+				__('The %s file %s could not be instantiated.', 'event_espresso'),
1286
+				$type,
1287
+				$class_name
1288
+			)
1289
+		);
1290
+	}
1291
+
1292
+
1293
+	/**
1294
+	 * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1295
+	 * @param array $array
1296
+	 * @return bool
1297
+	 */
1298
+	protected function _array_is_numerically_and_sequentially_indexed(array $array)
1299
+	{
1300
+		return ! empty($array)
1301
+			? array_keys($array) === range(0, count($array) - 1)
1302
+			: true;
1303
+	}
1304
+
1305
+
1306
+	/**
1307
+	 * _resolve_dependencies
1308
+	 * examines the constructor for the requested class to determine
1309
+	 * if any dependencies exist, and if they can be injected.
1310
+	 * If so, then those classes will be added to the array of arguments passed to the constructor
1311
+	 * PLZ NOTE: this is achieved by type hinting the constructor params
1312
+	 * For example:
1313
+	 *        if attempting to load a class "Foo" with the following constructor:
1314
+	 *        __construct( Bar $bar_class, Fighter $grohl_class )
1315
+	 *        then $bar_class and $grohl_class will be added to the $arguments array,
1316
+	 *        but only IF they are NOT already present in the incoming arguments array,
1317
+	 *        and the correct classes can be loaded
1318
+	 *
1319
+	 * @param ReflectionClass $reflector
1320
+	 * @param string          $class_name
1321
+	 * @param array           $arguments
1322
+	 * @return array
1323
+	 * @throws InvalidArgumentException
1324
+	 * @throws InvalidDataTypeException
1325
+	 * @throws InvalidInterfaceException
1326
+	 * @throws ReflectionException
1327
+	 */
1328
+	protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, array $arguments = array())
1329
+	{
1330
+		// let's examine the constructor
1331
+		$constructor = $this->mirror->getConstructorFromReflection($reflector);
1332
+		// whu? huh? nothing?
1333
+		if (! $constructor) {
1334
+			return $arguments;
1335
+		}
1336
+		// get constructor parameters
1337
+		$params = $this->mirror->getParametersFromReflection($reflector);
1338
+		// and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1339
+		$argument_keys = array_keys($arguments);
1340
+		// now loop thru all of the constructors expected parameters
1341
+		foreach ($params as $index => $param) {
1342
+			try {
1343
+				// is this a dependency for a specific class ?
1344
+				$param_class = $this->mirror->getParameterClassName($param, $class_name, $index);
1345
+			} catch (ReflectionException $exception) {
1346
+				// uh-oh... most likely a legacy class that has not been autoloaded
1347
+				// let's try to derive the classname from what we have now
1348
+				// and hope that the property var name is close to the class name
1349
+				$param_class = $param->getName();
1350
+				$param_class = str_replace('_', ' ', $param_class);
1351
+				$param_class = ucwords($param_class);
1352
+				$param_class = str_replace(' ', '_', $param_class);
1353
+			}
1354
+			// BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1355
+			$param_class = $this->class_cache->isAlias($param_class, $class_name)
1356
+				? $this->class_cache->getFqnForAlias($param_class, $class_name)
1357
+				: $param_class;
1358
+			if (
1359 1359
 // param is not even a class
1360
-                $param_class === null
1361
-                // and something already exists in the incoming arguments for this param
1362
-                && array_key_exists($index, $argument_keys)
1363
-                && array_key_exists($argument_keys[ $index ], $arguments)
1364
-            ) {
1365
-                // so let's skip this argument and move on to the next
1366
-                continue;
1367
-            }
1368
-            if (
1360
+				$param_class === null
1361
+				// and something already exists in the incoming arguments for this param
1362
+				&& array_key_exists($index, $argument_keys)
1363
+				&& array_key_exists($argument_keys[ $index ], $arguments)
1364
+			) {
1365
+				// so let's skip this argument and move on to the next
1366
+				continue;
1367
+			}
1368
+			if (
1369 1369
 // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1370
-                $param_class !== null
1371
-                && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
1372
-                && $arguments[ $argument_keys[ $index ] ] instanceof $param_class
1373
-            ) {
1374
-                // skip this argument and move on to the next
1375
-                continue;
1376
-            }
1377
-            if (
1370
+				$param_class !== null
1371
+				&& isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
1372
+				&& $arguments[ $argument_keys[ $index ] ] instanceof $param_class
1373
+			) {
1374
+				// skip this argument and move on to the next
1375
+				continue;
1376
+			}
1377
+			if (
1378 1378
 // parameter is type hinted as a class, and should be injected
1379
-                $param_class !== null
1380
-                && $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1381
-            ) {
1382
-                $arguments = $this->_resolve_dependency(
1383
-                    $class_name,
1384
-                    $param_class,
1385
-                    $arguments,
1386
-                    $index
1387
-                );
1388
-            }
1389
-            if (empty($arguments[ $index ])) {
1390
-                $arguments[ $index ] = $this->mirror->getParameterDefaultValue(
1391
-                    $param,
1392
-                    $class_name,
1393
-                    $index
1394
-                );
1395
-            }
1396
-        }
1397
-        return $arguments;
1398
-    }
1399
-
1400
-
1401
-    /**
1402
-     * @param string $class_name
1403
-     * @param string $param_class
1404
-     * @param array  $arguments
1405
-     * @param mixed  $index
1406
-     * @return array
1407
-     * @throws InvalidArgumentException
1408
-     * @throws InvalidInterfaceException
1409
-     * @throws InvalidDataTypeException
1410
-     */
1411
-    protected function _resolve_dependency($class_name, $param_class, $arguments, $index)
1412
-    {
1413
-        $dependency = null;
1414
-        // should dependency be loaded from cache ?
1415
-        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1416
-            $class_name,
1417
-            $param_class
1418
-        );
1419
-        $cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1420
-        // we might have a dependency...
1421
-        // let's MAYBE try and find it in our cache if that's what's been requested
1422
-        $cached_class = $cache_on
1423
-            ? $this->_get_cached_class($param_class)
1424
-            : null;
1425
-        // and grab it if it exists
1426
-        if ($cached_class instanceof $param_class) {
1427
-            $dependency = $cached_class;
1428
-        } elseif ($param_class !== $class_name) {
1429
-            // obtain the loader method from the dependency map
1430
-            $loader = $this->_dependency_map->class_loader($param_class);
1431
-            // is loader a custom closure ?
1432
-            if ($loader instanceof Closure) {
1433
-                $dependency = $loader($arguments);
1434
-            } else {
1435
-                // set the cache on property for the recursive loading call
1436
-                $this->_cache_on = $cache_on;
1437
-                // if not, then let's try and load it via the registry
1438
-                if ($loader && method_exists($this, $loader)) {
1439
-                    $dependency = $this->{$loader}($param_class);
1440
-                } else {
1441
-                    $dependency = LoaderFactory::getLoader()->load(
1442
-                        $param_class,
1443
-                        array(),
1444
-                        $cache_on
1445
-                    );
1446
-                }
1447
-            }
1448
-        }
1449
-        // did we successfully find the correct dependency ?
1450
-        if ($dependency instanceof $param_class) {
1451
-            // then let's inject it into the incoming array of arguments at the correct location
1452
-            $arguments[ $index ] = $dependency;
1453
-        }
1454
-        return $arguments;
1455
-    }
1456
-
1457
-
1458
-    /**
1459
-     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1460
-     *
1461
-     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1462
-     *                          in the EE_Dependency_Map::$_class_loaders array,
1463
-     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1464
-     * @param array  $arguments
1465
-     * @return object
1466
-     */
1467
-    public static function factory($classname, $arguments = array())
1468
-    {
1469
-        $loader = self::instance()->_dependency_map->class_loader($classname);
1470
-        if ($loader instanceof Closure) {
1471
-            return $loader($arguments);
1472
-        }
1473
-        if (method_exists(self::instance(), $loader)) {
1474
-            return self::instance()->{$loader}($classname, $arguments);
1475
-        }
1476
-        return null;
1477
-    }
1478
-
1479
-
1480
-    /**
1481
-     * Gets the addon by its class name
1482
-     *
1483
-     * @param string $class_name
1484
-     * @return EE_Addon
1485
-     */
1486
-    public function getAddon($class_name)
1487
-    {
1488
-        $class_name = str_replace('\\', '_', $class_name);
1489
-        if (isset($this->addons->{$class_name})) {
1490
-            return $this->addons->{$class_name};
1491
-        } else {
1492
-            return null;
1493
-        }
1494
-    }
1495
-
1496
-
1497
-    /**
1498
-     * removes the addon from the internal cache
1499
-     *
1500
-     * @param string $class_name
1501
-     * @return void
1502
-     */
1503
-    public function removeAddon($class_name)
1504
-    {
1505
-        $class_name = str_replace('\\', '_', $class_name);
1506
-        unset($this->addons->{$class_name});
1507
-    }
1508
-
1509
-
1510
-    /**
1511
-     * Gets the addon by its name/slug (not classname. For that, just
1512
-     * use the get_addon() method above
1513
-     *
1514
-     * @param string $name
1515
-     * @return EE_Addon
1516
-     */
1517
-    public function get_addon_by_name($name)
1518
-    {
1519
-        foreach ($this->addons as $addon) {
1520
-            if ($addon->name() === $name) {
1521
-                return $addon;
1522
-            }
1523
-        }
1524
-        return null;
1525
-    }
1526
-
1527
-
1528
-    /**
1529
-     * Gets an array of all the registered addons, where the keys are their names.
1530
-     * (ie, what each returns for their name() function)
1531
-     * They're already available on EE_Registry::instance()->addons as properties,
1532
-     * where each property's name is the addon's classname,
1533
-     * So if you just want to get the addon by classname,
1534
-     * OR use the get_addon() method above.
1535
-     * PLEASE  NOTE:
1536
-     * addons with Fully Qualified Class Names
1537
-     * have had the namespace separators converted to underscores,
1538
-     * so a classname like Fully\Qualified\ClassName
1539
-     * would have been converted to Fully_Qualified_ClassName
1540
-     *
1541
-     * @return EE_Addon[] where the KEYS are the addon's name()
1542
-     */
1543
-    public function get_addons_by_name()
1544
-    {
1545
-        $addons = array();
1546
-        foreach ($this->addons as $addon) {
1547
-            $addons[ $addon->name() ] = $addon;
1548
-        }
1549
-        return $addons;
1550
-    }
1551
-
1552
-
1553
-    /**
1554
-     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1555
-     * a stale copy of it around
1556
-     *
1557
-     * @param string $model_name
1558
-     * @return \EEM_Base
1559
-     * @throws \EE_Error
1560
-     */
1561
-    public function reset_model($model_name)
1562
-    {
1563
-        $model_class_name = strpos($model_name, 'EEM_') !== 0
1564
-            ? "EEM_{$model_name}"
1565
-            : $model_name;
1566
-        if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1567
-            return null;
1568
-        }
1569
-        // get that model reset it and make sure we nuke the old reference to it
1570
-        if (
1571
-            $this->LIB->{$model_class_name} instanceof $model_class_name
1572
-            && is_callable(
1573
-                array($model_class_name, 'reset')
1574
-            )
1575
-        ) {
1576
-            $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1577
-        } else {
1578
-            throw new EE_Error(
1579
-                sprintf(
1580
-                    esc_html__('Model %s does not have a method "reset"', 'event_espresso'),
1581
-                    $model_name
1582
-                )
1583
-            );
1584
-        }
1585
-        return $this->LIB->{$model_class_name};
1586
-    }
1587
-
1588
-
1589
-    /**
1590
-     * Resets the registry.
1591
-     * The criteria for what gets reset is based on what can be shared between sites on the same request when
1592
-     * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1593
-     * - $_dependency_map
1594
-     * - $_class_abbreviations
1595
-     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1596
-     * - $REQ:  Still on the same request so no need to change.
1597
-     * - $CAP: There is no site specific state in the EE_Capability class.
1598
-     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1599
-     * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1600
-     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1601
-     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1602
-     *             switch or on the restore.
1603
-     * - $modules
1604
-     * - $shortcodes
1605
-     * - $widgets
1606
-     *
1607
-     * @param boolean $hard             [deprecated]
1608
-     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1609
-     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1610
-     *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1611
-     * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1612
-     *                                  client
1613
-     *                                  code instead can just change the model context to a different blog id if
1614
-     *                                  necessary
1615
-     * @return EE_Registry
1616
-     * @throws InvalidInterfaceException
1617
-     * @throws InvalidDataTypeException
1618
-     * @throws EE_Error
1619
-     * @throws ReflectionException
1620
-     * @throws InvalidArgumentException
1621
-     */
1622
-    public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1623
-    {
1624
-        $instance = self::instance();
1625
-        $instance->_cache_on = true;
1626
-        // reset some "special" classes
1627
-        EEH_Activation::reset();
1628
-        EEH_DTT_Helper::resetDefaultTimezoneString();
1629
-
1630
-        $hard = apply_filters('FHEE__EE_Registry__reset__hard', $hard);
1631
-        $instance->CFG = EE_Config::reset($hard, $reinstantiate);
1632
-        $instance->CART = null;
1633
-        $instance->MRM = null;
1634
-        $instance->AssetsRegistry = LoaderFactory::getLoader()->getShared(
1635
-            'EventEspresso\core\services\assets\Registry'
1636
-        );
1637
-        // messages reset
1638
-        EED_Messages::reset();
1639
-        // handle of objects cached on LIB
1640
-        foreach (array('LIB', 'modules') as $cache) {
1641
-            foreach ($instance->{$cache} as $class_name => $class) {
1642
-                if (self::_reset_and_unset_object($class, $reset_models)) {
1643
-                    unset($instance->{$cache}->{$class_name});
1644
-                }
1645
-            }
1646
-        }
1647
-        return $instance;
1648
-    }
1649
-
1650
-
1651
-    /**
1652
-     * if passed object implements ResettableInterface, then call it's reset() method
1653
-     * if passed object implements InterminableInterface, then return false,
1654
-     * to indicate that it should NOT be cleared from the Registry cache
1655
-     *
1656
-     * @param      $object
1657
-     * @param bool $reset_models
1658
-     * @return bool returns true if cached object should be unset
1659
-     */
1660
-    private static function _reset_and_unset_object($object, $reset_models)
1661
-    {
1662
-        if (! is_object($object)) {
1663
-            // don't unset anything that's not an object
1664
-            return false;
1665
-        }
1666
-        if ($object instanceof EED_Module) {
1667
-            $object::reset();
1668
-            // don't unset modules
1669
-            return false;
1670
-        }
1671
-        if ($object instanceof ResettableInterface) {
1672
-            if ($object instanceof EEM_Base) {
1673
-                if ($reset_models) {
1674
-                    $object->reset();
1675
-                    return true;
1676
-                }
1677
-                return false;
1678
-            }
1679
-            $object->reset();
1680
-            return true;
1681
-        }
1682
-        if (! $object instanceof InterminableInterface) {
1683
-            return true;
1684
-        }
1685
-        return false;
1686
-    }
1687
-
1688
-
1689
-    /**
1690
-     * Gets all the custom post type models defined
1691
-     *
1692
-     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1693
-     */
1694
-    public function cpt_models()
1695
-    {
1696
-        $cpt_models = array();
1697
-        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1698
-            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1699
-                $cpt_models[ $short_name ] = $classname;
1700
-            }
1701
-        }
1702
-        return $cpt_models;
1703
-    }
1704
-
1705
-
1706
-    /**
1707
-     * @return \EE_Config
1708
-     */
1709
-    public static function CFG()
1710
-    {
1711
-        return self::instance()->CFG;
1712
-    }
1713
-
1714
-
1715
-    /**
1716
-     * @deprecated 4.9.62.p
1717
-     * @param string $class_name
1718
-     * @return ReflectionClass
1719
-     * @throws ReflectionException
1720
-     * @throws InvalidDataTypeException
1721
-     */
1722
-    public function get_ReflectionClass($class_name)
1723
-    {
1724
-        return $this->mirror->getReflectionClass($class_name);
1725
-    }
1379
+				$param_class !== null
1380
+				&& $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1381
+			) {
1382
+				$arguments = $this->_resolve_dependency(
1383
+					$class_name,
1384
+					$param_class,
1385
+					$arguments,
1386
+					$index
1387
+				);
1388
+			}
1389
+			if (empty($arguments[ $index ])) {
1390
+				$arguments[ $index ] = $this->mirror->getParameterDefaultValue(
1391
+					$param,
1392
+					$class_name,
1393
+					$index
1394
+				);
1395
+			}
1396
+		}
1397
+		return $arguments;
1398
+	}
1399
+
1400
+
1401
+	/**
1402
+	 * @param string $class_name
1403
+	 * @param string $param_class
1404
+	 * @param array  $arguments
1405
+	 * @param mixed  $index
1406
+	 * @return array
1407
+	 * @throws InvalidArgumentException
1408
+	 * @throws InvalidInterfaceException
1409
+	 * @throws InvalidDataTypeException
1410
+	 */
1411
+	protected function _resolve_dependency($class_name, $param_class, $arguments, $index)
1412
+	{
1413
+		$dependency = null;
1414
+		// should dependency be loaded from cache ?
1415
+		$cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1416
+			$class_name,
1417
+			$param_class
1418
+		);
1419
+		$cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1420
+		// we might have a dependency...
1421
+		// let's MAYBE try and find it in our cache if that's what's been requested
1422
+		$cached_class = $cache_on
1423
+			? $this->_get_cached_class($param_class)
1424
+			: null;
1425
+		// and grab it if it exists
1426
+		if ($cached_class instanceof $param_class) {
1427
+			$dependency = $cached_class;
1428
+		} elseif ($param_class !== $class_name) {
1429
+			// obtain the loader method from the dependency map
1430
+			$loader = $this->_dependency_map->class_loader($param_class);
1431
+			// is loader a custom closure ?
1432
+			if ($loader instanceof Closure) {
1433
+				$dependency = $loader($arguments);
1434
+			} else {
1435
+				// set the cache on property for the recursive loading call
1436
+				$this->_cache_on = $cache_on;
1437
+				// if not, then let's try and load it via the registry
1438
+				if ($loader && method_exists($this, $loader)) {
1439
+					$dependency = $this->{$loader}($param_class);
1440
+				} else {
1441
+					$dependency = LoaderFactory::getLoader()->load(
1442
+						$param_class,
1443
+						array(),
1444
+						$cache_on
1445
+					);
1446
+				}
1447
+			}
1448
+		}
1449
+		// did we successfully find the correct dependency ?
1450
+		if ($dependency instanceof $param_class) {
1451
+			// then let's inject it into the incoming array of arguments at the correct location
1452
+			$arguments[ $index ] = $dependency;
1453
+		}
1454
+		return $arguments;
1455
+	}
1456
+
1457
+
1458
+	/**
1459
+	 * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1460
+	 *
1461
+	 * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1462
+	 *                          in the EE_Dependency_Map::$_class_loaders array,
1463
+	 *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1464
+	 * @param array  $arguments
1465
+	 * @return object
1466
+	 */
1467
+	public static function factory($classname, $arguments = array())
1468
+	{
1469
+		$loader = self::instance()->_dependency_map->class_loader($classname);
1470
+		if ($loader instanceof Closure) {
1471
+			return $loader($arguments);
1472
+		}
1473
+		if (method_exists(self::instance(), $loader)) {
1474
+			return self::instance()->{$loader}($classname, $arguments);
1475
+		}
1476
+		return null;
1477
+	}
1478
+
1479
+
1480
+	/**
1481
+	 * Gets the addon by its class name
1482
+	 *
1483
+	 * @param string $class_name
1484
+	 * @return EE_Addon
1485
+	 */
1486
+	public function getAddon($class_name)
1487
+	{
1488
+		$class_name = str_replace('\\', '_', $class_name);
1489
+		if (isset($this->addons->{$class_name})) {
1490
+			return $this->addons->{$class_name};
1491
+		} else {
1492
+			return null;
1493
+		}
1494
+	}
1495
+
1496
+
1497
+	/**
1498
+	 * removes the addon from the internal cache
1499
+	 *
1500
+	 * @param string $class_name
1501
+	 * @return void
1502
+	 */
1503
+	public function removeAddon($class_name)
1504
+	{
1505
+		$class_name = str_replace('\\', '_', $class_name);
1506
+		unset($this->addons->{$class_name});
1507
+	}
1508
+
1509
+
1510
+	/**
1511
+	 * Gets the addon by its name/slug (not classname. For that, just
1512
+	 * use the get_addon() method above
1513
+	 *
1514
+	 * @param string $name
1515
+	 * @return EE_Addon
1516
+	 */
1517
+	public function get_addon_by_name($name)
1518
+	{
1519
+		foreach ($this->addons as $addon) {
1520
+			if ($addon->name() === $name) {
1521
+				return $addon;
1522
+			}
1523
+		}
1524
+		return null;
1525
+	}
1526
+
1527
+
1528
+	/**
1529
+	 * Gets an array of all the registered addons, where the keys are their names.
1530
+	 * (ie, what each returns for their name() function)
1531
+	 * They're already available on EE_Registry::instance()->addons as properties,
1532
+	 * where each property's name is the addon's classname,
1533
+	 * So if you just want to get the addon by classname,
1534
+	 * OR use the get_addon() method above.
1535
+	 * PLEASE  NOTE:
1536
+	 * addons with Fully Qualified Class Names
1537
+	 * have had the namespace separators converted to underscores,
1538
+	 * so a classname like Fully\Qualified\ClassName
1539
+	 * would have been converted to Fully_Qualified_ClassName
1540
+	 *
1541
+	 * @return EE_Addon[] where the KEYS are the addon's name()
1542
+	 */
1543
+	public function get_addons_by_name()
1544
+	{
1545
+		$addons = array();
1546
+		foreach ($this->addons as $addon) {
1547
+			$addons[ $addon->name() ] = $addon;
1548
+		}
1549
+		return $addons;
1550
+	}
1551
+
1552
+
1553
+	/**
1554
+	 * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1555
+	 * a stale copy of it around
1556
+	 *
1557
+	 * @param string $model_name
1558
+	 * @return \EEM_Base
1559
+	 * @throws \EE_Error
1560
+	 */
1561
+	public function reset_model($model_name)
1562
+	{
1563
+		$model_class_name = strpos($model_name, 'EEM_') !== 0
1564
+			? "EEM_{$model_name}"
1565
+			: $model_name;
1566
+		if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1567
+			return null;
1568
+		}
1569
+		// get that model reset it and make sure we nuke the old reference to it
1570
+		if (
1571
+			$this->LIB->{$model_class_name} instanceof $model_class_name
1572
+			&& is_callable(
1573
+				array($model_class_name, 'reset')
1574
+			)
1575
+		) {
1576
+			$this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1577
+		} else {
1578
+			throw new EE_Error(
1579
+				sprintf(
1580
+					esc_html__('Model %s does not have a method "reset"', 'event_espresso'),
1581
+					$model_name
1582
+				)
1583
+			);
1584
+		}
1585
+		return $this->LIB->{$model_class_name};
1586
+	}
1587
+
1588
+
1589
+	/**
1590
+	 * Resets the registry.
1591
+	 * The criteria for what gets reset is based on what can be shared between sites on the same request when
1592
+	 * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1593
+	 * - $_dependency_map
1594
+	 * - $_class_abbreviations
1595
+	 * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1596
+	 * - $REQ:  Still on the same request so no need to change.
1597
+	 * - $CAP: There is no site specific state in the EE_Capability class.
1598
+	 * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1599
+	 * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1600
+	 * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1601
+	 *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1602
+	 *             switch or on the restore.
1603
+	 * - $modules
1604
+	 * - $shortcodes
1605
+	 * - $widgets
1606
+	 *
1607
+	 * @param boolean $hard             [deprecated]
1608
+	 * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1609
+	 *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1610
+	 *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1611
+	 * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1612
+	 *                                  client
1613
+	 *                                  code instead can just change the model context to a different blog id if
1614
+	 *                                  necessary
1615
+	 * @return EE_Registry
1616
+	 * @throws InvalidInterfaceException
1617
+	 * @throws InvalidDataTypeException
1618
+	 * @throws EE_Error
1619
+	 * @throws ReflectionException
1620
+	 * @throws InvalidArgumentException
1621
+	 */
1622
+	public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1623
+	{
1624
+		$instance = self::instance();
1625
+		$instance->_cache_on = true;
1626
+		// reset some "special" classes
1627
+		EEH_Activation::reset();
1628
+		EEH_DTT_Helper::resetDefaultTimezoneString();
1629
+
1630
+		$hard = apply_filters('FHEE__EE_Registry__reset__hard', $hard);
1631
+		$instance->CFG = EE_Config::reset($hard, $reinstantiate);
1632
+		$instance->CART = null;
1633
+		$instance->MRM = null;
1634
+		$instance->AssetsRegistry = LoaderFactory::getLoader()->getShared(
1635
+			'EventEspresso\core\services\assets\Registry'
1636
+		);
1637
+		// messages reset
1638
+		EED_Messages::reset();
1639
+		// handle of objects cached on LIB
1640
+		foreach (array('LIB', 'modules') as $cache) {
1641
+			foreach ($instance->{$cache} as $class_name => $class) {
1642
+				if (self::_reset_and_unset_object($class, $reset_models)) {
1643
+					unset($instance->{$cache}->{$class_name});
1644
+				}
1645
+			}
1646
+		}
1647
+		return $instance;
1648
+	}
1649
+
1650
+
1651
+	/**
1652
+	 * if passed object implements ResettableInterface, then call it's reset() method
1653
+	 * if passed object implements InterminableInterface, then return false,
1654
+	 * to indicate that it should NOT be cleared from the Registry cache
1655
+	 *
1656
+	 * @param      $object
1657
+	 * @param bool $reset_models
1658
+	 * @return bool returns true if cached object should be unset
1659
+	 */
1660
+	private static function _reset_and_unset_object($object, $reset_models)
1661
+	{
1662
+		if (! is_object($object)) {
1663
+			// don't unset anything that's not an object
1664
+			return false;
1665
+		}
1666
+		if ($object instanceof EED_Module) {
1667
+			$object::reset();
1668
+			// don't unset modules
1669
+			return false;
1670
+		}
1671
+		if ($object instanceof ResettableInterface) {
1672
+			if ($object instanceof EEM_Base) {
1673
+				if ($reset_models) {
1674
+					$object->reset();
1675
+					return true;
1676
+				}
1677
+				return false;
1678
+			}
1679
+			$object->reset();
1680
+			return true;
1681
+		}
1682
+		if (! $object instanceof InterminableInterface) {
1683
+			return true;
1684
+		}
1685
+		return false;
1686
+	}
1687
+
1688
+
1689
+	/**
1690
+	 * Gets all the custom post type models defined
1691
+	 *
1692
+	 * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1693
+	 */
1694
+	public function cpt_models()
1695
+	{
1696
+		$cpt_models = array();
1697
+		foreach ($this->non_abstract_db_models as $short_name => $classname) {
1698
+			if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1699
+				$cpt_models[ $short_name ] = $classname;
1700
+			}
1701
+		}
1702
+		return $cpt_models;
1703
+	}
1704
+
1705
+
1706
+	/**
1707
+	 * @return \EE_Config
1708
+	 */
1709
+	public static function CFG()
1710
+	{
1711
+		return self::instance()->CFG;
1712
+	}
1713
+
1714
+
1715
+	/**
1716
+	 * @deprecated 4.9.62.p
1717
+	 * @param string $class_name
1718
+	 * @return ReflectionClass
1719
+	 * @throws ReflectionException
1720
+	 * @throws InvalidDataTypeException
1721
+	 */
1722
+	public function get_ReflectionClass($class_name)
1723
+	{
1724
+		return $this->mirror->getReflectionClass($class_name);
1725
+	}
1726 1726
 }
Please login to merge, or discard this patch.