Completed
Branch FET/allow-prices-to-be-more-pr... (276f1f)
by
unknown
17:51 queued 14:33
created
core/EE_Registry.core.php 2 patches
Indentation   +1795 added lines, -1795 removed lines patch added patch discarded remove patch
@@ -22,1799 +22,1799 @@
 block discarded – undo
22 22
  */
23 23
 class EE_Registry implements ResettableInterface
24 24
 {
25
-    /**
26
-     * @var EE_Registry $_instance
27
-     */
28
-    private static $_instance;
29
-
30
-    /**
31
-     * @var EE_Dependency_Map $_dependency_map
32
-     */
33
-    protected $_dependency_map;
34
-
35
-    /**
36
-     * @var Mirror
37
-     */
38
-    private $mirror;
39
-
40
-    /**
41
-     * @var ClassInterfaceCache $class_cache
42
-     */
43
-    private $class_cache;
44
-
45
-    /**
46
-     * @var array $_class_abbreviations
47
-     */
48
-    protected $_class_abbreviations = [];
49
-
50
-    /**
51
-     * @var CommandBusInterface $BUS
52
-     */
53
-    public $BUS;
54
-
55
-    /**
56
-     * @var EE_Cart $CART
57
-     */
58
-    public $CART;
59
-
60
-    /**
61
-     * @var EE_Config $CFG
62
-     */
63
-    public $CFG;
64
-
65
-    /**
66
-     * @var EE_Network_Config $NET_CFG
67
-     */
68
-    public $NET_CFG;
69
-
70
-    /**
71
-     * RegistryContainer for storing library classes in
72
-     *
73
-     * @var RegistryContainer $LIB
74
-     */
75
-    public $LIB;
76
-
77
-    /**
78
-     * @var EE_Request_Handler $REQ
79
-     * @deprecated 4.10.14.p
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
-     * RegistryContainer for holding addons which have registered themselves to work with EE core
107
-     *
108
-     * @var RegistryContainer|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 = [];
118
-
119
-    /**
120
-     * @var RegistryContainer|EED_Module[] $modules
121
-     */
122
-    public $modules;
123
-
124
-    /**
125
-     * @var RegistryContainer|EES_Shortcode[] $shortcodes
126
-     */
127
-    public $shortcodes;
128
-
129
-    /**
130
-     * @var RegistryContainer|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 = [];
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 = [];
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
-    ): EE_Registry {
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', [$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
-            [
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', [], 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', [$this, 'init']);
286
-    }
287
-
288
-
289
-    /**
290
-     * @return void
291
-     */
292
-    public function init()
293
-    {
294
-        // Get current page protocol
295
-        $protocol = is_ssl() ? '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;
299
-    }
300
-
301
-
302
-    /**
303
-     * @return array
304
-     */
305
-    public static function sanitize_i18n_js_strings(): array
306
-    {
307
-        $i18n_js_strings = (array) self::$i18n_js_strings;
308
-        foreach ($i18n_js_strings as $key => $value) {
309
-            if (is_scalar($value)) {
310
-                $decoded_value           = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
311
-                $i18n_js_strings[ $key ] = wp_strip_all_tags($decoded_value);
312
-            }
313
-        }
314
-        return $i18n_js_strings;
315
-    }
316
-
317
-
318
-    /**
319
-     * localize_i18n_js_strings
320
-     *
321
-     * @return string
322
-     */
323
-    public static function localize_i18n_js_strings(): string
324
-    {
325
-        $i18n_js_strings = EE_Registry::sanitize_i18n_js_strings();
326
-        return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
327
-    }
328
-
329
-
330
-    /**
331
-     * @param mixed string | EED_Module $module
332
-     * @throws OutOfBoundsException
333
-     * @throws InvalidArgumentException
334
-     * @throws InvalidInterfaceException
335
-     * @throws InvalidDataTypeException
336
-     * @throws EE_Error
337
-     * @throws ReflectionException
338
-     */
339
-    public function add_module($module)
340
-    {
341
-        if ($module instanceof EED_Module) {
342
-            $module_class = get_class($module);
343
-            $this->modules->add($module_class, $module);
344
-        } else {
345
-            if (! class_exists('EE_Module_Request_Router', false)) {
346
-                $this->load_core('Module_Request_Router');
347
-            }
348
-            EE_Module_Request_Router::module_factory($module);
349
-        }
350
-    }
351
-
352
-
353
-    /**
354
-     * @param string $module_name
355
-     * @return mixed EED_Module | NULL
356
-     */
357
-    public function get_module(string $module_name = '')
358
-    {
359
-        return $this->modules->get($module_name);
360
-    }
361
-
362
-
363
-    /**
364
-     * loads core classes - must be singletons
365
-     *
366
-     * @param string $class_name - simple class name ie: session
367
-     * @param mixed  $arguments
368
-     * @param bool   $load_only
369
-     * @return bool|null|object
370
-     * @throws InvalidInterfaceException
371
-     * @throws InvalidDataTypeException
372
-     * @throws EE_Error
373
-     * @throws ReflectionException
374
-     * @throws InvalidArgumentException
375
-     */
376
-    public function load_core(string $class_name, $arguments = [], bool $load_only = false)
377
-    {
378
-        $core_paths = (array) apply_filters(
379
-            'FHEE__EE_Registry__load_core__core_paths',
380
-            [
381
-                EE_CORE,
382
-                EE_ADMIN,
383
-                EE_CPTS,
384
-                EE_CORE . 'CPTs/',
385
-                EE_CORE . 'data_migration_scripts/',
386
-                EE_CORE . 'request_stack/',
387
-                EE_CORE . 'middleware/',
388
-            ]
389
-        );
390
-        // retrieve instantiated class
391
-        return $this->_load(
392
-            $core_paths,
393
-            'EE_',
394
-            $class_name,
395
-            'core',
396
-            $arguments,
397
-            false,
398
-            true,
399
-            $load_only
400
-        );
401
-    }
402
-
403
-
404
-    /**
405
-     * loads service classes
406
-     *
407
-     * @param string $class_name - simple class name ie: session
408
-     * @param mixed  $arguments
409
-     * @param bool   $load_only
410
-     * @return bool|null|object
411
-     * @throws InvalidInterfaceException
412
-     * @throws InvalidDataTypeException
413
-     * @throws EE_Error
414
-     * @throws ReflectionException
415
-     * @throws InvalidArgumentException
416
-     * @deprecated  4.10.33.p
417
-     */
418
-    public function load_service(string $class_name, $arguments = [], bool $load_only = false)
419
-    {
420
-        $service_paths = (array) apply_filters(
421
-            'FHEE__EE_Registry__load_service__service_paths',
422
-            [
423
-                EE_CORE . 'services/',
424
-            ]
425
-        );
426
-        // retrieve instantiated class
427
-        return $this->_load(
428
-            $service_paths,
429
-            'EE_',
430
-            $class_name,
431
-            'class',
432
-            $arguments,
433
-            false,
434
-            true,
435
-            $load_only
436
-        );
437
-    }
438
-
439
-
440
-    /**
441
-     * loads data_migration_scripts
442
-     *
443
-     * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
444
-     * @param mixed  $arguments
445
-     * @return bool|null|object
446
-     * @throws InvalidInterfaceException
447
-     * @throws InvalidDataTypeException
448
-     * @throws EE_Error
449
-     * @throws ReflectionException
450
-     * @throws InvalidArgumentException
451
-     */
452
-    public function load_dms(string $class_name, $arguments = [])
453
-    {
454
-        // retrieve instantiated class
455
-        return $this->_load(
456
-            EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
457
-            'EE_DMS_',
458
-            $class_name,
459
-            'dms',
460
-            $arguments,
461
-            false,
462
-            false
463
-        );
464
-    }
465
-
466
-
467
-    /**
468
-     * loads object creating classes - must be singletons
469
-     *
470
-     * @param string $class_name - simple class name ie: attendee
471
-     * @param mixed  $arguments  - an array of arguments to pass to the class
472
-     * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
473
-     *                           instantiate
474
-     * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
475
-     *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
476
-     * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
477
-     *                           (default)
478
-     * @return EE_Base_Class|mixed|bool|null
479
-     * @throws InvalidInterfaceException
480
-     * @throws InvalidDataTypeException
481
-     * @throws EE_Error
482
-     * @throws ReflectionException
483
-     * @throws InvalidArgumentException
484
-     */
485
-    public function load_class(
486
-        string $class_name,
487
-        $arguments = [],
488
-        bool $from_db = false,
489
-        bool $cache = true,
490
-        bool $load_only = false
491
-    ) {
492
-        $paths = (array) apply_filters(
493
-            'FHEE__EE_Registry__load_class__paths',
494
-            [
495
-                EE_CORE,
496
-                EE_CLASSES,
497
-                EE_BUSINESS,
498
-            ]
499
-        );
500
-        // retrieve instantiated class
501
-        return $this->_load(
502
-            $paths,
503
-            'EE_',
504
-            $class_name,
505
-            'class',
506
-            $arguments,
507
-            $from_db,
508
-            $cache,
509
-            $load_only
510
-        );
511
-    }
512
-
513
-
514
-    /**
515
-     * loads helper classes - must be singletons
516
-     *
517
-     * @param string $class_name - simple class name ie: price
518
-     * @param mixed  $arguments
519
-     * @param bool   $load_only
520
-     * @return bool|null|object
521
-     * @throws InvalidInterfaceException
522
-     * @throws InvalidDataTypeException
523
-     * @throws EE_Error
524
-     * @throws ReflectionException
525
-     * @throws InvalidArgumentException
526
-     */
527
-    public function load_helper(string $class_name, $arguments = [], bool $load_only = true)
528
-    {
529
-        // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
530
-        $helper_paths = (array) apply_filters('FHEE__EE_Registry__load_helper__helper_paths', [EE_HELPERS]);
531
-        // retrieve instantiated class
532
-        return $this->_load(
533
-            $helper_paths,
534
-            'EEH_',
535
-            $class_name,
536
-            'helper',
537
-            $arguments,
538
-            false,
539
-            true,
540
-            $load_only
541
-        );
542
-    }
543
-
544
-
545
-    /**
546
-     * loads core classes - must be singletons
547
-     *
548
-     * @param string $class_name - simple class name ie: session
549
-     * @param mixed  $arguments
550
-     * @param bool   $load_only
551
-     * @param bool   $cache      whether to cache the object or not.
552
-     * @return bool|null|object
553
-     * @throws InvalidInterfaceException
554
-     * @throws InvalidDataTypeException
555
-     * @throws EE_Error
556
-     * @throws ReflectionException
557
-     * @throws InvalidArgumentException
558
-     */
559
-    public function load_lib(string $class_name, $arguments = [], bool $load_only = false, bool $cache = true)
560
-    {
561
-        $paths = [
562
-            EE_LIBRARIES,
563
-            EE_LIBRARIES . 'messages/',
564
-            EE_LIBRARIES . 'shortcodes/',
565
-            EE_LIBRARIES . 'qtips/',
566
-            EE_LIBRARIES . 'payment_methods/',
567
-        ];
568
-        // retrieve instantiated class
569
-        return $this->_load(
570
-            $paths,
571
-            'EE_',
572
-            $class_name,
573
-            'lib',
574
-            $arguments,
575
-            false,
576
-            $cache,
577
-            $load_only
578
-        );
579
-    }
580
-
581
-
582
-    /**
583
-     * loads model classes - must be singletons
584
-     *
585
-     * @param string $class_name - simple class name ie: price
586
-     * @param mixed  $arguments
587
-     * @param bool   $load_only
588
-     * @return bool|null|object
589
-     * @throws InvalidInterfaceException
590
-     * @throws InvalidDataTypeException
591
-     * @throws EE_Error
592
-     * @throws ReflectionException
593
-     * @throws InvalidArgumentException
594
-     */
595
-    public function load_model(string $class_name, $arguments = [], bool $load_only = false)
596
-    {
597
-        $paths = (array) apply_filters(
598
-            'FHEE__EE_Registry__load_model__paths',
599
-            [
600
-                EE_MODELS,
601
-                EE_CORE,
602
-            ]
603
-        );
604
-        // retrieve instantiated class
605
-        return $this->_load(
606
-            $paths,
607
-            'EEM_',
608
-            $class_name,
609
-            'model',
610
-            $arguments,
611
-            false,
612
-            true,
613
-            $load_only
614
-        );
615
-    }
616
-
617
-
618
-    /**
619
-     * loads model classes - must be singletons
620
-     *
621
-     * @param string $class_name - simple class name ie: price
622
-     * @param mixed  $arguments
623
-     * @param bool   $load_only
624
-     * @return bool|null|object
625
-     * @throws InvalidInterfaceException
626
-     * @throws InvalidDataTypeException
627
-     * @throws EE_Error
628
-     * @throws ReflectionException
629
-     * @throws InvalidArgumentException
630
-     * @deprecated  4.10.33.p
631
-     */
632
-    public function load_model_class(string $class_name, $arguments = [], bool $load_only = true)
633
-    {
634
-        $paths = [
635
-            EE_MODELS . 'fields/',
636
-            EE_MODELS . 'helpers/',
637
-            EE_MODELS . 'relations/',
638
-            EE_MODELS . 'strategies/',
639
-        ];
640
-        // retrieve instantiated class
641
-        return $this->_load(
642
-            $paths,
643
-            'EE_',
644
-            $class_name,
645
-            '',
646
-            $arguments,
647
-            false,
648
-            true,
649
-            $load_only
650
-        );
651
-    }
652
-
653
-
654
-    /**
655
-     * Determines if $model_name is the name of an actual EE model.
656
-     *
657
-     * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
658
-     * @return boolean
659
-     */
660
-    public function is_model_name(string $model_name): bool
661
-    {
662
-        return isset($this->models[ $model_name ]);
663
-    }
664
-
665
-
666
-    /**
667
-     * generic class loader
668
-     *
669
-     * @param string $path_to_file - directory path to file location, not including filename
670
-     * @param string $file_name    - file name  ie:  my_file.php, including extension
671
-     * @param string $type         - file type - core? class? helper? model?
672
-     * @param mixed  $arguments
673
-     * @param bool   $load_only
674
-     * @return bool|null|object
675
-     * @throws InvalidInterfaceException
676
-     * @throws InvalidDataTypeException
677
-     * @throws EE_Error
678
-     * @throws ReflectionException
679
-     * @throws InvalidArgumentException
680
-     */
681
-    public function load_file(
682
-        string $path_to_file,
683
-        string $file_name,
684
-        string $type = '',
685
-        $arguments = [],
686
-        bool $load_only = true
687
-    ) {
688
-        // retrieve instantiated class
689
-        return $this->_load(
690
-            (array) $path_to_file,
691
-            '',
692
-            $file_name,
693
-            $type,
694
-            $arguments,
695
-            false,
696
-            true,
697
-            $load_only
698
-        );
699
-    }
700
-
701
-
702
-    /**
703
-     * @param string $path_to_file - directory path to file location, not including filename
704
-     * @param string $class_name   - full class name  ie:  My_Class
705
-     * @param string $type         - file type - core? class? helper? model?
706
-     * @param mixed  $arguments
707
-     * @param bool   $load_only
708
-     * @return bool|null|object
709
-     * @throws InvalidInterfaceException
710
-     * @throws InvalidDataTypeException
711
-     * @throws EE_Error
712
-     * @throws ReflectionException
713
-     * @throws InvalidArgumentException
714
-     * @deprecated  4.10.33.p
715
-     */
716
-    public function load_addon(
717
-        string $path_to_file,
718
-        string $class_name,
719
-        string $type = 'class',
720
-        $arguments = [],
721
-        bool $load_only = false
722
-    ) {
723
-        // retrieve instantiated class
724
-        return $this->_load(
725
-            (array) $path_to_file,
726
-            'addon',
727
-            $class_name,
728
-            $type,
729
-            $arguments,
730
-            false,
731
-            true,
732
-            $load_only
733
-        );
734
-    }
735
-
736
-
737
-    /**
738
-     * instantiates, caches, and automatically resolves dependencies
739
-     * for classes that use a Fully Qualified Class Name.
740
-     * if the class is not capable of being loaded using PSR-4 autoloading,
741
-     * then you need to use one of the existing load_*() methods
742
-     * which can resolve the classname and filepath from the passed arguments
743
-     *
744
-     * @param string      $class_name Fully Qualified Class Name
745
-     * @param array       $arguments  an argument, or array of arguments to pass to the class upon instantiation
746
-     * @param bool        $cache      whether to cache the instantiated object for reuse
747
-     * @param bool        $from_db    some classes are instantiated from the db
748
-     *                                and thus call a different method to instantiate
749
-     * @param bool        $load_only  if true, will only load the file, but will NOT instantiate an object
750
-     * @param bool|string $addon      if true, will cache the object in the EE_Registry->$addons array
751
-     * @return bool|null|mixed     null = failure to load or instantiate class object.
752
-     *                                object = class loaded and instantiated successfully.
753
-     *                                bool = fail or success when $load_only is true
754
-     * @throws InvalidInterfaceException
755
-     * @throws InvalidDataTypeException
756
-     * @throws EE_Error
757
-     * @throws ReflectionException
758
-     * @throws InvalidArgumentException
759
-     */
760
-    public function create(
761
-        string $class_name = '',
762
-        array $arguments = [],
763
-        bool $cache = false,
764
-        bool $from_db = false,
765
-        bool $load_only = false,
766
-        bool $addon = false
767
-    ) {
768
-        $class_name   = ltrim($class_name, '\\');
769
-        $class_name   = $this->class_cache->getFqnForAlias($class_name);
770
-        $class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
771
-        // if a non-FQCN was passed, then
772
-        // verifyClassExists() might return an object
773
-        // or it could return null if the class just could not be found anywhere
774
-        if ($class_exists instanceof $class_name || $class_exists === null) {
775
-            // either way, return the results
776
-            return $class_exists;
777
-        }
778
-        $class_name = $class_exists;
779
-        // if we're only loading the class and it already exists, then let's just return true immediately
780
-        if ($load_only) {
781
-            return true;
782
-        }
783
-        $addon = $addon ? 'addon' : '';
784
-        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
785
-        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
786
-        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
787
-        if ($this->_cache_on && $cache) {
788
-            // return object if it's already cached
789
-            $cached_class = $this->_get_cached_class($class_name, $addon, $arguments);
790
-
791
-            if ($cached_class !== null) {
792
-                return $cached_class;
793
-            }
794
-        }
795
-        // obtain the loader method from the dependency map
796
-        $loader = $this->_dependency_map->class_loader($class_name);
797
-        // instantiate the requested object
798
-        if ($loader instanceof Closure) {
799
-            $class_obj = $loader($arguments);
800
-        } else {
801
-            if ($loader && method_exists($this, $loader)) {
802
-                $class_obj = $this->{$loader}($class_name, $arguments);
803
-            } else {
804
-                $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
805
-            }
806
-        }
807
-        if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) {
808
-            // save it for later... kinda like gum  { : $
809
-            $this->_set_cached_class(
810
-                $class_obj,
811
-                $class_name,
812
-                $addon,
813
-                $from_db,
814
-                $arguments
815
-            );
816
-        }
817
-        $this->_cache_on = true;
818
-        return $class_obj;
819
-    }
820
-
821
-
822
-    /**
823
-     * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
824
-     *
825
-     * @param string|mixed $class_name
826
-     * @param array        $arguments
827
-     * @param int          $attempt
828
-     * @return mixed
829
-     */
830
-    private function loadOrVerifyClassExists($class_name, array $arguments, int $attempt = 1)
831
-    {
832
-        if (is_object($class_name) || class_exists($class_name)) {
833
-            return $class_name;
834
-        }
835
-        switch ($attempt) {
836
-            case 1:
837
-                // if it's a FQCN then maybe the class is registered with a preceding \
838
-                $class_name = strpos($class_name, '\\') !== false
839
-                    ? '\\' . ltrim($class_name, '\\')
840
-                    : $class_name;
841
-                break;
842
-            case 2:
843
-                //
844
-                $loader = $this->_dependency_map->class_loader($class_name);
845
-                if ($loader && method_exists($this, $loader)) {
846
-                    return $this->{$loader}($class_name, $arguments);
847
-                }
848
-                break;
849
-            case 3:
850
-            default:
851
-                return null;
852
-        }
853
-        $attempt++;
854
-        return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
855
-    }
856
-
857
-
858
-    /**
859
-     * instantiates, caches, and injects dependencies for classes
860
-     *
861
-     * @param array       $file_paths   an array of paths to folders to look in
862
-     * @param string      $class_prefix EE  or EEM or... ???
863
-     * @param bool|string $class_name   $class name
864
-     * @param string      $type         file type - core? class? helper? model?
865
-     * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
866
-     * @param bool        $from_db      some classes are instantiated from the db
867
-     *                                  and thus call a different method to instantiate
868
-     * @param bool        $cache        whether to cache the instantiated object for reuse
869
-     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
870
-     * @return EE_Base_Class|mixed|bool|null = failure to load or instantiate class object.
871
-     *                                  object = class loaded and instantiated successfully.
872
-     *                                  bool = fail or success when $load_only is true
873
-     * @throws EE_Error
874
-     * @throws ReflectionException
875
-     * @throws InvalidInterfaceException
876
-     * @throws InvalidDataTypeException
877
-     * @throws InvalidArgumentException
878
-     */
879
-    protected function _load(
880
-        array $file_paths = [],
881
-        string $class_prefix = 'EE_',
882
-        string $class_name = '',
883
-        string $type = 'class',
884
-        array $arguments = [],
885
-        bool $from_db = false,
886
-        bool $cache = true,
887
-        bool $load_only = false
888
-    ) {
889
-        $class_name = ltrim($class_name, '\\');
890
-        // strip php file extension
891
-        $class_name = str_replace('.php', '', trim($class_name));
892
-        // does the class have a prefix ?
893
-        if (! empty($class_prefix) && $class_prefix !== 'addon') {
894
-            // make sure $class_prefix is uppercase
895
-            $class_prefix = strtoupper(trim($class_prefix));
896
-            // add class prefix ONCE!!!
897
-            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
898
-        }
899
-        $class_name   = $this->class_cache->getFqnForAlias($class_name);
900
-        $class_exists = class_exists($class_name, false);
901
-        // if we're only loading the class and it already exists, then let's just return true immediately
902
-        if ($load_only && $class_exists) {
903
-            return true;
904
-        }
905
-        $arguments = is_array($arguments) ? $arguments : [$arguments];
906
-        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
907
-        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
908
-        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
909
-        if ($this->_cache_on && $cache && ! $load_only) {
910
-            // return object if it's already cached
911
-            $cached_class = $this->_get_cached_class($class_name, $class_prefix, $arguments);
912
-            if ($cached_class !== null) {
913
-                return $cached_class;
914
-            }
915
-        }
916
-        // if the class doesn't already exist.. then we need to try and find the file and load it
917
-        if (! $class_exists) {
918
-            // get full path to file
919
-            $path = $this->_resolve_path($class_name, $type, $file_paths);
920
-            // load the file
921
-            $loaded = $this->_require_file($path, $class_name, $type, $file_paths);
922
-            // if we are only loading a file but NOT instantiating an object
923
-            // then return boolean for whether class was loaded or not
924
-            if ($load_only) {
925
-                return $loaded;
926
-            }
927
-            // if an object was expected but loading failed, then return nothing
928
-            if (! $loaded) {
929
-                return null;
930
-            }
931
-        }
932
-        // instantiate the requested object
933
-        $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
934
-        if ($this->_cache_on && $cache) {
935
-            // save it for later... kinda like gum  { : $
936
-            $this->_set_cached_class(
937
-                $class_obj,
938
-                $class_name,
939
-                $class_prefix,
940
-                $from_db,
941
-                $arguments
942
-            );
943
-        }
944
-        $this->_cache_on = true;
945
-        return $class_obj;
946
-    }
947
-
948
-
949
-    /**
950
-     * @param string $class_name
951
-     * @param string $default have to specify something, but not anything that will conflict
952
-     * @return mixed|string
953
-     */
954
-    protected function get_class_abbreviation(string $class_name, string $default = 'FANCY_BATMAN_PANTS')
955
-    {
956
-        return $this->_class_abbreviations[ $class_name ] ?? $default;
957
-    }
958
-
959
-
960
-    /**
961
-     * attempts to find a cached version of the requested class
962
-     * by looking in the following places:
963
-     *        $this->{$class_abbreviation}            ie:    $this->CART
964
-     *        $this->{$class_name}                        ie:    $this->Some_Class
965
-     *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
966
-     *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
967
-     *
968
-     * @param string $class_name
969
-     * @param string $class_prefix
970
-     * @param array  $arguments
971
-     * @return mixed
972
-     */
973
-    protected function _get_cached_class(
974
-        string $class_name,
975
-        string $class_prefix = '',
976
-        array $arguments = []
977
-    ) {
978
-        if ($class_name === 'EE_Registry') {
979
-            return $this;
980
-        }
981
-        $class_abbreviation = $this->get_class_abbreviation($class_name);
982
-        // check if class has already been loaded, and return it if it has been
983
-        if (isset($this->{$class_abbreviation})) {
984
-            return $this->{$class_abbreviation};
985
-        }
986
-        $class_name = str_replace('\\', '_', $class_name);
987
-        if (isset($this->{$class_name})) {
988
-            return $this->{$class_name};
989
-        }
990
-        if ($class_prefix === 'addon' && $this->addons->has($class_name)) {
991
-            return $this->addons->get($class_name);
992
-        }
993
-        $object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments);
994
-        if ($this->LIB->has($object_identifier)) {
995
-            return $this->LIB->get($object_identifier);
996
-        }
997
-        foreach ($this->LIB as $key => $object) {
998
-            if (
999
-                // request does not contain new arguments and therefore no args identifier
1000
-                ! $this->object_identifier->hasArguments($object_identifier)
1001
-                // but previously cached class with args was found
1002
-                && $this->object_identifier->fqcnMatchesObjectIdentifier($class_name, $key)
1003
-            ) {
1004
-                return $object;
1005
-            }
1006
-        }
1007
-        return null;
1008
-    }
1009
-
1010
-
1011
-    /**
1012
-     * removes a cached version of the requested class
1013
-     *
1014
-     * @param string  $class_name
1015
-     * @param boolean $addon
1016
-     * @param array   $arguments
1017
-     * @return boolean
1018
-     */
1019
-    public function clear_cached_class(
1020
-        string $class_name,
1021
-        bool $addon = false,
1022
-        array $arguments = []
1023
-    ): bool {
1024
-        $class_abbreviation = $this->get_class_abbreviation($class_name);
1025
-        // check if class has already been loaded, and return it if it has been
1026
-        if (isset($this->{$class_abbreviation}) && ! $this->{$class_abbreviation} instanceof InterminableInterface) {
1027
-            $this->{$class_abbreviation} = null;
1028
-            return true;
1029
-        }
1030
-        $class_name = str_replace('\\', '_', $class_name);
1031
-        if (isset($this->{$class_name}) && ! $this->{$class_name} instanceof InterminableInterface) {
1032
-            $this->{$class_name} = null;
1033
-            return true;
1034
-        }
1035
-        if ($addon && $this->addons->has($class_name)) {
1036
-            $this->addons->remove($class_name);
1037
-            return true;
1038
-        }
1039
-        $object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments);
1040
-        if ($this->LIB->has($object_identifier) && ! $this->LIB->get($object_identifier) instanceof InterminableInterface) {
1041
-            $this->LIB->remove($object_identifier);
1042
-            return true;
1043
-        }
1044
-        return false;
1045
-    }
1046
-
1047
-
1048
-    /**
1049
-     * _set_cached_class
1050
-     * attempts to cache the instantiated class locally
1051
-     * in one of the following places, in the following order:
1052
-     *        $this->{class_abbreviation}   ie:    $this->CART
1053
-     *        $this->{$class_name}          ie:    $this->Some_Class
1054
-     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1055
-     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1056
-     *
1057
-     * @param object $class_obj
1058
-     * @param string $class_name
1059
-     * @param string $class_prefix
1060
-     * @param bool   $from_db
1061
-     * @param array  $arguments
1062
-     * @return void
1063
-     */
1064
-    protected function _set_cached_class(
1065
-        $class_obj,
1066
-        string $class_name,
1067
-        string $class_prefix = '',
1068
-        bool $from_db = false,
1069
-        array $arguments = []
1070
-    ) {
1071
-        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1072
-            return;
1073
-        }
1074
-        // return newly instantiated class
1075
-        $class_abbreviation = $this->get_class_abbreviation($class_name, '');
1076
-        if ($class_abbreviation) {
1077
-            $this->{$class_abbreviation} = $class_obj;
1078
-            return;
1079
-        }
1080
-        $class_name = str_replace('\\', '_', $class_name);
1081
-        if (property_exists($this, $class_name)) {
1082
-            $this->{$class_name} = $class_obj;
1083
-            return;
1084
-        }
1085
-        if ($class_prefix === 'addon') {
1086
-            $this->addons->add($class_name, $class_obj);
1087
-            return;
1088
-        }
1089
-        if (! $from_db) {
1090
-            $class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1091
-            $this->LIB->add($class_name, $class_obj);
1092
-        }
1093
-    }
1094
-
1095
-
1096
-    /**
1097
-     * attempts to find a full valid filepath for the requested class.
1098
-     * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
1099
-     * then returns that path if the target file has been found and is readable
1100
-     *
1101
-     * @param string $class_name
1102
-     * @param string $type
1103
-     * @param array  $file_paths
1104
-     * @return string | bool
1105
-     */
1106
-    protected function _resolve_path(string $class_name, string $type = '', array $file_paths = [])
1107
-    {
1108
-        // make sure $file_paths is an array
1109
-        $file_paths = is_array($file_paths)
1110
-            ? $file_paths
1111
-            : [$file_paths];
1112
-        // cycle thru paths
1113
-        foreach ($file_paths as $key => $file_path) {
1114
-            // convert all separators to proper /, if no filepath, then use EE_CLASSES
1115
-            $file_path = $file_path
1116
-                ? str_replace(['/', '\\'], '/', $file_path)
1117
-                : EE_CLASSES;
1118
-            // prep file type
1119
-            $type = ! empty($type)
1120
-                ? trim($type, '.') . '.'
1121
-                : '';
1122
-            // build full file path
1123
-            $file_paths[ $key ] = rtrim($file_path, '/') . '/' . $class_name . '.' . $type . 'php';
1124
-            // does the file exist and can be read ?
1125
-            if (is_readable($file_paths[ $key ])) {
1126
-                return $file_paths[ $key ];
1127
-            }
1128
-        }
1129
-        return false;
1130
-    }
1131
-
1132
-
1133
-    /**
1134
-     * basically just performs a require_once()
1135
-     * but with some error handling
1136
-     *
1137
-     * @param string $path
1138
-     * @param string $class_name
1139
-     * @param string $type
1140
-     * @param array  $file_paths
1141
-     * @return bool
1142
-     * @throws EE_Error
1143
-     * @throws ReflectionException
1144
-     */
1145
-    protected function _require_file(string $path, string $class_name, string $type = '', array $file_paths = []): bool
1146
-    {
1147
-        $this->resolve_legacy_class_parent($class_name);
1148
-        // don't give up! you gotta...
1149
-        try {
1150
-            // does the file exist and can it be read ?
1151
-            if (! $path) {
1152
-                // just in case the file has already been autoloaded,
1153
-                // but discrepancies in the naming schema are preventing it from
1154
-                // being loaded via one of the EE_Registry::load_*() methods,
1155
-                // then let's try one last hail mary before throwing an exception
1156
-                // and call class_exists() again, but with autoloading turned ON
1157
-                if (class_exists($class_name)) {
1158
-                    return true;
1159
-                }
1160
-                // so sorry, can't find the file
1161
-                throw new EE_Error(
1162
-                    sprintf(
1163
-                        esc_html__(
1164
-                            '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',
1165
-                            'event_espresso'
1166
-                        ),
1167
-                        trim($type, '.'),
1168
-                        $class_name,
1169
-                        '<br />' . implode(',<br />', $file_paths)
1170
-                    )
1171
-                );
1172
-            }
1173
-            // get the file
1174
-            require_once($path);
1175
-            // if the class isn't already declared somewhere
1176
-            if (class_exists($class_name, false) === false) {
1177
-                // so sorry, not a class
1178
-                throw new EE_Error(
1179
-                    sprintf(
1180
-                        esc_html__(
1181
-                            'The %s file %s does not appear to contain the %s Class.',
1182
-                            'event_espresso'
1183
-                        ),
1184
-                        $type,
1185
-                        $path,
1186
-                        $class_name
1187
-                    )
1188
-                );
1189
-            }
1190
-        } catch (EE_Error $e) {
1191
-            $e->get_error();
1192
-            return false;
1193
-        }
1194
-        return true;
1195
-    }
1196
-
1197
-
1198
-    /**
1199
-     * Some of our legacy classes that extended a parent class would simply use a require() statement
1200
-     * before their class declaration in order to ensure that the parent class was loaded.
1201
-     * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1202
-     * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1203
-     *
1204
-     * @param string $class_name
1205
-     */
1206
-    protected function resolve_legacy_class_parent(string $class_name = '')
1207
-    {
1208
-        try {
1209
-            $legacy_parent_class_map = [
1210
-                'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php',
1211
-            ];
1212
-            if (isset($legacy_parent_class_map[ $class_name ])) {
1213
-                require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ];
1214
-            }
1215
-        } catch (Exception $exception) {
1216
-        }
1217
-    }
1218
-
1219
-
1220
-    /**
1221
-     * _create_object
1222
-     * Attempts to instantiate the requested class via any of the
1223
-     * commonly used instantiation methods employed throughout EE.
1224
-     * The priority for instantiation is as follows:
1225
-     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1226
-     *        - model objects via their 'new_instance_from_db' method
1227
-     *        - model objects via their 'new_instance' method
1228
-     *        - "singleton" classes" via their 'instance' method
1229
-     *    - standard instantiable classes via their __constructor
1230
-     * Prior to instantiation, if the classname exists in the dependency_map,
1231
-     * then the constructor for the requested class will be examined to determine
1232
-     * if any dependencies exist, and if they can be injected.
1233
-     * If so, then those classes will be added to the array of arguments passed to the constructor
1234
-     *
1235
-     * @param string $class_name
1236
-     * @param array  $arguments
1237
-     * @param string $type
1238
-     * @param bool   $from_db
1239
-     * @return null|object|bool
1240
-     * @throws InvalidArgumentException
1241
-     * @throws InvalidInterfaceException
1242
-     * @throws EE_Error
1243
-     * @throws ReflectionException
1244
-     * @throws InvalidDataTypeException
1245
-     */
1246
-    protected function _create_object(
1247
-        string $class_name,
1248
-        array $arguments = [],
1249
-        string $type = '',
1250
-        bool $from_db = false
1251
-    ) {
1252
-        // create reflection
1253
-        $reflector = $this->mirror->getReflectionClass($class_name);
1254
-        // make sure arguments are an array
1255
-        $arguments = is_array($arguments)
1256
-            ? $arguments
1257
-            : [$arguments];
1258
-        // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1259
-        // else wrap it in an additional array so that it doesn't get split into multiple parameters
1260
-        $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1261
-            ? $arguments
1262
-            : [$arguments];
1263
-        // attempt to inject dependencies ?
1264
-        if ($this->_dependency_map->has($class_name)) {
1265
-            $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1266
-        }
1267
-        // instantiate the class if possible
1268
-        if ($reflector->isAbstract()) {
1269
-            // nothing to instantiate, loading file was enough
1270
-            // does not throw an exception so $instantiation_mode is unused
1271
-            // $instantiation_mode = "1) no constructor abstract class";
1272
-            return true;
1273
-        }
1274
-        if (
1275
-            empty($arguments)
1276
-            && $this->mirror->getConstructorFromReflection($reflector) === null
1277
-            && $reflector->isInstantiable()
1278
-        ) {
1279
-            // no constructor = static methods only... nothing to instantiate, loading file was enough
1280
-            // $instantiation_mode = "2) no constructor but instantiable";
1281
-            return $reflector->newInstance();
1282
-        }
1283
-        if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1284
-            // $instantiation_mode = "3) new_instance_from_db()";
1285
-            return call_user_func_array([$class_name, 'new_instance_from_db'], $arguments);
1286
-        }
1287
-        if (method_exists($class_name, 'new_instance')) {
1288
-            // $instantiation_mode = "4) new_instance()";
1289
-            return call_user_func_array([$class_name, 'new_instance'], $arguments);
1290
-        }
1291
-        if (method_exists($class_name, 'instance')) {
1292
-            // $instantiation_mode = "5) instance()";
1293
-            return call_user_func_array([$class_name, 'instance'], $arguments);
1294
-        }
1295
-        if ($reflector->isInstantiable()) {
1296
-            // $instantiation_mode = "6) constructor";
1297
-            return $reflector->newInstanceArgs($arguments);
1298
-        }
1299
-        // heh ? something's not right !
1300
-        throw new EE_Error(
1301
-            sprintf(
1302
-                esc_html__('The %s file %s could not be instantiated.', 'event_espresso'),
1303
-                $type,
1304
-                $class_name
1305
-            )
1306
-        );
1307
-    }
1308
-
1309
-
1310
-    /**
1311
-     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1312
-     * @param array $array
1313
-     * @return bool
1314
-     */
1315
-    protected function _array_is_numerically_and_sequentially_indexed(array $array): bool
1316
-    {
1317
-        return empty($array) || array_keys($array) === range(0, count($array) - 1);
1318
-    }
1319
-
1320
-
1321
-    /**
1322
-     * _resolve_dependencies
1323
-     * examines the constructor for the requested class to determine
1324
-     * if any dependencies exist, and if they can be injected.
1325
-     * If so, then those classes will be added to the array of arguments passed to the constructor
1326
-     * PLZ NOTE: this is achieved by type hinting the constructor params
1327
-     * For example:
1328
-     *        if attempting to load a class "Foo" with the following constructor:
1329
-     *        __construct( Bar $bar_class, Fighter $grohl_class )
1330
-     *        then $bar_class and $grohl_class will be added to the $arguments array,
1331
-     *        but only IF they are NOT already present in the incoming arguments array,
1332
-     *        and the correct classes can be loaded
1333
-     *
1334
-     * @param ReflectionClass $reflector
1335
-     * @param string          $class_name
1336
-     * @param array           $arguments
1337
-     * @return array
1338
-     * @throws InvalidArgumentException
1339
-     * @throws InvalidDataTypeException
1340
-     * @throws InvalidInterfaceException
1341
-     * @throws ReflectionException
1342
-     */
1343
-    protected function _resolve_dependencies(
1344
-        ReflectionClass $reflector,
1345
-        string $class_name,
1346
-        array $arguments = []
1347
-    ): array {
1348
-        // let's examine the constructor
1349
-        $constructor = $this->mirror->getConstructorFromReflection($reflector);
1350
-        // whu? huh? nothing?
1351
-        if (! $constructor) {
1352
-            return $arguments;
1353
-        }
1354
-        // get constructor parameters
1355
-        $params = $this->mirror->getParametersFromReflection($reflector);
1356
-        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1357
-        $argument_keys = array_keys($arguments);
1358
-        // now loop thru all of the constructors expected parameters
1359
-        foreach ($params as $index => $param) {
1360
-            try {
1361
-                // is this a dependency for a specific class ?
1362
-                $param_class = $this->mirror->getParameterClassName($param, $class_name, $index);
1363
-            } catch (ReflectionException $exception) {
1364
-                // uh-oh... most likely a legacy class that has not been autoloaded
1365
-                // let's try to derive the classname from what we have now
1366
-                // and hope that the property var name is close to the class name
1367
-                $param_class = $param->getName();
1368
-                $param_class = str_replace('_', ' ', $param_class);
1369
-                $param_class = ucwords($param_class);
1370
-                $param_class = str_replace(' ', '_', $param_class);
1371
-            }
1372
-            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1373
-            $param_class = $this->class_cache->getFqnForAlias($param_class, $class_name);
1374
-            // param is not even a class
1375
-            if (
1376
-                ! empty($param_class)
1377
-                && ! class_exists($param_class, false)
1378
-                // and something already exists in the incoming arguments for this param
1379
-                && array_key_exists($index, $argument_keys)
1380
-                && isset($arguments[ $argument_keys[ $index ] ])
1381
-            ) {
1382
-                // so let's skip this argument and move on to the next
1383
-                continue;
1384
-            }
1385
-            // parameter is type hinted as a class
1386
-            if ($param_class !== null) {
1387
-                // parameter exists as an incoming argument, AND it's the correct class
1388
-                if (
1389
-                    array_key_exists($index, $argument_keys)
1390
-                    && isset($arguments[ $argument_keys[ $index ] ])
1391
-                    && $arguments[ $argument_keys[ $index ] ] instanceof $param_class
1392
-                ) {
1393
-                    // skip this argument and move on to the next
1394
-                    continue;
1395
-                }
1396
-                // parameter should be injected
1397
-                if ($this->_dependency_map->has_dependency_for_class($class_name, $param_class)) {
1398
-                    $arguments = $this->_resolve_dependency(
1399
-                        $class_name,
1400
-                        $param_class,
1401
-                        $arguments,
1402
-                        $index
1403
-                    );
1404
-                }
1405
-            }
1406
-            if (empty($arguments[ $index ])) {
1407
-                $default_value = $this->mirror->getParameterDefaultValue(
1408
-                    $param,
1409
-                    $class_name,
1410
-                    $index
1411
-                );
1412
-                // if there's no default value, and the incoming argument is an array (albeit empty), then use that
1413
-                $arguments[ $index ] = $default_value === null
1414
-                                       && isset($arguments[ $index ])
1415
-                                       && is_array($arguments[ $index ])
1416
-                    ? $arguments[ $index ]
1417
-                    : $default_value;
1418
-            }
1419
-        }
1420
-        return $arguments;
1421
-    }
1422
-
1423
-
1424
-    /**
1425
-     * @param string $class_name
1426
-     * @param string $param_class
1427
-     * @param array  $arguments
1428
-     * @param mixed  $index
1429
-     * @return array
1430
-     * @throws InvalidArgumentException
1431
-     * @throws InvalidInterfaceException
1432
-     * @throws InvalidDataTypeException
1433
-     */
1434
-    protected function _resolve_dependency(string $class_name, string $param_class, array $arguments, $index): array
1435
-    {
1436
-        $dependency = null;
1437
-        // should dependency be loaded from cache ?
1438
-        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1439
-            $class_name,
1440
-            $param_class
1441
-        );
1442
-        $cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1443
-        // we might have a dependency...
1444
-        // let's MAYBE try and find it in our cache if that's what's been requested
1445
-        $cached_class = $cache_on
1446
-            ? $this->_get_cached_class($param_class)
1447
-            : null;
1448
-        // and grab it if it exists
1449
-        if ($cached_class instanceof $param_class) {
1450
-            $dependency = $cached_class;
1451
-        } elseif ($param_class !== $class_name) {
1452
-            // obtain the loader method from the dependency map
1453
-            $loader = $this->_dependency_map->class_loader($param_class);
1454
-            // is loader a custom closure ?
1455
-            if ($loader instanceof Closure) {
1456
-                $dependency = $loader($arguments);
1457
-            } else {
1458
-                // set the cache on property for the recursive loading call
1459
-                $this->_cache_on = $cache_on;
1460
-                // if not, then let's try and load it via the registry
1461
-                if ($loader && method_exists($this, $loader)) {
1462
-                    $dependency = $this->{$loader}($param_class);
1463
-                } else {
1464
-                    $dependency = LoaderFactory::getLoader()->load(
1465
-                        $param_class,
1466
-                        [],
1467
-                        $cache_on
1468
-                    );
1469
-                }
1470
-            }
1471
-        }
1472
-        // did we successfully find the correct dependency ?
1473
-        if ($dependency instanceof $param_class) {
1474
-            // then let's inject it into the incoming array of arguments at the correct location
1475
-            $arguments[ $index ] = $dependency;
1476
-        }
1477
-        return $arguments;
1478
-    }
1479
-
1480
-
1481
-    /**
1482
-     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1483
-     *
1484
-     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1485
-     *                          in the EE_Dependency_Map::$_class_loaders array,
1486
-     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1487
-     * @param array  $arguments
1488
-     * @return mixed
1489
-     */
1490
-    public static function factory(string $classname, array $arguments = [])
1491
-    {
1492
-        $loader = self::instance()->_dependency_map->class_loader($classname);
1493
-        if ($loader instanceof Closure) {
1494
-            return $loader($arguments);
1495
-        }
1496
-        if (method_exists(self::instance(), $loader)) {
1497
-            return self::instance()->{$loader}($classname, $arguments);
1498
-        }
1499
-        return null;
1500
-    }
1501
-
1502
-
1503
-    /**
1504
-     * Gets the addon by its class name
1505
-     *
1506
-     * @param string $class_name
1507
-     * @return EE_Addon
1508
-     */
1509
-    public function getAddon(string $class_name): ?EE_Addon
1510
-    {
1511
-        $class_name = str_replace('\\', '_', $class_name);
1512
-        $addon      = $this->_get_cached_class($class_name);
1513
-        if ($addon) {
1514
-            return $addon;
1515
-        }
1516
-        return $this->addons->{$class_name} ?? null;
1517
-    }
1518
-
1519
-
1520
-    /**
1521
-     * removes the addon from the internal cache
1522
-     *
1523
-     * @param string $class_name
1524
-     * @return void
1525
-     */
1526
-    public function removeAddon(string $class_name)
1527
-    {
1528
-        $class_name = str_replace('\\', '_', $class_name);
1529
-        $this->addons->remove($class_name);
1530
-    }
1531
-
1532
-
1533
-    /**
1534
-     * Gets the addon by its name/slug (not classname. For that, just
1535
-     * use the get_addon() method above
1536
-     *
1537
-     * @param string $name
1538
-     * @return EE_Addon
1539
-     */
1540
-    public function get_addon_by_name(string $name): ?EE_Addon
1541
-    {
1542
-        foreach ($this->addons as $addon) {
1543
-            if ($addon->name() === $name) {
1544
-                return $addon;
1545
-            }
1546
-        }
1547
-        return null;
1548
-    }
1549
-
1550
-
1551
-    /**
1552
-     * Gets an array of all the registered addons, where the keys are their names.
1553
-     * (ie, what each returns for their name() function)
1554
-     * They're already available on EE_Registry::instance()->addons as properties,
1555
-     * where each property's name is the addon's classname,
1556
-     * So if you just want to get the addon by classname,
1557
-     * OR use the get_addon() method above.
1558
-     * PLEASE  NOTE:
1559
-     * addons with Fully Qualified Class Names
1560
-     * have had the namespace separators converted to underscores,
1561
-     * so a classname like Fully\Qualified\ClassName
1562
-     * would have been converted to Fully_Qualified_ClassName
1563
-     *
1564
-     * @return EE_Addon[] where the KEYS are the addon's name()
1565
-     */
1566
-    public function get_addons_by_name(): array
1567
-    {
1568
-        $addons = [];
1569
-        foreach ($this->addons as $addon) {
1570
-            $addons[ $addon->name() ] = $addon;
1571
-        }
1572
-        return $addons;
1573
-    }
1574
-
1575
-
1576
-    /**
1577
-     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1578
-     * a stale copy of it around
1579
-     *
1580
-     * @param string $model_name
1581
-     * @return EEM_Base
1582
-     * @throws EE_Error
1583
-     * @throws ReflectionException
1584
-     */
1585
-    public function reset_model(string $model_name): ?EEM_Base
1586
-    {
1587
-        $model_class_name = strpos($model_name, 'EEM_') !== 0
1588
-            ? "EEM_$model_name"
1589
-            : $model_name;
1590
-        if (! $this->LIB->has($model_class_name)) {
1591
-            return null;
1592
-        }
1593
-        $model = $this->LIB->get($model_class_name);
1594
-        if (! $model instanceof EEM_Base) {
1595
-            return null;
1596
-        }
1597
-        // get that model reset it and make sure we nuke the old reference to it
1598
-        if ($model instanceof $model_class_name && is_callable([$model_class_name, 'reset'])) {
1599
-            $this->LIB->remove($model_class_name);
1600
-            $this->LIB->add($model_class_name, $model->reset());
1601
-        } else {
1602
-            throw new EE_Error(
1603
-                sprintf(
1604
-                    esc_html__('Model %s does not have a method "reset"', 'event_espresso'),
1605
-                    $model_name
1606
-                )
1607
-            );
1608
-        }
1609
-        return $model;
1610
-    }
1611
-
1612
-
1613
-    /**
1614
-     * Resets the registry.
1615
-     * The criteria for what gets reset is based on what can be shared between sites on the same request when
1616
-     * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1617
-     * - $_dependency_map
1618
-     * - $_class_abbreviations
1619
-     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1620
-     * - $REQ:  Still on the same request so no need to change.
1621
-     * - $CAP: There is no site specific state in the EE_Capability class.
1622
-     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1623
-     * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1624
-     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1625
-     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1626
-     *             switch or on the restore.
1627
-     * - $modules
1628
-     * - $shortcodes
1629
-     * - $widgets
1630
-     *
1631
-     * @param boolean $hard             [deprecated]
1632
-     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1633
-     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1634
-     *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1635
-     * @param bool    $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1636
-     *                                  client
1637
-     *                                  code instead can just change the model context to a different blog id if
1638
-     *                                  necessary
1639
-     * @return EE_Registry
1640
-     * @throws EE_Error
1641
-     * @throws ReflectionException
1642
-     * @throws InvalidArgumentException
1643
-     */
1644
-    public static function reset(bool $hard = false, bool $reinstantiate = true, bool $reset_models = true): EE_Registry
1645
-    {
1646
-        $hard              = apply_filters('FHEE__EE_Registry__reset__hard', $hard);
1647
-        $cached_properties = [
1648
-            'BUS',
1649
-            'CART',
1650
-            'CFG',
1651
-            'LIB',
1652
-            'MRM',
1653
-            'REQ',
1654
-            'SSN',
1655
-            'AssetsRegistry',
1656
-            // 'addons',
1657
-            // 'models',
1658
-            'modules',
1659
-            'shortcodes',
1660
-            'widgets',
1661
-        ];
1662
-        foreach ($cached_properties as $cached_property) {
1663
-            if (EE_UnitTestCase::$debug) {
1664
-                echo "\n\n" . __LINE__ . ') ' . strtoupper($cached_property);
1665
-            }
1666
-            if (
1667
-                ! property_exists(self::$_instance, $cached_property)
1668
-                || ! isset(self::$_instance->{$cached_property})
1669
-            ) {
1670
-                continue;
1671
-            }
1672
-            $cached = self::$_instance->{$cached_property};
1673
-            if (is_array($cached) || $cached instanceof RegistryContainer) {
1674
-                foreach ($cached as $class_name => $class) {
1675
-                    if (self::_reset_object($class_name, $class, $reset_models, $hard, $reinstantiate)) {
1676
-                        // because unset() doesn't guarantee object destruction
1677
-                        self::$_instance->{$cached_property}->{$class_name} = null;
1678
-                        unset(self::$_instance->{$cached_property}->{$class_name});
1679
-                    }
1680
-                }
1681
-                continue;
1682
-            }
1683
-            if (is_object($cached)) {
1684
-                if (self::_reset_object(get_class($cached), $cached, $reset_models, $hard, $reinstantiate)) {
1685
-                    // because unset() doesn't guarantee object destruction
1686
-                    self::$_instance->{$cached_property} = null;
1687
-                    unset(self::$_instance->{$cached_property});
1688
-                }
1689
-            }
1690
-        }
1691
-        if (EE_UnitTestCase::$debug) {
1692
-            echo "\n\n";
1693
-        }
1694
-        return self::$_instance;
1695
-    }
1696
-
1697
-
1698
-    /**
1699
-     * if passed object implements ResettableInterface, then call it's reset() method
1700
-     * if passed object implements InterminableInterface, then return false,
1701
-     * to indicate that it should NOT be cleared from the Registry cache
1702
-     *
1703
-     * @param string $class_name
1704
-     * @param        $object
1705
-     * @param bool   $reset_models
1706
-     * @param bool   $hard
1707
-     * @param bool   $reinstantiate
1708
-     * @return bool returns true if cached object should be unset
1709
-     * @throws EE_Error
1710
-     * @throws ReflectionException
1711
-     */
1712
-    private static function _reset_object(
1713
-        string $class_name,
1714
-        $object,
1715
-        bool $reset_models,
1716
-        bool $hard,
1717
-        bool $reinstantiate
1718
-    ): bool {
1719
-        if (EE_UnitTestCase::$debug) {
1720
-            echo "\n\n - reset $class_name";
1721
-        }
1722
-        if (! is_object($object)) {
1723
-            if (EE_UnitTestCase::$debug) {
1724
-                echo "\n --> not an object";
1725
-            }
1726
-            // don't unset anything that's not an object
1727
-            return false;
1728
-        }
1729
-        if ($object instanceof InterminableInterface) {
1730
-            if (EE_UnitTestCase::$debug) {
1731
-                echo "\n --> NO (interminable)";
1732
-            }
1733
-            // don't unset anything that's not terminable
1734
-            return false;
1735
-        }
1736
-        if ($object instanceof EED_Module) {
1737
-            $object::reset();
1738
-            if (EE_UnitTestCase::$debug) {
1739
-                echo "\n --> NO (module)";
1740
-            }
1741
-            // don't unset modules
1742
-            return false;
1743
-        }
1744
-        if ($object instanceof ResettableInterface) {
1745
-            // reset some "special" classes
1746
-            if ($object instanceof EE_Config) {
1747
-                EE_Config::reset($hard, $reinstantiate);
1748
-                if (EE_UnitTestCase::$debug) {
1749
-                    echo "\n --> NO (config)";
1750
-                }
1751
-                return false;
1752
-            }
1753
-            if ($object instanceof EEH_Activation) {
1754
-                EEH_Activation::reset();
1755
-                if (EE_UnitTestCase::$debug) {
1756
-                    echo "\n --> NO (activation)";
1757
-                }
1758
-                return false;
1759
-            }
1760
-            if ($object instanceof EEM_Base) {
1761
-                if ($reset_models) {
1762
-                    self::$_instance->reset_model($class_name);
1763
-                }
1764
-                return false;
1765
-            }
1766
-            if (method_exists($object, 'reset') && is_callable([$object, 'reset'])) {
1767
-                if (EE_UnitTestCase::$debug) {
1768
-                    echo "\n  --> NO (has reset)";
1769
-                }
1770
-                $object->reset();
1771
-                return false;
1772
-            }
1773
-        }
1774
-        if (EE_UnitTestCase::$debug) {
1775
-            echo "\n  --> YES ??? " . get_class($object);
1776
-        }
1777
-        // at least clear object from cache
1778
-        self::$_instance->clear_cached_class(get_class($object));
1779
-        return false;
1780
-    }
1781
-
1782
-
1783
-    /**
1784
-     * Gets all the custom post type models defined
1785
-     *
1786
-     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1787
-     */
1788
-    public function cpt_models(): array
1789
-    {
1790
-        $cpt_models = [];
1791
-        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1792
-            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1793
-                $cpt_models[ $short_name ] = $classname;
1794
-            }
1795
-        }
1796
-        return $cpt_models;
1797
-    }
1798
-
1799
-
1800
-    /**
1801
-     * @return EE_Config
1802
-     */
1803
-    public static function CFG(): EE_Config
1804
-    {
1805
-        return self::instance()->CFG;
1806
-    }
1807
-
1808
-
1809
-    /**
1810
-     * @param string $class_name
1811
-     * @return ReflectionClass
1812
-     * @throws ReflectionException
1813
-     * @throws InvalidDataTypeException
1814
-     * @deprecated 4.9.62.p
1815
-     */
1816
-    public function get_ReflectionClass(string $class_name): ReflectionClass
1817
-    {
1818
-        return $this->mirror->getReflectionClass($class_name);
1819
-    }
25
+	/**
26
+	 * @var EE_Registry $_instance
27
+	 */
28
+	private static $_instance;
29
+
30
+	/**
31
+	 * @var EE_Dependency_Map $_dependency_map
32
+	 */
33
+	protected $_dependency_map;
34
+
35
+	/**
36
+	 * @var Mirror
37
+	 */
38
+	private $mirror;
39
+
40
+	/**
41
+	 * @var ClassInterfaceCache $class_cache
42
+	 */
43
+	private $class_cache;
44
+
45
+	/**
46
+	 * @var array $_class_abbreviations
47
+	 */
48
+	protected $_class_abbreviations = [];
49
+
50
+	/**
51
+	 * @var CommandBusInterface $BUS
52
+	 */
53
+	public $BUS;
54
+
55
+	/**
56
+	 * @var EE_Cart $CART
57
+	 */
58
+	public $CART;
59
+
60
+	/**
61
+	 * @var EE_Config $CFG
62
+	 */
63
+	public $CFG;
64
+
65
+	/**
66
+	 * @var EE_Network_Config $NET_CFG
67
+	 */
68
+	public $NET_CFG;
69
+
70
+	/**
71
+	 * RegistryContainer for storing library classes in
72
+	 *
73
+	 * @var RegistryContainer $LIB
74
+	 */
75
+	public $LIB;
76
+
77
+	/**
78
+	 * @var EE_Request_Handler $REQ
79
+	 * @deprecated 4.10.14.p
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
+	 * RegistryContainer for holding addons which have registered themselves to work with EE core
107
+	 *
108
+	 * @var RegistryContainer|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 = [];
118
+
119
+	/**
120
+	 * @var RegistryContainer|EED_Module[] $modules
121
+	 */
122
+	public $modules;
123
+
124
+	/**
125
+	 * @var RegistryContainer|EES_Shortcode[] $shortcodes
126
+	 */
127
+	public $shortcodes;
128
+
129
+	/**
130
+	 * @var RegistryContainer|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 = [];
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 = [];
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
+	): EE_Registry {
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', [$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
+			[
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', [], 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', [$this, 'init']);
286
+	}
287
+
288
+
289
+	/**
290
+	 * @return void
291
+	 */
292
+	public function init()
293
+	{
294
+		// Get current page protocol
295
+		$protocol = is_ssl() ? '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;
299
+	}
300
+
301
+
302
+	/**
303
+	 * @return array
304
+	 */
305
+	public static function sanitize_i18n_js_strings(): array
306
+	{
307
+		$i18n_js_strings = (array) self::$i18n_js_strings;
308
+		foreach ($i18n_js_strings as $key => $value) {
309
+			if (is_scalar($value)) {
310
+				$decoded_value           = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
311
+				$i18n_js_strings[ $key ] = wp_strip_all_tags($decoded_value);
312
+			}
313
+		}
314
+		return $i18n_js_strings;
315
+	}
316
+
317
+
318
+	/**
319
+	 * localize_i18n_js_strings
320
+	 *
321
+	 * @return string
322
+	 */
323
+	public static function localize_i18n_js_strings(): string
324
+	{
325
+		$i18n_js_strings = EE_Registry::sanitize_i18n_js_strings();
326
+		return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
327
+	}
328
+
329
+
330
+	/**
331
+	 * @param mixed string | EED_Module $module
332
+	 * @throws OutOfBoundsException
333
+	 * @throws InvalidArgumentException
334
+	 * @throws InvalidInterfaceException
335
+	 * @throws InvalidDataTypeException
336
+	 * @throws EE_Error
337
+	 * @throws ReflectionException
338
+	 */
339
+	public function add_module($module)
340
+	{
341
+		if ($module instanceof EED_Module) {
342
+			$module_class = get_class($module);
343
+			$this->modules->add($module_class, $module);
344
+		} else {
345
+			if (! class_exists('EE_Module_Request_Router', false)) {
346
+				$this->load_core('Module_Request_Router');
347
+			}
348
+			EE_Module_Request_Router::module_factory($module);
349
+		}
350
+	}
351
+
352
+
353
+	/**
354
+	 * @param string $module_name
355
+	 * @return mixed EED_Module | NULL
356
+	 */
357
+	public function get_module(string $module_name = '')
358
+	{
359
+		return $this->modules->get($module_name);
360
+	}
361
+
362
+
363
+	/**
364
+	 * loads core classes - must be singletons
365
+	 *
366
+	 * @param string $class_name - simple class name ie: session
367
+	 * @param mixed  $arguments
368
+	 * @param bool   $load_only
369
+	 * @return bool|null|object
370
+	 * @throws InvalidInterfaceException
371
+	 * @throws InvalidDataTypeException
372
+	 * @throws EE_Error
373
+	 * @throws ReflectionException
374
+	 * @throws InvalidArgumentException
375
+	 */
376
+	public function load_core(string $class_name, $arguments = [], bool $load_only = false)
377
+	{
378
+		$core_paths = (array) apply_filters(
379
+			'FHEE__EE_Registry__load_core__core_paths',
380
+			[
381
+				EE_CORE,
382
+				EE_ADMIN,
383
+				EE_CPTS,
384
+				EE_CORE . 'CPTs/',
385
+				EE_CORE . 'data_migration_scripts/',
386
+				EE_CORE . 'request_stack/',
387
+				EE_CORE . 'middleware/',
388
+			]
389
+		);
390
+		// retrieve instantiated class
391
+		return $this->_load(
392
+			$core_paths,
393
+			'EE_',
394
+			$class_name,
395
+			'core',
396
+			$arguments,
397
+			false,
398
+			true,
399
+			$load_only
400
+		);
401
+	}
402
+
403
+
404
+	/**
405
+	 * loads service classes
406
+	 *
407
+	 * @param string $class_name - simple class name ie: session
408
+	 * @param mixed  $arguments
409
+	 * @param bool   $load_only
410
+	 * @return bool|null|object
411
+	 * @throws InvalidInterfaceException
412
+	 * @throws InvalidDataTypeException
413
+	 * @throws EE_Error
414
+	 * @throws ReflectionException
415
+	 * @throws InvalidArgumentException
416
+	 * @deprecated  4.10.33.p
417
+	 */
418
+	public function load_service(string $class_name, $arguments = [], bool $load_only = false)
419
+	{
420
+		$service_paths = (array) apply_filters(
421
+			'FHEE__EE_Registry__load_service__service_paths',
422
+			[
423
+				EE_CORE . 'services/',
424
+			]
425
+		);
426
+		// retrieve instantiated class
427
+		return $this->_load(
428
+			$service_paths,
429
+			'EE_',
430
+			$class_name,
431
+			'class',
432
+			$arguments,
433
+			false,
434
+			true,
435
+			$load_only
436
+		);
437
+	}
438
+
439
+
440
+	/**
441
+	 * loads data_migration_scripts
442
+	 *
443
+	 * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
444
+	 * @param mixed  $arguments
445
+	 * @return bool|null|object
446
+	 * @throws InvalidInterfaceException
447
+	 * @throws InvalidDataTypeException
448
+	 * @throws EE_Error
449
+	 * @throws ReflectionException
450
+	 * @throws InvalidArgumentException
451
+	 */
452
+	public function load_dms(string $class_name, $arguments = [])
453
+	{
454
+		// retrieve instantiated class
455
+		return $this->_load(
456
+			EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
457
+			'EE_DMS_',
458
+			$class_name,
459
+			'dms',
460
+			$arguments,
461
+			false,
462
+			false
463
+		);
464
+	}
465
+
466
+
467
+	/**
468
+	 * loads object creating classes - must be singletons
469
+	 *
470
+	 * @param string $class_name - simple class name ie: attendee
471
+	 * @param mixed  $arguments  - an array of arguments to pass to the class
472
+	 * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
473
+	 *                           instantiate
474
+	 * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
475
+	 *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
476
+	 * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
477
+	 *                           (default)
478
+	 * @return EE_Base_Class|mixed|bool|null
479
+	 * @throws InvalidInterfaceException
480
+	 * @throws InvalidDataTypeException
481
+	 * @throws EE_Error
482
+	 * @throws ReflectionException
483
+	 * @throws InvalidArgumentException
484
+	 */
485
+	public function load_class(
486
+		string $class_name,
487
+		$arguments = [],
488
+		bool $from_db = false,
489
+		bool $cache = true,
490
+		bool $load_only = false
491
+	) {
492
+		$paths = (array) apply_filters(
493
+			'FHEE__EE_Registry__load_class__paths',
494
+			[
495
+				EE_CORE,
496
+				EE_CLASSES,
497
+				EE_BUSINESS,
498
+			]
499
+		);
500
+		// retrieve instantiated class
501
+		return $this->_load(
502
+			$paths,
503
+			'EE_',
504
+			$class_name,
505
+			'class',
506
+			$arguments,
507
+			$from_db,
508
+			$cache,
509
+			$load_only
510
+		);
511
+	}
512
+
513
+
514
+	/**
515
+	 * loads helper classes - must be singletons
516
+	 *
517
+	 * @param string $class_name - simple class name ie: price
518
+	 * @param mixed  $arguments
519
+	 * @param bool   $load_only
520
+	 * @return bool|null|object
521
+	 * @throws InvalidInterfaceException
522
+	 * @throws InvalidDataTypeException
523
+	 * @throws EE_Error
524
+	 * @throws ReflectionException
525
+	 * @throws InvalidArgumentException
526
+	 */
527
+	public function load_helper(string $class_name, $arguments = [], bool $load_only = true)
528
+	{
529
+		// todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
530
+		$helper_paths = (array) apply_filters('FHEE__EE_Registry__load_helper__helper_paths', [EE_HELPERS]);
531
+		// retrieve instantiated class
532
+		return $this->_load(
533
+			$helper_paths,
534
+			'EEH_',
535
+			$class_name,
536
+			'helper',
537
+			$arguments,
538
+			false,
539
+			true,
540
+			$load_only
541
+		);
542
+	}
543
+
544
+
545
+	/**
546
+	 * loads core classes - must be singletons
547
+	 *
548
+	 * @param string $class_name - simple class name ie: session
549
+	 * @param mixed  $arguments
550
+	 * @param bool   $load_only
551
+	 * @param bool   $cache      whether to cache the object or not.
552
+	 * @return bool|null|object
553
+	 * @throws InvalidInterfaceException
554
+	 * @throws InvalidDataTypeException
555
+	 * @throws EE_Error
556
+	 * @throws ReflectionException
557
+	 * @throws InvalidArgumentException
558
+	 */
559
+	public function load_lib(string $class_name, $arguments = [], bool $load_only = false, bool $cache = true)
560
+	{
561
+		$paths = [
562
+			EE_LIBRARIES,
563
+			EE_LIBRARIES . 'messages/',
564
+			EE_LIBRARIES . 'shortcodes/',
565
+			EE_LIBRARIES . 'qtips/',
566
+			EE_LIBRARIES . 'payment_methods/',
567
+		];
568
+		// retrieve instantiated class
569
+		return $this->_load(
570
+			$paths,
571
+			'EE_',
572
+			$class_name,
573
+			'lib',
574
+			$arguments,
575
+			false,
576
+			$cache,
577
+			$load_only
578
+		);
579
+	}
580
+
581
+
582
+	/**
583
+	 * loads model classes - must be singletons
584
+	 *
585
+	 * @param string $class_name - simple class name ie: price
586
+	 * @param mixed  $arguments
587
+	 * @param bool   $load_only
588
+	 * @return bool|null|object
589
+	 * @throws InvalidInterfaceException
590
+	 * @throws InvalidDataTypeException
591
+	 * @throws EE_Error
592
+	 * @throws ReflectionException
593
+	 * @throws InvalidArgumentException
594
+	 */
595
+	public function load_model(string $class_name, $arguments = [], bool $load_only = false)
596
+	{
597
+		$paths = (array) apply_filters(
598
+			'FHEE__EE_Registry__load_model__paths',
599
+			[
600
+				EE_MODELS,
601
+				EE_CORE,
602
+			]
603
+		);
604
+		// retrieve instantiated class
605
+		return $this->_load(
606
+			$paths,
607
+			'EEM_',
608
+			$class_name,
609
+			'model',
610
+			$arguments,
611
+			false,
612
+			true,
613
+			$load_only
614
+		);
615
+	}
616
+
617
+
618
+	/**
619
+	 * loads model classes - must be singletons
620
+	 *
621
+	 * @param string $class_name - simple class name ie: price
622
+	 * @param mixed  $arguments
623
+	 * @param bool   $load_only
624
+	 * @return bool|null|object
625
+	 * @throws InvalidInterfaceException
626
+	 * @throws InvalidDataTypeException
627
+	 * @throws EE_Error
628
+	 * @throws ReflectionException
629
+	 * @throws InvalidArgumentException
630
+	 * @deprecated  4.10.33.p
631
+	 */
632
+	public function load_model_class(string $class_name, $arguments = [], bool $load_only = true)
633
+	{
634
+		$paths = [
635
+			EE_MODELS . 'fields/',
636
+			EE_MODELS . 'helpers/',
637
+			EE_MODELS . 'relations/',
638
+			EE_MODELS . 'strategies/',
639
+		];
640
+		// retrieve instantiated class
641
+		return $this->_load(
642
+			$paths,
643
+			'EE_',
644
+			$class_name,
645
+			'',
646
+			$arguments,
647
+			false,
648
+			true,
649
+			$load_only
650
+		);
651
+	}
652
+
653
+
654
+	/**
655
+	 * Determines if $model_name is the name of an actual EE model.
656
+	 *
657
+	 * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
658
+	 * @return boolean
659
+	 */
660
+	public function is_model_name(string $model_name): bool
661
+	{
662
+		return isset($this->models[ $model_name ]);
663
+	}
664
+
665
+
666
+	/**
667
+	 * generic class loader
668
+	 *
669
+	 * @param string $path_to_file - directory path to file location, not including filename
670
+	 * @param string $file_name    - file name  ie:  my_file.php, including extension
671
+	 * @param string $type         - file type - core? class? helper? model?
672
+	 * @param mixed  $arguments
673
+	 * @param bool   $load_only
674
+	 * @return bool|null|object
675
+	 * @throws InvalidInterfaceException
676
+	 * @throws InvalidDataTypeException
677
+	 * @throws EE_Error
678
+	 * @throws ReflectionException
679
+	 * @throws InvalidArgumentException
680
+	 */
681
+	public function load_file(
682
+		string $path_to_file,
683
+		string $file_name,
684
+		string $type = '',
685
+		$arguments = [],
686
+		bool $load_only = true
687
+	) {
688
+		// retrieve instantiated class
689
+		return $this->_load(
690
+			(array) $path_to_file,
691
+			'',
692
+			$file_name,
693
+			$type,
694
+			$arguments,
695
+			false,
696
+			true,
697
+			$load_only
698
+		);
699
+	}
700
+
701
+
702
+	/**
703
+	 * @param string $path_to_file - directory path to file location, not including filename
704
+	 * @param string $class_name   - full class name  ie:  My_Class
705
+	 * @param string $type         - file type - core? class? helper? model?
706
+	 * @param mixed  $arguments
707
+	 * @param bool   $load_only
708
+	 * @return bool|null|object
709
+	 * @throws InvalidInterfaceException
710
+	 * @throws InvalidDataTypeException
711
+	 * @throws EE_Error
712
+	 * @throws ReflectionException
713
+	 * @throws InvalidArgumentException
714
+	 * @deprecated  4.10.33.p
715
+	 */
716
+	public function load_addon(
717
+		string $path_to_file,
718
+		string $class_name,
719
+		string $type = 'class',
720
+		$arguments = [],
721
+		bool $load_only = false
722
+	) {
723
+		// retrieve instantiated class
724
+		return $this->_load(
725
+			(array) $path_to_file,
726
+			'addon',
727
+			$class_name,
728
+			$type,
729
+			$arguments,
730
+			false,
731
+			true,
732
+			$load_only
733
+		);
734
+	}
735
+
736
+
737
+	/**
738
+	 * instantiates, caches, and automatically resolves dependencies
739
+	 * for classes that use a Fully Qualified Class Name.
740
+	 * if the class is not capable of being loaded using PSR-4 autoloading,
741
+	 * then you need to use one of the existing load_*() methods
742
+	 * which can resolve the classname and filepath from the passed arguments
743
+	 *
744
+	 * @param string      $class_name Fully Qualified Class Name
745
+	 * @param array       $arguments  an argument, or array of arguments to pass to the class upon instantiation
746
+	 * @param bool        $cache      whether to cache the instantiated object for reuse
747
+	 * @param bool        $from_db    some classes are instantiated from the db
748
+	 *                                and thus call a different method to instantiate
749
+	 * @param bool        $load_only  if true, will only load the file, but will NOT instantiate an object
750
+	 * @param bool|string $addon      if true, will cache the object in the EE_Registry->$addons array
751
+	 * @return bool|null|mixed     null = failure to load or instantiate class object.
752
+	 *                                object = class loaded and instantiated successfully.
753
+	 *                                bool = fail or success when $load_only is true
754
+	 * @throws InvalidInterfaceException
755
+	 * @throws InvalidDataTypeException
756
+	 * @throws EE_Error
757
+	 * @throws ReflectionException
758
+	 * @throws InvalidArgumentException
759
+	 */
760
+	public function create(
761
+		string $class_name = '',
762
+		array $arguments = [],
763
+		bool $cache = false,
764
+		bool $from_db = false,
765
+		bool $load_only = false,
766
+		bool $addon = false
767
+	) {
768
+		$class_name   = ltrim($class_name, '\\');
769
+		$class_name   = $this->class_cache->getFqnForAlias($class_name);
770
+		$class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
771
+		// if a non-FQCN was passed, then
772
+		// verifyClassExists() might return an object
773
+		// or it could return null if the class just could not be found anywhere
774
+		if ($class_exists instanceof $class_name || $class_exists === null) {
775
+			// either way, return the results
776
+			return $class_exists;
777
+		}
778
+		$class_name = $class_exists;
779
+		// if we're only loading the class and it already exists, then let's just return true immediately
780
+		if ($load_only) {
781
+			return true;
782
+		}
783
+		$addon = $addon ? 'addon' : '';
784
+		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
785
+		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
786
+		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
787
+		if ($this->_cache_on && $cache) {
788
+			// return object if it's already cached
789
+			$cached_class = $this->_get_cached_class($class_name, $addon, $arguments);
790
+
791
+			if ($cached_class !== null) {
792
+				return $cached_class;
793
+			}
794
+		}
795
+		// obtain the loader method from the dependency map
796
+		$loader = $this->_dependency_map->class_loader($class_name);
797
+		// instantiate the requested object
798
+		if ($loader instanceof Closure) {
799
+			$class_obj = $loader($arguments);
800
+		} else {
801
+			if ($loader && method_exists($this, $loader)) {
802
+				$class_obj = $this->{$loader}($class_name, $arguments);
803
+			} else {
804
+				$class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
805
+			}
806
+		}
807
+		if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) {
808
+			// save it for later... kinda like gum  { : $
809
+			$this->_set_cached_class(
810
+				$class_obj,
811
+				$class_name,
812
+				$addon,
813
+				$from_db,
814
+				$arguments
815
+			);
816
+		}
817
+		$this->_cache_on = true;
818
+		return $class_obj;
819
+	}
820
+
821
+
822
+	/**
823
+	 * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
824
+	 *
825
+	 * @param string|mixed $class_name
826
+	 * @param array        $arguments
827
+	 * @param int          $attempt
828
+	 * @return mixed
829
+	 */
830
+	private function loadOrVerifyClassExists($class_name, array $arguments, int $attempt = 1)
831
+	{
832
+		if (is_object($class_name) || class_exists($class_name)) {
833
+			return $class_name;
834
+		}
835
+		switch ($attempt) {
836
+			case 1:
837
+				// if it's a FQCN then maybe the class is registered with a preceding \
838
+				$class_name = strpos($class_name, '\\') !== false
839
+					? '\\' . ltrim($class_name, '\\')
840
+					: $class_name;
841
+				break;
842
+			case 2:
843
+				//
844
+				$loader = $this->_dependency_map->class_loader($class_name);
845
+				if ($loader && method_exists($this, $loader)) {
846
+					return $this->{$loader}($class_name, $arguments);
847
+				}
848
+				break;
849
+			case 3:
850
+			default:
851
+				return null;
852
+		}
853
+		$attempt++;
854
+		return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
855
+	}
856
+
857
+
858
+	/**
859
+	 * instantiates, caches, and injects dependencies for classes
860
+	 *
861
+	 * @param array       $file_paths   an array of paths to folders to look in
862
+	 * @param string      $class_prefix EE  or EEM or... ???
863
+	 * @param bool|string $class_name   $class name
864
+	 * @param string      $type         file type - core? class? helper? model?
865
+	 * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
866
+	 * @param bool        $from_db      some classes are instantiated from the db
867
+	 *                                  and thus call a different method to instantiate
868
+	 * @param bool        $cache        whether to cache the instantiated object for reuse
869
+	 * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
870
+	 * @return EE_Base_Class|mixed|bool|null = failure to load or instantiate class object.
871
+	 *                                  object = class loaded and instantiated successfully.
872
+	 *                                  bool = fail or success when $load_only is true
873
+	 * @throws EE_Error
874
+	 * @throws ReflectionException
875
+	 * @throws InvalidInterfaceException
876
+	 * @throws InvalidDataTypeException
877
+	 * @throws InvalidArgumentException
878
+	 */
879
+	protected function _load(
880
+		array $file_paths = [],
881
+		string $class_prefix = 'EE_',
882
+		string $class_name = '',
883
+		string $type = 'class',
884
+		array $arguments = [],
885
+		bool $from_db = false,
886
+		bool $cache = true,
887
+		bool $load_only = false
888
+	) {
889
+		$class_name = ltrim($class_name, '\\');
890
+		// strip php file extension
891
+		$class_name = str_replace('.php', '', trim($class_name));
892
+		// does the class have a prefix ?
893
+		if (! empty($class_prefix) && $class_prefix !== 'addon') {
894
+			// make sure $class_prefix is uppercase
895
+			$class_prefix = strtoupper(trim($class_prefix));
896
+			// add class prefix ONCE!!!
897
+			$class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
898
+		}
899
+		$class_name   = $this->class_cache->getFqnForAlias($class_name);
900
+		$class_exists = class_exists($class_name, false);
901
+		// if we're only loading the class and it already exists, then let's just return true immediately
902
+		if ($load_only && $class_exists) {
903
+			return true;
904
+		}
905
+		$arguments = is_array($arguments) ? $arguments : [$arguments];
906
+		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
907
+		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
908
+		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
909
+		if ($this->_cache_on && $cache && ! $load_only) {
910
+			// return object if it's already cached
911
+			$cached_class = $this->_get_cached_class($class_name, $class_prefix, $arguments);
912
+			if ($cached_class !== null) {
913
+				return $cached_class;
914
+			}
915
+		}
916
+		// if the class doesn't already exist.. then we need to try and find the file and load it
917
+		if (! $class_exists) {
918
+			// get full path to file
919
+			$path = $this->_resolve_path($class_name, $type, $file_paths);
920
+			// load the file
921
+			$loaded = $this->_require_file($path, $class_name, $type, $file_paths);
922
+			// if we are only loading a file but NOT instantiating an object
923
+			// then return boolean for whether class was loaded or not
924
+			if ($load_only) {
925
+				return $loaded;
926
+			}
927
+			// if an object was expected but loading failed, then return nothing
928
+			if (! $loaded) {
929
+				return null;
930
+			}
931
+		}
932
+		// instantiate the requested object
933
+		$class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
934
+		if ($this->_cache_on && $cache) {
935
+			// save it for later... kinda like gum  { : $
936
+			$this->_set_cached_class(
937
+				$class_obj,
938
+				$class_name,
939
+				$class_prefix,
940
+				$from_db,
941
+				$arguments
942
+			);
943
+		}
944
+		$this->_cache_on = true;
945
+		return $class_obj;
946
+	}
947
+
948
+
949
+	/**
950
+	 * @param string $class_name
951
+	 * @param string $default have to specify something, but not anything that will conflict
952
+	 * @return mixed|string
953
+	 */
954
+	protected function get_class_abbreviation(string $class_name, string $default = 'FANCY_BATMAN_PANTS')
955
+	{
956
+		return $this->_class_abbreviations[ $class_name ] ?? $default;
957
+	}
958
+
959
+
960
+	/**
961
+	 * attempts to find a cached version of the requested class
962
+	 * by looking in the following places:
963
+	 *        $this->{$class_abbreviation}            ie:    $this->CART
964
+	 *        $this->{$class_name}                        ie:    $this->Some_Class
965
+	 *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
966
+	 *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
967
+	 *
968
+	 * @param string $class_name
969
+	 * @param string $class_prefix
970
+	 * @param array  $arguments
971
+	 * @return mixed
972
+	 */
973
+	protected function _get_cached_class(
974
+		string $class_name,
975
+		string $class_prefix = '',
976
+		array $arguments = []
977
+	) {
978
+		if ($class_name === 'EE_Registry') {
979
+			return $this;
980
+		}
981
+		$class_abbreviation = $this->get_class_abbreviation($class_name);
982
+		// check if class has already been loaded, and return it if it has been
983
+		if (isset($this->{$class_abbreviation})) {
984
+			return $this->{$class_abbreviation};
985
+		}
986
+		$class_name = str_replace('\\', '_', $class_name);
987
+		if (isset($this->{$class_name})) {
988
+			return $this->{$class_name};
989
+		}
990
+		if ($class_prefix === 'addon' && $this->addons->has($class_name)) {
991
+			return $this->addons->get($class_name);
992
+		}
993
+		$object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments);
994
+		if ($this->LIB->has($object_identifier)) {
995
+			return $this->LIB->get($object_identifier);
996
+		}
997
+		foreach ($this->LIB as $key => $object) {
998
+			if (
999
+				// request does not contain new arguments and therefore no args identifier
1000
+				! $this->object_identifier->hasArguments($object_identifier)
1001
+				// but previously cached class with args was found
1002
+				&& $this->object_identifier->fqcnMatchesObjectIdentifier($class_name, $key)
1003
+			) {
1004
+				return $object;
1005
+			}
1006
+		}
1007
+		return null;
1008
+	}
1009
+
1010
+
1011
+	/**
1012
+	 * removes a cached version of the requested class
1013
+	 *
1014
+	 * @param string  $class_name
1015
+	 * @param boolean $addon
1016
+	 * @param array   $arguments
1017
+	 * @return boolean
1018
+	 */
1019
+	public function clear_cached_class(
1020
+		string $class_name,
1021
+		bool $addon = false,
1022
+		array $arguments = []
1023
+	): bool {
1024
+		$class_abbreviation = $this->get_class_abbreviation($class_name);
1025
+		// check if class has already been loaded, and return it if it has been
1026
+		if (isset($this->{$class_abbreviation}) && ! $this->{$class_abbreviation} instanceof InterminableInterface) {
1027
+			$this->{$class_abbreviation} = null;
1028
+			return true;
1029
+		}
1030
+		$class_name = str_replace('\\', '_', $class_name);
1031
+		if (isset($this->{$class_name}) && ! $this->{$class_name} instanceof InterminableInterface) {
1032
+			$this->{$class_name} = null;
1033
+			return true;
1034
+		}
1035
+		if ($addon && $this->addons->has($class_name)) {
1036
+			$this->addons->remove($class_name);
1037
+			return true;
1038
+		}
1039
+		$object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments);
1040
+		if ($this->LIB->has($object_identifier) && ! $this->LIB->get($object_identifier) instanceof InterminableInterface) {
1041
+			$this->LIB->remove($object_identifier);
1042
+			return true;
1043
+		}
1044
+		return false;
1045
+	}
1046
+
1047
+
1048
+	/**
1049
+	 * _set_cached_class
1050
+	 * attempts to cache the instantiated class locally
1051
+	 * in one of the following places, in the following order:
1052
+	 *        $this->{class_abbreviation}   ie:    $this->CART
1053
+	 *        $this->{$class_name}          ie:    $this->Some_Class
1054
+	 *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1055
+	 *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1056
+	 *
1057
+	 * @param object $class_obj
1058
+	 * @param string $class_name
1059
+	 * @param string $class_prefix
1060
+	 * @param bool   $from_db
1061
+	 * @param array  $arguments
1062
+	 * @return void
1063
+	 */
1064
+	protected function _set_cached_class(
1065
+		$class_obj,
1066
+		string $class_name,
1067
+		string $class_prefix = '',
1068
+		bool $from_db = false,
1069
+		array $arguments = []
1070
+	) {
1071
+		if ($class_name === 'EE_Registry' || empty($class_obj)) {
1072
+			return;
1073
+		}
1074
+		// return newly instantiated class
1075
+		$class_abbreviation = $this->get_class_abbreviation($class_name, '');
1076
+		if ($class_abbreviation) {
1077
+			$this->{$class_abbreviation} = $class_obj;
1078
+			return;
1079
+		}
1080
+		$class_name = str_replace('\\', '_', $class_name);
1081
+		if (property_exists($this, $class_name)) {
1082
+			$this->{$class_name} = $class_obj;
1083
+			return;
1084
+		}
1085
+		if ($class_prefix === 'addon') {
1086
+			$this->addons->add($class_name, $class_obj);
1087
+			return;
1088
+		}
1089
+		if (! $from_db) {
1090
+			$class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1091
+			$this->LIB->add($class_name, $class_obj);
1092
+		}
1093
+	}
1094
+
1095
+
1096
+	/**
1097
+	 * attempts to find a full valid filepath for the requested class.
1098
+	 * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
1099
+	 * then returns that path if the target file has been found and is readable
1100
+	 *
1101
+	 * @param string $class_name
1102
+	 * @param string $type
1103
+	 * @param array  $file_paths
1104
+	 * @return string | bool
1105
+	 */
1106
+	protected function _resolve_path(string $class_name, string $type = '', array $file_paths = [])
1107
+	{
1108
+		// make sure $file_paths is an array
1109
+		$file_paths = is_array($file_paths)
1110
+			? $file_paths
1111
+			: [$file_paths];
1112
+		// cycle thru paths
1113
+		foreach ($file_paths as $key => $file_path) {
1114
+			// convert all separators to proper /, if no filepath, then use EE_CLASSES
1115
+			$file_path = $file_path
1116
+				? str_replace(['/', '\\'], '/', $file_path)
1117
+				: EE_CLASSES;
1118
+			// prep file type
1119
+			$type = ! empty($type)
1120
+				? trim($type, '.') . '.'
1121
+				: '';
1122
+			// build full file path
1123
+			$file_paths[ $key ] = rtrim($file_path, '/') . '/' . $class_name . '.' . $type . 'php';
1124
+			// does the file exist and can be read ?
1125
+			if (is_readable($file_paths[ $key ])) {
1126
+				return $file_paths[ $key ];
1127
+			}
1128
+		}
1129
+		return false;
1130
+	}
1131
+
1132
+
1133
+	/**
1134
+	 * basically just performs a require_once()
1135
+	 * but with some error handling
1136
+	 *
1137
+	 * @param string $path
1138
+	 * @param string $class_name
1139
+	 * @param string $type
1140
+	 * @param array  $file_paths
1141
+	 * @return bool
1142
+	 * @throws EE_Error
1143
+	 * @throws ReflectionException
1144
+	 */
1145
+	protected function _require_file(string $path, string $class_name, string $type = '', array $file_paths = []): bool
1146
+	{
1147
+		$this->resolve_legacy_class_parent($class_name);
1148
+		// don't give up! you gotta...
1149
+		try {
1150
+			// does the file exist and can it be read ?
1151
+			if (! $path) {
1152
+				// just in case the file has already been autoloaded,
1153
+				// but discrepancies in the naming schema are preventing it from
1154
+				// being loaded via one of the EE_Registry::load_*() methods,
1155
+				// then let's try one last hail mary before throwing an exception
1156
+				// and call class_exists() again, but with autoloading turned ON
1157
+				if (class_exists($class_name)) {
1158
+					return true;
1159
+				}
1160
+				// so sorry, can't find the file
1161
+				throw new EE_Error(
1162
+					sprintf(
1163
+						esc_html__(
1164
+							'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',
1165
+							'event_espresso'
1166
+						),
1167
+						trim($type, '.'),
1168
+						$class_name,
1169
+						'<br />' . implode(',<br />', $file_paths)
1170
+					)
1171
+				);
1172
+			}
1173
+			// get the file
1174
+			require_once($path);
1175
+			// if the class isn't already declared somewhere
1176
+			if (class_exists($class_name, false) === false) {
1177
+				// so sorry, not a class
1178
+				throw new EE_Error(
1179
+					sprintf(
1180
+						esc_html__(
1181
+							'The %s file %s does not appear to contain the %s Class.',
1182
+							'event_espresso'
1183
+						),
1184
+						$type,
1185
+						$path,
1186
+						$class_name
1187
+					)
1188
+				);
1189
+			}
1190
+		} catch (EE_Error $e) {
1191
+			$e->get_error();
1192
+			return false;
1193
+		}
1194
+		return true;
1195
+	}
1196
+
1197
+
1198
+	/**
1199
+	 * Some of our legacy classes that extended a parent class would simply use a require() statement
1200
+	 * before their class declaration in order to ensure that the parent class was loaded.
1201
+	 * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1202
+	 * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1203
+	 *
1204
+	 * @param string $class_name
1205
+	 */
1206
+	protected function resolve_legacy_class_parent(string $class_name = '')
1207
+	{
1208
+		try {
1209
+			$legacy_parent_class_map = [
1210
+				'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php',
1211
+			];
1212
+			if (isset($legacy_parent_class_map[ $class_name ])) {
1213
+				require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ];
1214
+			}
1215
+		} catch (Exception $exception) {
1216
+		}
1217
+	}
1218
+
1219
+
1220
+	/**
1221
+	 * _create_object
1222
+	 * Attempts to instantiate the requested class via any of the
1223
+	 * commonly used instantiation methods employed throughout EE.
1224
+	 * The priority for instantiation is as follows:
1225
+	 *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1226
+	 *        - model objects via their 'new_instance_from_db' method
1227
+	 *        - model objects via their 'new_instance' method
1228
+	 *        - "singleton" classes" via their 'instance' method
1229
+	 *    - standard instantiable classes via their __constructor
1230
+	 * Prior to instantiation, if the classname exists in the dependency_map,
1231
+	 * then the constructor for the requested class will be examined to determine
1232
+	 * if any dependencies exist, and if they can be injected.
1233
+	 * If so, then those classes will be added to the array of arguments passed to the constructor
1234
+	 *
1235
+	 * @param string $class_name
1236
+	 * @param array  $arguments
1237
+	 * @param string $type
1238
+	 * @param bool   $from_db
1239
+	 * @return null|object|bool
1240
+	 * @throws InvalidArgumentException
1241
+	 * @throws InvalidInterfaceException
1242
+	 * @throws EE_Error
1243
+	 * @throws ReflectionException
1244
+	 * @throws InvalidDataTypeException
1245
+	 */
1246
+	protected function _create_object(
1247
+		string $class_name,
1248
+		array $arguments = [],
1249
+		string $type = '',
1250
+		bool $from_db = false
1251
+	) {
1252
+		// create reflection
1253
+		$reflector = $this->mirror->getReflectionClass($class_name);
1254
+		// make sure arguments are an array
1255
+		$arguments = is_array($arguments)
1256
+			? $arguments
1257
+			: [$arguments];
1258
+		// and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1259
+		// else wrap it in an additional array so that it doesn't get split into multiple parameters
1260
+		$arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1261
+			? $arguments
1262
+			: [$arguments];
1263
+		// attempt to inject dependencies ?
1264
+		if ($this->_dependency_map->has($class_name)) {
1265
+			$arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1266
+		}
1267
+		// instantiate the class if possible
1268
+		if ($reflector->isAbstract()) {
1269
+			// nothing to instantiate, loading file was enough
1270
+			// does not throw an exception so $instantiation_mode is unused
1271
+			// $instantiation_mode = "1) no constructor abstract class";
1272
+			return true;
1273
+		}
1274
+		if (
1275
+			empty($arguments)
1276
+			&& $this->mirror->getConstructorFromReflection($reflector) === null
1277
+			&& $reflector->isInstantiable()
1278
+		) {
1279
+			// no constructor = static methods only... nothing to instantiate, loading file was enough
1280
+			// $instantiation_mode = "2) no constructor but instantiable";
1281
+			return $reflector->newInstance();
1282
+		}
1283
+		if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1284
+			// $instantiation_mode = "3) new_instance_from_db()";
1285
+			return call_user_func_array([$class_name, 'new_instance_from_db'], $arguments);
1286
+		}
1287
+		if (method_exists($class_name, 'new_instance')) {
1288
+			// $instantiation_mode = "4) new_instance()";
1289
+			return call_user_func_array([$class_name, 'new_instance'], $arguments);
1290
+		}
1291
+		if (method_exists($class_name, 'instance')) {
1292
+			// $instantiation_mode = "5) instance()";
1293
+			return call_user_func_array([$class_name, 'instance'], $arguments);
1294
+		}
1295
+		if ($reflector->isInstantiable()) {
1296
+			// $instantiation_mode = "6) constructor";
1297
+			return $reflector->newInstanceArgs($arguments);
1298
+		}
1299
+		// heh ? something's not right !
1300
+		throw new EE_Error(
1301
+			sprintf(
1302
+				esc_html__('The %s file %s could not be instantiated.', 'event_espresso'),
1303
+				$type,
1304
+				$class_name
1305
+			)
1306
+		);
1307
+	}
1308
+
1309
+
1310
+	/**
1311
+	 * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1312
+	 * @param array $array
1313
+	 * @return bool
1314
+	 */
1315
+	protected function _array_is_numerically_and_sequentially_indexed(array $array): bool
1316
+	{
1317
+		return empty($array) || array_keys($array) === range(0, count($array) - 1);
1318
+	}
1319
+
1320
+
1321
+	/**
1322
+	 * _resolve_dependencies
1323
+	 * examines the constructor for the requested class to determine
1324
+	 * if any dependencies exist, and if they can be injected.
1325
+	 * If so, then those classes will be added to the array of arguments passed to the constructor
1326
+	 * PLZ NOTE: this is achieved by type hinting the constructor params
1327
+	 * For example:
1328
+	 *        if attempting to load a class "Foo" with the following constructor:
1329
+	 *        __construct( Bar $bar_class, Fighter $grohl_class )
1330
+	 *        then $bar_class and $grohl_class will be added to the $arguments array,
1331
+	 *        but only IF they are NOT already present in the incoming arguments array,
1332
+	 *        and the correct classes can be loaded
1333
+	 *
1334
+	 * @param ReflectionClass $reflector
1335
+	 * @param string          $class_name
1336
+	 * @param array           $arguments
1337
+	 * @return array
1338
+	 * @throws InvalidArgumentException
1339
+	 * @throws InvalidDataTypeException
1340
+	 * @throws InvalidInterfaceException
1341
+	 * @throws ReflectionException
1342
+	 */
1343
+	protected function _resolve_dependencies(
1344
+		ReflectionClass $reflector,
1345
+		string $class_name,
1346
+		array $arguments = []
1347
+	): array {
1348
+		// let's examine the constructor
1349
+		$constructor = $this->mirror->getConstructorFromReflection($reflector);
1350
+		// whu? huh? nothing?
1351
+		if (! $constructor) {
1352
+			return $arguments;
1353
+		}
1354
+		// get constructor parameters
1355
+		$params = $this->mirror->getParametersFromReflection($reflector);
1356
+		// and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1357
+		$argument_keys = array_keys($arguments);
1358
+		// now loop thru all of the constructors expected parameters
1359
+		foreach ($params as $index => $param) {
1360
+			try {
1361
+				// is this a dependency for a specific class ?
1362
+				$param_class = $this->mirror->getParameterClassName($param, $class_name, $index);
1363
+			} catch (ReflectionException $exception) {
1364
+				// uh-oh... most likely a legacy class that has not been autoloaded
1365
+				// let's try to derive the classname from what we have now
1366
+				// and hope that the property var name is close to the class name
1367
+				$param_class = $param->getName();
1368
+				$param_class = str_replace('_', ' ', $param_class);
1369
+				$param_class = ucwords($param_class);
1370
+				$param_class = str_replace(' ', '_', $param_class);
1371
+			}
1372
+			// BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1373
+			$param_class = $this->class_cache->getFqnForAlias($param_class, $class_name);
1374
+			// param is not even a class
1375
+			if (
1376
+				! empty($param_class)
1377
+				&& ! class_exists($param_class, false)
1378
+				// and something already exists in the incoming arguments for this param
1379
+				&& array_key_exists($index, $argument_keys)
1380
+				&& isset($arguments[ $argument_keys[ $index ] ])
1381
+			) {
1382
+				// so let's skip this argument and move on to the next
1383
+				continue;
1384
+			}
1385
+			// parameter is type hinted as a class
1386
+			if ($param_class !== null) {
1387
+				// parameter exists as an incoming argument, AND it's the correct class
1388
+				if (
1389
+					array_key_exists($index, $argument_keys)
1390
+					&& isset($arguments[ $argument_keys[ $index ] ])
1391
+					&& $arguments[ $argument_keys[ $index ] ] instanceof $param_class
1392
+				) {
1393
+					// skip this argument and move on to the next
1394
+					continue;
1395
+				}
1396
+				// parameter should be injected
1397
+				if ($this->_dependency_map->has_dependency_for_class($class_name, $param_class)) {
1398
+					$arguments = $this->_resolve_dependency(
1399
+						$class_name,
1400
+						$param_class,
1401
+						$arguments,
1402
+						$index
1403
+					);
1404
+				}
1405
+			}
1406
+			if (empty($arguments[ $index ])) {
1407
+				$default_value = $this->mirror->getParameterDefaultValue(
1408
+					$param,
1409
+					$class_name,
1410
+					$index
1411
+				);
1412
+				// if there's no default value, and the incoming argument is an array (albeit empty), then use that
1413
+				$arguments[ $index ] = $default_value === null
1414
+									   && isset($arguments[ $index ])
1415
+									   && is_array($arguments[ $index ])
1416
+					? $arguments[ $index ]
1417
+					: $default_value;
1418
+			}
1419
+		}
1420
+		return $arguments;
1421
+	}
1422
+
1423
+
1424
+	/**
1425
+	 * @param string $class_name
1426
+	 * @param string $param_class
1427
+	 * @param array  $arguments
1428
+	 * @param mixed  $index
1429
+	 * @return array
1430
+	 * @throws InvalidArgumentException
1431
+	 * @throws InvalidInterfaceException
1432
+	 * @throws InvalidDataTypeException
1433
+	 */
1434
+	protected function _resolve_dependency(string $class_name, string $param_class, array $arguments, $index): array
1435
+	{
1436
+		$dependency = null;
1437
+		// should dependency be loaded from cache ?
1438
+		$cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1439
+			$class_name,
1440
+			$param_class
1441
+		);
1442
+		$cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1443
+		// we might have a dependency...
1444
+		// let's MAYBE try and find it in our cache if that's what's been requested
1445
+		$cached_class = $cache_on
1446
+			? $this->_get_cached_class($param_class)
1447
+			: null;
1448
+		// and grab it if it exists
1449
+		if ($cached_class instanceof $param_class) {
1450
+			$dependency = $cached_class;
1451
+		} elseif ($param_class !== $class_name) {
1452
+			// obtain the loader method from the dependency map
1453
+			$loader = $this->_dependency_map->class_loader($param_class);
1454
+			// is loader a custom closure ?
1455
+			if ($loader instanceof Closure) {
1456
+				$dependency = $loader($arguments);
1457
+			} else {
1458
+				// set the cache on property for the recursive loading call
1459
+				$this->_cache_on = $cache_on;
1460
+				// if not, then let's try and load it via the registry
1461
+				if ($loader && method_exists($this, $loader)) {
1462
+					$dependency = $this->{$loader}($param_class);
1463
+				} else {
1464
+					$dependency = LoaderFactory::getLoader()->load(
1465
+						$param_class,
1466
+						[],
1467
+						$cache_on
1468
+					);
1469
+				}
1470
+			}
1471
+		}
1472
+		// did we successfully find the correct dependency ?
1473
+		if ($dependency instanceof $param_class) {
1474
+			// then let's inject it into the incoming array of arguments at the correct location
1475
+			$arguments[ $index ] = $dependency;
1476
+		}
1477
+		return $arguments;
1478
+	}
1479
+
1480
+
1481
+	/**
1482
+	 * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1483
+	 *
1484
+	 * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1485
+	 *                          in the EE_Dependency_Map::$_class_loaders array,
1486
+	 *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1487
+	 * @param array  $arguments
1488
+	 * @return mixed
1489
+	 */
1490
+	public static function factory(string $classname, array $arguments = [])
1491
+	{
1492
+		$loader = self::instance()->_dependency_map->class_loader($classname);
1493
+		if ($loader instanceof Closure) {
1494
+			return $loader($arguments);
1495
+		}
1496
+		if (method_exists(self::instance(), $loader)) {
1497
+			return self::instance()->{$loader}($classname, $arguments);
1498
+		}
1499
+		return null;
1500
+	}
1501
+
1502
+
1503
+	/**
1504
+	 * Gets the addon by its class name
1505
+	 *
1506
+	 * @param string $class_name
1507
+	 * @return EE_Addon
1508
+	 */
1509
+	public function getAddon(string $class_name): ?EE_Addon
1510
+	{
1511
+		$class_name = str_replace('\\', '_', $class_name);
1512
+		$addon      = $this->_get_cached_class($class_name);
1513
+		if ($addon) {
1514
+			return $addon;
1515
+		}
1516
+		return $this->addons->{$class_name} ?? null;
1517
+	}
1518
+
1519
+
1520
+	/**
1521
+	 * removes the addon from the internal cache
1522
+	 *
1523
+	 * @param string $class_name
1524
+	 * @return void
1525
+	 */
1526
+	public function removeAddon(string $class_name)
1527
+	{
1528
+		$class_name = str_replace('\\', '_', $class_name);
1529
+		$this->addons->remove($class_name);
1530
+	}
1531
+
1532
+
1533
+	/**
1534
+	 * Gets the addon by its name/slug (not classname. For that, just
1535
+	 * use the get_addon() method above
1536
+	 *
1537
+	 * @param string $name
1538
+	 * @return EE_Addon
1539
+	 */
1540
+	public function get_addon_by_name(string $name): ?EE_Addon
1541
+	{
1542
+		foreach ($this->addons as $addon) {
1543
+			if ($addon->name() === $name) {
1544
+				return $addon;
1545
+			}
1546
+		}
1547
+		return null;
1548
+	}
1549
+
1550
+
1551
+	/**
1552
+	 * Gets an array of all the registered addons, where the keys are their names.
1553
+	 * (ie, what each returns for their name() function)
1554
+	 * They're already available on EE_Registry::instance()->addons as properties,
1555
+	 * where each property's name is the addon's classname,
1556
+	 * So if you just want to get the addon by classname,
1557
+	 * OR use the get_addon() method above.
1558
+	 * PLEASE  NOTE:
1559
+	 * addons with Fully Qualified Class Names
1560
+	 * have had the namespace separators converted to underscores,
1561
+	 * so a classname like Fully\Qualified\ClassName
1562
+	 * would have been converted to Fully_Qualified_ClassName
1563
+	 *
1564
+	 * @return EE_Addon[] where the KEYS are the addon's name()
1565
+	 */
1566
+	public function get_addons_by_name(): array
1567
+	{
1568
+		$addons = [];
1569
+		foreach ($this->addons as $addon) {
1570
+			$addons[ $addon->name() ] = $addon;
1571
+		}
1572
+		return $addons;
1573
+	}
1574
+
1575
+
1576
+	/**
1577
+	 * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1578
+	 * a stale copy of it around
1579
+	 *
1580
+	 * @param string $model_name
1581
+	 * @return EEM_Base
1582
+	 * @throws EE_Error
1583
+	 * @throws ReflectionException
1584
+	 */
1585
+	public function reset_model(string $model_name): ?EEM_Base
1586
+	{
1587
+		$model_class_name = strpos($model_name, 'EEM_') !== 0
1588
+			? "EEM_$model_name"
1589
+			: $model_name;
1590
+		if (! $this->LIB->has($model_class_name)) {
1591
+			return null;
1592
+		}
1593
+		$model = $this->LIB->get($model_class_name);
1594
+		if (! $model instanceof EEM_Base) {
1595
+			return null;
1596
+		}
1597
+		// get that model reset it and make sure we nuke the old reference to it
1598
+		if ($model instanceof $model_class_name && is_callable([$model_class_name, 'reset'])) {
1599
+			$this->LIB->remove($model_class_name);
1600
+			$this->LIB->add($model_class_name, $model->reset());
1601
+		} else {
1602
+			throw new EE_Error(
1603
+				sprintf(
1604
+					esc_html__('Model %s does not have a method "reset"', 'event_espresso'),
1605
+					$model_name
1606
+				)
1607
+			);
1608
+		}
1609
+		return $model;
1610
+	}
1611
+
1612
+
1613
+	/**
1614
+	 * Resets the registry.
1615
+	 * The criteria for what gets reset is based on what can be shared between sites on the same request when
1616
+	 * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1617
+	 * - $_dependency_map
1618
+	 * - $_class_abbreviations
1619
+	 * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1620
+	 * - $REQ:  Still on the same request so no need to change.
1621
+	 * - $CAP: There is no site specific state in the EE_Capability class.
1622
+	 * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1623
+	 * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1624
+	 * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1625
+	 *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1626
+	 *             switch or on the restore.
1627
+	 * - $modules
1628
+	 * - $shortcodes
1629
+	 * - $widgets
1630
+	 *
1631
+	 * @param boolean $hard             [deprecated]
1632
+	 * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1633
+	 *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1634
+	 *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1635
+	 * @param bool    $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1636
+	 *                                  client
1637
+	 *                                  code instead can just change the model context to a different blog id if
1638
+	 *                                  necessary
1639
+	 * @return EE_Registry
1640
+	 * @throws EE_Error
1641
+	 * @throws ReflectionException
1642
+	 * @throws InvalidArgumentException
1643
+	 */
1644
+	public static function reset(bool $hard = false, bool $reinstantiate = true, bool $reset_models = true): EE_Registry
1645
+	{
1646
+		$hard              = apply_filters('FHEE__EE_Registry__reset__hard', $hard);
1647
+		$cached_properties = [
1648
+			'BUS',
1649
+			'CART',
1650
+			'CFG',
1651
+			'LIB',
1652
+			'MRM',
1653
+			'REQ',
1654
+			'SSN',
1655
+			'AssetsRegistry',
1656
+			// 'addons',
1657
+			// 'models',
1658
+			'modules',
1659
+			'shortcodes',
1660
+			'widgets',
1661
+		];
1662
+		foreach ($cached_properties as $cached_property) {
1663
+			if (EE_UnitTestCase::$debug) {
1664
+				echo "\n\n" . __LINE__ . ') ' . strtoupper($cached_property);
1665
+			}
1666
+			if (
1667
+				! property_exists(self::$_instance, $cached_property)
1668
+				|| ! isset(self::$_instance->{$cached_property})
1669
+			) {
1670
+				continue;
1671
+			}
1672
+			$cached = self::$_instance->{$cached_property};
1673
+			if (is_array($cached) || $cached instanceof RegistryContainer) {
1674
+				foreach ($cached as $class_name => $class) {
1675
+					if (self::_reset_object($class_name, $class, $reset_models, $hard, $reinstantiate)) {
1676
+						// because unset() doesn't guarantee object destruction
1677
+						self::$_instance->{$cached_property}->{$class_name} = null;
1678
+						unset(self::$_instance->{$cached_property}->{$class_name});
1679
+					}
1680
+				}
1681
+				continue;
1682
+			}
1683
+			if (is_object($cached)) {
1684
+				if (self::_reset_object(get_class($cached), $cached, $reset_models, $hard, $reinstantiate)) {
1685
+					// because unset() doesn't guarantee object destruction
1686
+					self::$_instance->{$cached_property} = null;
1687
+					unset(self::$_instance->{$cached_property});
1688
+				}
1689
+			}
1690
+		}
1691
+		if (EE_UnitTestCase::$debug) {
1692
+			echo "\n\n";
1693
+		}
1694
+		return self::$_instance;
1695
+	}
1696
+
1697
+
1698
+	/**
1699
+	 * if passed object implements ResettableInterface, then call it's reset() method
1700
+	 * if passed object implements InterminableInterface, then return false,
1701
+	 * to indicate that it should NOT be cleared from the Registry cache
1702
+	 *
1703
+	 * @param string $class_name
1704
+	 * @param        $object
1705
+	 * @param bool   $reset_models
1706
+	 * @param bool   $hard
1707
+	 * @param bool   $reinstantiate
1708
+	 * @return bool returns true if cached object should be unset
1709
+	 * @throws EE_Error
1710
+	 * @throws ReflectionException
1711
+	 */
1712
+	private static function _reset_object(
1713
+		string $class_name,
1714
+		$object,
1715
+		bool $reset_models,
1716
+		bool $hard,
1717
+		bool $reinstantiate
1718
+	): bool {
1719
+		if (EE_UnitTestCase::$debug) {
1720
+			echo "\n\n - reset $class_name";
1721
+		}
1722
+		if (! is_object($object)) {
1723
+			if (EE_UnitTestCase::$debug) {
1724
+				echo "\n --> not an object";
1725
+			}
1726
+			// don't unset anything that's not an object
1727
+			return false;
1728
+		}
1729
+		if ($object instanceof InterminableInterface) {
1730
+			if (EE_UnitTestCase::$debug) {
1731
+				echo "\n --> NO (interminable)";
1732
+			}
1733
+			// don't unset anything that's not terminable
1734
+			return false;
1735
+		}
1736
+		if ($object instanceof EED_Module) {
1737
+			$object::reset();
1738
+			if (EE_UnitTestCase::$debug) {
1739
+				echo "\n --> NO (module)";
1740
+			}
1741
+			// don't unset modules
1742
+			return false;
1743
+		}
1744
+		if ($object instanceof ResettableInterface) {
1745
+			// reset some "special" classes
1746
+			if ($object instanceof EE_Config) {
1747
+				EE_Config::reset($hard, $reinstantiate);
1748
+				if (EE_UnitTestCase::$debug) {
1749
+					echo "\n --> NO (config)";
1750
+				}
1751
+				return false;
1752
+			}
1753
+			if ($object instanceof EEH_Activation) {
1754
+				EEH_Activation::reset();
1755
+				if (EE_UnitTestCase::$debug) {
1756
+					echo "\n --> NO (activation)";
1757
+				}
1758
+				return false;
1759
+			}
1760
+			if ($object instanceof EEM_Base) {
1761
+				if ($reset_models) {
1762
+					self::$_instance->reset_model($class_name);
1763
+				}
1764
+				return false;
1765
+			}
1766
+			if (method_exists($object, 'reset') && is_callable([$object, 'reset'])) {
1767
+				if (EE_UnitTestCase::$debug) {
1768
+					echo "\n  --> NO (has reset)";
1769
+				}
1770
+				$object->reset();
1771
+				return false;
1772
+			}
1773
+		}
1774
+		if (EE_UnitTestCase::$debug) {
1775
+			echo "\n  --> YES ??? " . get_class($object);
1776
+		}
1777
+		// at least clear object from cache
1778
+		self::$_instance->clear_cached_class(get_class($object));
1779
+		return false;
1780
+	}
1781
+
1782
+
1783
+	/**
1784
+	 * Gets all the custom post type models defined
1785
+	 *
1786
+	 * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1787
+	 */
1788
+	public function cpt_models(): array
1789
+	{
1790
+		$cpt_models = [];
1791
+		foreach ($this->non_abstract_db_models as $short_name => $classname) {
1792
+			if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1793
+				$cpt_models[ $short_name ] = $classname;
1794
+			}
1795
+		}
1796
+		return $cpt_models;
1797
+	}
1798
+
1799
+
1800
+	/**
1801
+	 * @return EE_Config
1802
+	 */
1803
+	public static function CFG(): EE_Config
1804
+	{
1805
+		return self::instance()->CFG;
1806
+	}
1807
+
1808
+
1809
+	/**
1810
+	 * @param string $class_name
1811
+	 * @return ReflectionClass
1812
+	 * @throws ReflectionException
1813
+	 * @throws InvalidDataTypeException
1814
+	 * @deprecated 4.9.62.p
1815
+	 */
1816
+	public function get_ReflectionClass(string $class_name): ReflectionClass
1817
+	{
1818
+		return $this->mirror->getReflectionClass($class_name);
1819
+	}
1820 1820
 }
Please login to merge, or discard this patch.
Spacing   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -308,7 +308,7 @@  discard block
 block discarded – undo
308 308
         foreach ($i18n_js_strings as $key => $value) {
309 309
             if (is_scalar($value)) {
310 310
                 $decoded_value           = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
311
-                $i18n_js_strings[ $key ] = wp_strip_all_tags($decoded_value);
311
+                $i18n_js_strings[$key] = wp_strip_all_tags($decoded_value);
312 312
             }
313 313
         }
314 314
         return $i18n_js_strings;
@@ -323,7 +323,7 @@  discard block
 block discarded – undo
323 323
     public static function localize_i18n_js_strings(): string
324 324
     {
325 325
         $i18n_js_strings = EE_Registry::sanitize_i18n_js_strings();
326
-        return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
326
+        return '/* <![CDATA[ */ var eei18n = '.wp_json_encode($i18n_js_strings).'; /* ]]> */';
327 327
     }
328 328
 
329 329
 
@@ -342,7 +342,7 @@  discard block
 block discarded – undo
342 342
             $module_class = get_class($module);
343 343
             $this->modules->add($module_class, $module);
344 344
         } else {
345
-            if (! class_exists('EE_Module_Request_Router', false)) {
345
+            if ( ! class_exists('EE_Module_Request_Router', false)) {
346 346
                 $this->load_core('Module_Request_Router');
347 347
             }
348 348
             EE_Module_Request_Router::module_factory($module);
@@ -381,10 +381,10 @@  discard block
 block discarded – undo
381 381
                 EE_CORE,
382 382
                 EE_ADMIN,
383 383
                 EE_CPTS,
384
-                EE_CORE . 'CPTs/',
385
-                EE_CORE . 'data_migration_scripts/',
386
-                EE_CORE . 'request_stack/',
387
-                EE_CORE . 'middleware/',
384
+                EE_CORE.'CPTs/',
385
+                EE_CORE.'data_migration_scripts/',
386
+                EE_CORE.'request_stack/',
387
+                EE_CORE.'middleware/',
388 388
             ]
389 389
         );
390 390
         // retrieve instantiated class
@@ -420,7 +420,7 @@  discard block
 block discarded – undo
420 420
         $service_paths = (array) apply_filters(
421 421
             'FHEE__EE_Registry__load_service__service_paths',
422 422
             [
423
-                EE_CORE . 'services/',
423
+                EE_CORE.'services/',
424 424
             ]
425 425
         );
426 426
         // retrieve instantiated class
@@ -560,10 +560,10 @@  discard block
 block discarded – undo
560 560
     {
561 561
         $paths = [
562 562
             EE_LIBRARIES,
563
-            EE_LIBRARIES . 'messages/',
564
-            EE_LIBRARIES . 'shortcodes/',
565
-            EE_LIBRARIES . 'qtips/',
566
-            EE_LIBRARIES . 'payment_methods/',
563
+            EE_LIBRARIES.'messages/',
564
+            EE_LIBRARIES.'shortcodes/',
565
+            EE_LIBRARIES.'qtips/',
566
+            EE_LIBRARIES.'payment_methods/',
567 567
         ];
568 568
         // retrieve instantiated class
569 569
         return $this->_load(
@@ -632,10 +632,10 @@  discard block
 block discarded – undo
632 632
     public function load_model_class(string $class_name, $arguments = [], bool $load_only = true)
633 633
     {
634 634
         $paths = [
635
-            EE_MODELS . 'fields/',
636
-            EE_MODELS . 'helpers/',
637
-            EE_MODELS . 'relations/',
638
-            EE_MODELS . 'strategies/',
635
+            EE_MODELS.'fields/',
636
+            EE_MODELS.'helpers/',
637
+            EE_MODELS.'relations/',
638
+            EE_MODELS.'strategies/',
639 639
         ];
640 640
         // retrieve instantiated class
641 641
         return $this->_load(
@@ -659,7 +659,7 @@  discard block
 block discarded – undo
659 659
      */
660 660
     public function is_model_name(string $model_name): bool
661 661
     {
662
-        return isset($this->models[ $model_name ]);
662
+        return isset($this->models[$model_name]);
663 663
     }
664 664
 
665 665
 
@@ -836,7 +836,7 @@  discard block
 block discarded – undo
836 836
             case 1:
837 837
                 // if it's a FQCN then maybe the class is registered with a preceding \
838 838
                 $class_name = strpos($class_name, '\\') !== false
839
-                    ? '\\' . ltrim($class_name, '\\')
839
+                    ? '\\'.ltrim($class_name, '\\')
840 840
                     : $class_name;
841 841
                 break;
842 842
             case 2:
@@ -890,11 +890,11 @@  discard block
 block discarded – undo
890 890
         // strip php file extension
891 891
         $class_name = str_replace('.php', '', trim($class_name));
892 892
         // does the class have a prefix ?
893
-        if (! empty($class_prefix) && $class_prefix !== 'addon') {
893
+        if ( ! empty($class_prefix) && $class_prefix !== 'addon') {
894 894
             // make sure $class_prefix is uppercase
895 895
             $class_prefix = strtoupper(trim($class_prefix));
896 896
             // add class prefix ONCE!!!
897
-            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
897
+            $class_name = $class_prefix.str_replace($class_prefix, '', $class_name);
898 898
         }
899 899
         $class_name   = $this->class_cache->getFqnForAlias($class_name);
900 900
         $class_exists = class_exists($class_name, false);
@@ -914,7 +914,7 @@  discard block
 block discarded – undo
914 914
             }
915 915
         }
916 916
         // if the class doesn't already exist.. then we need to try and find the file and load it
917
-        if (! $class_exists) {
917
+        if ( ! $class_exists) {
918 918
             // get full path to file
919 919
             $path = $this->_resolve_path($class_name, $type, $file_paths);
920 920
             // load the file
@@ -925,7 +925,7 @@  discard block
 block discarded – undo
925 925
                 return $loaded;
926 926
             }
927 927
             // if an object was expected but loading failed, then return nothing
928
-            if (! $loaded) {
928
+            if ( ! $loaded) {
929 929
                 return null;
930 930
             }
931 931
         }
@@ -953,7 +953,7 @@  discard block
 block discarded – undo
953 953
      */
954 954
     protected function get_class_abbreviation(string $class_name, string $default = 'FANCY_BATMAN_PANTS')
955 955
     {
956
-        return $this->_class_abbreviations[ $class_name ] ?? $default;
956
+        return $this->_class_abbreviations[$class_name] ?? $default;
957 957
     }
958 958
 
959 959
 
@@ -1086,7 +1086,7 @@  discard block
 block discarded – undo
1086 1086
             $this->addons->add($class_name, $class_obj);
1087 1087
             return;
1088 1088
         }
1089
-        if (! $from_db) {
1089
+        if ( ! $from_db) {
1090 1090
             $class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1091 1091
             $this->LIB->add($class_name, $class_obj);
1092 1092
         }
@@ -1117,13 +1117,13 @@  discard block
 block discarded – undo
1117 1117
                 : EE_CLASSES;
1118 1118
             // prep file type
1119 1119
             $type = ! empty($type)
1120
-                ? trim($type, '.') . '.'
1120
+                ? trim($type, '.').'.'
1121 1121
                 : '';
1122 1122
             // build full file path
1123
-            $file_paths[ $key ] = rtrim($file_path, '/') . '/' . $class_name . '.' . $type . 'php';
1123
+            $file_paths[$key] = rtrim($file_path, '/').'/'.$class_name.'.'.$type.'php';
1124 1124
             // does the file exist and can be read ?
1125
-            if (is_readable($file_paths[ $key ])) {
1126
-                return $file_paths[ $key ];
1125
+            if (is_readable($file_paths[$key])) {
1126
+                return $file_paths[$key];
1127 1127
             }
1128 1128
         }
1129 1129
         return false;
@@ -1148,7 +1148,7 @@  discard block
 block discarded – undo
1148 1148
         // don't give up! you gotta...
1149 1149
         try {
1150 1150
             // does the file exist and can it be read ?
1151
-            if (! $path) {
1151
+            if ( ! $path) {
1152 1152
                 // just in case the file has already been autoloaded,
1153 1153
                 // but discrepancies in the naming schema are preventing it from
1154 1154
                 // being loaded via one of the EE_Registry::load_*() methods,
@@ -1166,7 +1166,7 @@  discard block
 block discarded – undo
1166 1166
                         ),
1167 1167
                         trim($type, '.'),
1168 1168
                         $class_name,
1169
-                        '<br />' . implode(',<br />', $file_paths)
1169
+                        '<br />'.implode(',<br />', $file_paths)
1170 1170
                     )
1171 1171
                 );
1172 1172
             }
@@ -1209,8 +1209,8 @@  discard block
 block discarded – undo
1209 1209
             $legacy_parent_class_map = [
1210 1210
                 'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php',
1211 1211
             ];
1212
-            if (isset($legacy_parent_class_map[ $class_name ])) {
1213
-                require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ];
1212
+            if (isset($legacy_parent_class_map[$class_name])) {
1213
+                require_once EE_PLUGIN_DIR_PATH.$legacy_parent_class_map[$class_name];
1214 1214
             }
1215 1215
         } catch (Exception $exception) {
1216 1216
         }
@@ -1348,7 +1348,7 @@  discard block
 block discarded – undo
1348 1348
         // let's examine the constructor
1349 1349
         $constructor = $this->mirror->getConstructorFromReflection($reflector);
1350 1350
         // whu? huh? nothing?
1351
-        if (! $constructor) {
1351
+        if ( ! $constructor) {
1352 1352
             return $arguments;
1353 1353
         }
1354 1354
         // get constructor parameters
@@ -1377,7 +1377,7 @@  discard block
 block discarded – undo
1377 1377
                 && ! class_exists($param_class, false)
1378 1378
                 // and something already exists in the incoming arguments for this param
1379 1379
                 && array_key_exists($index, $argument_keys)
1380
-                && isset($arguments[ $argument_keys[ $index ] ])
1380
+                && isset($arguments[$argument_keys[$index]])
1381 1381
             ) {
1382 1382
                 // so let's skip this argument and move on to the next
1383 1383
                 continue;
@@ -1387,8 +1387,8 @@  discard block
 block discarded – undo
1387 1387
                 // parameter exists as an incoming argument, AND it's the correct class
1388 1388
                 if (
1389 1389
                     array_key_exists($index, $argument_keys)
1390
-                    && isset($arguments[ $argument_keys[ $index ] ])
1391
-                    && $arguments[ $argument_keys[ $index ] ] instanceof $param_class
1390
+                    && isset($arguments[$argument_keys[$index]])
1391
+                    && $arguments[$argument_keys[$index]] instanceof $param_class
1392 1392
                 ) {
1393 1393
                     // skip this argument and move on to the next
1394 1394
                     continue;
@@ -1403,17 +1403,17 @@  discard block
 block discarded – undo
1403 1403
                     );
1404 1404
                 }
1405 1405
             }
1406
-            if (empty($arguments[ $index ])) {
1406
+            if (empty($arguments[$index])) {
1407 1407
                 $default_value = $this->mirror->getParameterDefaultValue(
1408 1408
                     $param,
1409 1409
                     $class_name,
1410 1410
                     $index
1411 1411
                 );
1412 1412
                 // if there's no default value, and the incoming argument is an array (albeit empty), then use that
1413
-                $arguments[ $index ] = $default_value === null
1414
-                                       && isset($arguments[ $index ])
1415
-                                       && is_array($arguments[ $index ])
1416
-                    ? $arguments[ $index ]
1413
+                $arguments[$index] = $default_value === null
1414
+                                       && isset($arguments[$index])
1415
+                                       && is_array($arguments[$index])
1416
+                    ? $arguments[$index]
1417 1417
                     : $default_value;
1418 1418
             }
1419 1419
         }
@@ -1472,7 +1472,7 @@  discard block
 block discarded – undo
1472 1472
         // did we successfully find the correct dependency ?
1473 1473
         if ($dependency instanceof $param_class) {
1474 1474
             // then let's inject it into the incoming array of arguments at the correct location
1475
-            $arguments[ $index ] = $dependency;
1475
+            $arguments[$index] = $dependency;
1476 1476
         }
1477 1477
         return $arguments;
1478 1478
     }
@@ -1567,7 +1567,7 @@  discard block
 block discarded – undo
1567 1567
     {
1568 1568
         $addons = [];
1569 1569
         foreach ($this->addons as $addon) {
1570
-            $addons[ $addon->name() ] = $addon;
1570
+            $addons[$addon->name()] = $addon;
1571 1571
         }
1572 1572
         return $addons;
1573 1573
     }
@@ -1587,11 +1587,11 @@  discard block
 block discarded – undo
1587 1587
         $model_class_name = strpos($model_name, 'EEM_') !== 0
1588 1588
             ? "EEM_$model_name"
1589 1589
             : $model_name;
1590
-        if (! $this->LIB->has($model_class_name)) {
1590
+        if ( ! $this->LIB->has($model_class_name)) {
1591 1591
             return null;
1592 1592
         }
1593 1593
         $model = $this->LIB->get($model_class_name);
1594
-        if (! $model instanceof EEM_Base) {
1594
+        if ( ! $model instanceof EEM_Base) {
1595 1595
             return null;
1596 1596
         }
1597 1597
         // get that model reset it and make sure we nuke the old reference to it
@@ -1661,7 +1661,7 @@  discard block
 block discarded – undo
1661 1661
         ];
1662 1662
         foreach ($cached_properties as $cached_property) {
1663 1663
             if (EE_UnitTestCase::$debug) {
1664
-                echo "\n\n" . __LINE__ . ') ' . strtoupper($cached_property);
1664
+                echo "\n\n".__LINE__.') '.strtoupper($cached_property);
1665 1665
             }
1666 1666
             if (
1667 1667
                 ! property_exists(self::$_instance, $cached_property)
@@ -1719,7 +1719,7 @@  discard block
 block discarded – undo
1719 1719
         if (EE_UnitTestCase::$debug) {
1720 1720
             echo "\n\n - reset $class_name";
1721 1721
         }
1722
-        if (! is_object($object)) {
1722
+        if ( ! is_object($object)) {
1723 1723
             if (EE_UnitTestCase::$debug) {
1724 1724
                 echo "\n --> not an object";
1725 1725
             }
@@ -1772,7 +1772,7 @@  discard block
 block discarded – undo
1772 1772
             }
1773 1773
         }
1774 1774
         if (EE_UnitTestCase::$debug) {
1775
-            echo "\n  --> YES ??? " . get_class($object);
1775
+            echo "\n  --> YES ??? ".get_class($object);
1776 1776
         }
1777 1777
         // at least clear object from cache
1778 1778
         self::$_instance->clear_cached_class(get_class($object));
@@ -1790,7 +1790,7 @@  discard block
 block discarded – undo
1790 1790
         $cpt_models = [];
1791 1791
         foreach ($this->non_abstract_db_models as $short_name => $classname) {
1792 1792
             if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1793
-                $cpt_models[ $short_name ] = $classname;
1793
+                $cpt_models[$short_name] = $classname;
1794 1794
             }
1795 1795
         }
1796 1796
         return $cpt_models;
Please login to merge, or discard this patch.
core/EE_Config.core.php 1 patch
Indentation   +3209 added lines, -3209 removed lines patch added patch discarded remove patch
@@ -18,2571 +18,2571 @@  discard block
 block discarded – undo
18 18
  */
19 19
 final class EE_Config implements ResettableInterface
20 20
 {
21
-    const OPTION_NAME = 'ee_config';
22
-
23
-    const LOG_NAME = 'ee_config_log';
24
-
25
-    const LOG_LENGTH = 100;
26
-
27
-    const ADDON_OPTION_NAMES = 'ee_config_option_names';
28
-
29
-    /**
30
-     *    instance of the EE_Config object
31
-     *
32
-     * @var    EE_Config $_instance
33
-     * @access    private
34
-     */
35
-    private static $_instance;
36
-
37
-    /**
38
-     * @var boolean $_logging_enabled
39
-     */
40
-    private static $_logging_enabled = false;
41
-
42
-    /**
43
-     * @var LegacyShortcodesManager $legacy_shortcodes_manager
44
-     */
45
-    private $legacy_shortcodes_manager;
46
-
47
-    /**
48
-     * An StdClass whose property names are addon slugs,
49
-     * and values are their config classes
50
-     *
51
-     * @var StdClass
52
-     */
53
-    public $addons;
54
-
55
-    /**
56
-     * @var EE_Admin_Config
57
-     */
58
-    public $admin;
59
-
60
-    /**
61
-     * @var EE_Core_Config
62
-     */
63
-    public $core;
64
-
65
-    /**
66
-     * @var EE_Currency_Config
67
-     */
68
-    public $currency;
69
-
70
-    /**
71
-     * @var EE_Organization_Config
72
-     */
73
-    public $organization;
74
-
75
-    /**
76
-     * @var EE_Registration_Config
77
-     */
78
-    public $registration;
79
-
80
-    /**
81
-     * @var EE_Template_Config
82
-     */
83
-    public $template_settings;
84
-
85
-    /**
86
-     * Holds EE environment values.
87
-     *
88
-     * @var EE_Environment_Config
89
-     */
90
-    public $environment;
91
-
92
-    /**
93
-     * settings pertaining to Google maps
94
-     *
95
-     * @var EE_Map_Config
96
-     */
97
-    public $map_settings;
98
-
99
-    /**
100
-     * settings pertaining to Taxes
101
-     *
102
-     * @var EE_Tax_Config
103
-     */
104
-    public $tax_settings;
105
-
106
-    /**
107
-     * Settings pertaining to global messages settings.
108
-     *
109
-     * @var EE_Messages_Config
110
-     */
111
-    public $messages;
112
-
113
-    /**
114
-     * @deprecated
115
-     * @var EE_Gateway_Config
116
-     */
117
-    public $gateway;
118
-
119
-    /**
120
-     * @var    array $_addon_option_names
121
-     * @access    private
122
-     */
123
-    private $_addon_option_names = array();
124
-
125
-    /**
126
-     * @var    array $_module_route_map
127
-     * @access    private
128
-     */
129
-    private static $_module_route_map = array();
130
-
131
-    /**
132
-     * @var    array $_module_forward_map
133
-     * @access    private
134
-     */
135
-    private static $_module_forward_map = array();
136
-
137
-    /**
138
-     * @var    array $_module_view_map
139
-     * @access    private
140
-     */
141
-    private static $_module_view_map = array();
142
-
143
-
144
-    /**
145
-     * @singleton method used to instantiate class object
146
-     * @access    public
147
-     * @return EE_Config instance
148
-     */
149
-    public static function instance()
150
-    {
151
-        // check if class object is instantiated, and instantiated properly
152
-        if (! self::$_instance instanceof EE_Config) {
153
-            self::$_instance = new self();
154
-        }
155
-        return self::$_instance;
156
-    }
157
-
158
-
159
-    /**
160
-     * Resets the config
161
-     *
162
-     * @param bool    $hard_reset    if TRUE, sets EE_CONFig back to its original settings in the database. If FALSE
163
-     *                               (default) leaves the database alone, and merely resets the EE_Config object to
164
-     *                               reflect its state in the database
165
-     * @param boolean $reinstantiate if TRUE (default) call instance() and return it. Otherwise, just leave
166
-     *                               $_instance as NULL. Useful in case you want to forget about the old instance on
167
-     *                               EE_Config, but might not be ready to instantiate EE_Config currently (eg if the
168
-     *                               site was put into maintenance mode)
169
-     * @return EE_Config
170
-     */
171
-    public static function reset($hard_reset = false, $reinstantiate = true)
172
-    {
173
-        if (self::$_instance instanceof EE_Config) {
174
-            if ($hard_reset) {
175
-                self::$_instance->legacy_shortcodes_manager = null;
176
-                self::$_instance->_addon_option_names = array();
177
-                self::$_instance->_initialize_config();
178
-                self::$_instance->update_espresso_config();
179
-            }
180
-            self::$_instance->update_addon_option_names();
181
-        }
182
-        self::$_instance = null;
183
-        // we don't need to reset the static properties imo because those should
184
-        // only change when a module is added or removed. Currently we don't
185
-        // support removing a module during a request when it previously existed
186
-        if ($reinstantiate) {
187
-            return self::instance();
188
-        } else {
189
-            return null;
190
-        }
191
-    }
192
-
193
-
194
-    /**
195
-     *    class constructor
196
-     *
197
-     * @access    private
198
-     */
199
-    private function __construct()
200
-    {
201
-        do_action('AHEE__EE_Config__construct__begin', $this);
202
-        EE_Config::$_logging_enabled = apply_filters('FHEE__EE_Config___construct__logging_enabled', false);
203
-        // setup empty config classes
204
-        $this->_initialize_config();
205
-        // load existing EE site settings
206
-        $this->_load_core_config();
207
-        // confirm everything loaded correctly and set filtered defaults if not
208
-        $this->_verify_config();
209
-        //  register shortcodes and modules
210
-        add_action(
211
-            'AHEE__EE_System__register_shortcodes_modules_and_widgets',
212
-            array($this, 'register_shortcodes_and_modules'),
213
-            999
214
-        );
215
-        //  initialize shortcodes and modules
216
-        add_action('AHEE__EE_System__core_loaded_and_ready', array($this, 'initialize_shortcodes_and_modules'));
217
-        // register widgets
218
-        add_action('widgets_init', array($this, 'widgets_init'), 10);
219
-        // shutdown
220
-        add_action('shutdown', array($this, 'shutdown'), 10);
221
-        // construct__end hook
222
-        do_action('AHEE__EE_Config__construct__end', $this);
223
-        // hardcoded hack
224
-        $this->template_settings->current_espresso_theme = 'Espresso_Arabica_2014';
225
-    }
226
-
227
-
228
-    /**
229
-     * @return boolean
230
-     */
231
-    public static function logging_enabled()
232
-    {
233
-        return self::$_logging_enabled;
234
-    }
235
-
236
-
237
-    /**
238
-     * use to get the current theme if needed from static context
239
-     *
240
-     * @return string current theme set.
241
-     */
242
-    public static function get_current_theme()
243
-    {
244
-        return isset(self::$_instance->template_settings->current_espresso_theme)
245
-            ? self::$_instance->template_settings->current_espresso_theme : 'Espresso_Arabica_2014';
246
-    }
247
-
248
-
249
-    /**
250
-     *        _initialize_config
251
-     *
252
-     * @access private
253
-     * @return void
254
-     */
255
-    private function _initialize_config()
256
-    {
257
-        EE_Config::trim_log();
258
-        // set defaults
259
-        $this->_addon_option_names = get_option(EE_Config::ADDON_OPTION_NAMES, array());
260
-        $this->addons = new stdClass();
261
-        // set _module_route_map
262
-        EE_Config::$_module_route_map = array();
263
-        // set _module_forward_map
264
-        EE_Config::$_module_forward_map = array();
265
-        // set _module_view_map
266
-        EE_Config::$_module_view_map = array();
267
-    }
268
-
269
-
270
-    /**
271
-     *        load core plugin configuration
272
-     *
273
-     * @access private
274
-     * @return void
275
-     */
276
-    private function _load_core_config()
277
-    {
278
-        // load_core_config__start hook
279
-        do_action('AHEE__EE_Config___load_core_config__start', $this);
280
-        $espresso_config = $this->get_espresso_config();
281
-        foreach ($espresso_config as $config => $settings) {
282
-            // load_core_config__start hook
283
-            $settings = apply_filters(
284
-                'FHEE__EE_Config___load_core_config__config_settings',
285
-                $settings,
286
-                $config,
287
-                $this
288
-            );
289
-            if (is_object($settings) && property_exists($this, $config)) {
290
-                $this->{$config} = apply_filters('FHEE__EE_Config___load_core_config__' . $config, $settings);
291
-                // call configs populate method to ensure any defaults are set for empty values.
292
-                if (method_exists($settings, 'populate')) {
293
-                    $this->{$config}->populate();
294
-                }
295
-                if (method_exists($settings, 'do_hooks')) {
296
-                    $this->{$config}->do_hooks();
297
-                }
298
-            }
299
-        }
300
-        if (apply_filters('FHEE__EE_Config___load_core_config__update_espresso_config', false)) {
301
-            $this->update_espresso_config();
302
-        }
303
-        // load_core_config__end hook
304
-        do_action('AHEE__EE_Config___load_core_config__end', $this);
305
-    }
306
-
307
-
308
-    /**
309
-     *    _verify_config
310
-     *
311
-     * @access    protected
312
-     * @return    void
313
-     */
314
-    protected function _verify_config()
315
-    {
316
-        $this->core = $this->core instanceof EE_Core_Config
317
-            ? $this->core
318
-            : new EE_Core_Config();
319
-        $this->core = apply_filters('FHEE__EE_Config___initialize_config__core', $this->core);
320
-        $this->organization = $this->organization instanceof EE_Organization_Config
321
-            ? $this->organization
322
-            : new EE_Organization_Config();
323
-        $this->organization = apply_filters(
324
-            'FHEE__EE_Config___initialize_config__organization',
325
-            $this->organization
326
-        );
327
-        $this->currency = $this->currency instanceof EE_Currency_Config
328
-            ? $this->currency
329
-            : new EE_Currency_Config();
330
-        $this->currency = apply_filters('FHEE__EE_Config___initialize_config__currency', $this->currency);
331
-        $this->registration = $this->registration instanceof EE_Registration_Config
332
-            ? $this->registration
333
-            : new EE_Registration_Config();
334
-        $this->registration = apply_filters(
335
-            'FHEE__EE_Config___initialize_config__registration',
336
-            $this->registration
337
-        );
338
-        $this->admin = $this->admin instanceof EE_Admin_Config
339
-            ? $this->admin
340
-            : new EE_Admin_Config();
341
-        $this->admin = apply_filters('FHEE__EE_Config___initialize_config__admin', $this->admin);
342
-        $this->template_settings = $this->template_settings instanceof EE_Template_Config
343
-            ? $this->template_settings
344
-            : new EE_Template_Config();
345
-        $this->template_settings = apply_filters(
346
-            'FHEE__EE_Config___initialize_config__template_settings',
347
-            $this->template_settings
348
-        );
349
-        $this->map_settings = $this->map_settings instanceof EE_Map_Config
350
-            ? $this->map_settings
351
-            : new EE_Map_Config();
352
-        $this->map_settings = apply_filters(
353
-            'FHEE__EE_Config___initialize_config__map_settings',
354
-            $this->map_settings
355
-        );
356
-        $this->environment = $this->environment instanceof EE_Environment_Config
357
-            ? $this->environment
358
-            : new EE_Environment_Config();
359
-        $this->environment = apply_filters(
360
-            'FHEE__EE_Config___initialize_config__environment',
361
-            $this->environment
362
-        );
363
-        $this->tax_settings = $this->tax_settings instanceof EE_Tax_Config
364
-            ? $this->tax_settings
365
-            : new EE_Tax_Config();
366
-        $this->tax_settings = apply_filters(
367
-            'FHEE__EE_Config___initialize_config__tax_settings',
368
-            $this->tax_settings
369
-        );
370
-        $this->messages = apply_filters('FHEE__EE_Config__initialize_config__messages', $this->messages);
371
-        $this->messages = $this->messages instanceof EE_Messages_Config
372
-            ? $this->messages
373
-            : new EE_Messages_Config();
374
-        $this->gateway = $this->gateway instanceof EE_Gateway_Config
375
-            ? $this->gateway
376
-            : new EE_Gateway_Config();
377
-        $this->gateway = apply_filters('FHEE__EE_Config___initialize_config__gateway', $this->gateway);
378
-        $this->legacy_shortcodes_manager = null;
379
-    }
380
-
381
-
382
-    /**
383
-     *    get_espresso_config
384
-     *
385
-     * @access    public
386
-     * @return    array of espresso config stuff
387
-     */
388
-    public function get_espresso_config()
389
-    {
390
-        // grab espresso configuration
391
-        return apply_filters(
392
-            'FHEE__EE_Config__get_espresso_config__CFG',
393
-            get_option(EE_Config::OPTION_NAME, array())
394
-        );
395
-    }
396
-
397
-
398
-    /**
399
-     *    double_check_config_comparison
400
-     *
401
-     * @access    public
402
-     * @param string $option
403
-     * @param        $old_value
404
-     * @param        $value
405
-     */
406
-    public function double_check_config_comparison($option, $old_value, $value)
407
-    {
408
-        // make sure we're checking the ee config
409
-        if ($option === EE_Config::OPTION_NAME) {
410
-            // run a loose comparison of the old value against the new value for type and properties,
411
-            // but NOT exact instance like WP update_option does (ie: NOT type safe comparison)
412
-            if ($value != $old_value) {
413
-                // if they are NOT the same, then remove the hook,
414
-                // which means the subsequent update results will be based solely on the update query results
415
-                // the reason we do this is because, as stated above,
416
-                // WP update_option performs an exact instance comparison (===) on any update values passed to it
417
-                // this happens PRIOR to serialization and any subsequent update.
418
-                // If values are found to match their previous old value,
419
-                // then WP bails before performing any update.
420
-                // Since we are passing the EE_Config object, it is comparing the EXACT instance of the saved version
421
-                // it just pulled from the db, with the one being passed to it (which will not match).
422
-                // HOWEVER, once the object is serialized and passed off to MySQL to update,
423
-                // MySQL MAY ALSO NOT perform the update because
424
-                // the string it sees in the db looks the same as the new one it has been passed!!!
425
-                // This results in the query returning an "affected rows" value of ZERO,
426
-                // which gets returned immediately by WP update_option and looks like an error.
427
-                remove_action('update_option', array($this, 'check_config_updated'));
428
-            }
429
-        }
430
-    }
431
-
432
-
433
-    /**
434
-     *    update_espresso_config
435
-     *
436
-     * @access   public
437
-     */
438
-    protected function _reset_espresso_addon_config()
439
-    {
440
-        $this->_addon_option_names = array();
441
-        foreach ($this->addons as $addon_name => $addon_config_obj) {
442
-            $addon_config_obj = maybe_unserialize($addon_config_obj);
443
-            if ($addon_config_obj instanceof EE_Config_Base) {
444
-                $this->update_config('addons', $addon_name, $addon_config_obj, false);
445
-            }
446
-            $this->addons->{$addon_name} = null;
447
-        }
448
-    }
449
-
450
-
451
-    /**
452
-     *    update_espresso_config
453
-     *
454
-     * @access   public
455
-     * @param   bool $add_success
456
-     * @param   bool $add_error
457
-     * @return   bool
458
-     */
459
-    public function update_espresso_config($add_success = false, $add_error = true)
460
-    {
461
-        // don't allow config updates during WP heartbeats
462
-        /** @var RequestInterface $request */
463
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
464
-        if ($request->isWordPressHeartbeat()) {
465
-            return false;
466
-        }
467
-        // commented out the following re: https://events.codebasehq.com/projects/event-espresso/tickets/8197
468
-        // $clone = clone( self::$_instance );
469
-        // self::$_instance = NULL;
470
-        do_action('AHEE__EE_Config__update_espresso_config__begin', $this);
471
-        $this->_reset_espresso_addon_config();
472
-        // hook into update_option because that happens AFTER the ( $value === $old_value ) conditional
473
-        // but BEFORE the actual update occurs
474
-        add_action('update_option', array($this, 'double_check_config_comparison'), 1, 3);
475
-        // don't want to persist legacy_shortcodes_manager, but don't want to lose it either
476
-        $legacy_shortcodes_manager = $this->legacy_shortcodes_manager;
477
-        $this->legacy_shortcodes_manager = null;
478
-        // now update "ee_config"
479
-        $saved = update_option(EE_Config::OPTION_NAME, $this);
480
-        $this->legacy_shortcodes_manager = $legacy_shortcodes_manager;
481
-        EE_Config::log(EE_Config::OPTION_NAME);
482
-        // if not saved... check if the hook we just added still exists;
483
-        // if it does, it means one of two things:
484
-        // that update_option bailed at the($value === $old_value) conditional,
485
-        // or...
486
-        // the db update query returned 0 rows affected
487
-        // (probably because the data  value was the same from it's perspective)
488
-        // so the existence of the hook means that a negative result from update_option is NOT an error,
489
-        // but just means no update occurred, so don't display an error to the user.
490
-        // BUT... if update_option returns FALSE, AND the hook is missing,
491
-        // then it means that something truly went wrong
492
-        $saved = ! $saved ? has_action('update_option', array($this, 'double_check_config_comparison')) : $saved;
493
-        // remove our action since we don't want it in the system anymore
494
-        remove_action('update_option', array($this, 'double_check_config_comparison'), 1);
495
-        do_action('AHEE__EE_Config__update_espresso_config__end', $this, $saved);
496
-        // self::$_instance = $clone;
497
-        // unset( $clone );
498
-        // if config remains the same or was updated successfully
499
-        if ($saved) {
500
-            if ($add_success) {
501
-                EE_Error::add_success(
502
-                    esc_html__('The Event Espresso Configuration Settings have been successfully updated.', 'event_espresso'),
503
-                    __FILE__,
504
-                    __FUNCTION__,
505
-                    __LINE__
506
-                );
507
-            }
508
-            return true;
509
-        } else {
510
-            if ($add_error) {
511
-                EE_Error::add_error(
512
-                    esc_html__('The Event Espresso Configuration Settings were not updated.', 'event_espresso'),
513
-                    __FILE__,
514
-                    __FUNCTION__,
515
-                    __LINE__
516
-                );
517
-            }
518
-            return false;
519
-        }
520
-    }
521
-
522
-
523
-    /**
524
-     *    _verify_config_params
525
-     *
526
-     * @access    private
527
-     * @param    string         $section
528
-     * @param    string         $name
529
-     * @param    string         $config_class
530
-     * @param    EE_Config_Base $config_obj
531
-     * @param    array          $tests_to_run
532
-     * @param    bool           $display_errors
533
-     * @return    bool    TRUE on success, FALSE on fail
534
-     */
535
-    private function _verify_config_params(
536
-        $section = '',
537
-        $name = '',
538
-        $config_class = '',
539
-        $config_obj = null,
540
-        $tests_to_run = array(1, 2, 3, 4, 5, 6, 7, 8),
541
-        $display_errors = true
542
-    ) {
543
-        try {
544
-            foreach ($tests_to_run as $test) {
545
-                switch ($test) {
546
-                    // TEST #1 : check that section was set
547
-                    case 1:
548
-                        if (empty($section)) {
549
-                            if ($display_errors) {
550
-                                throw new EE_Error(
551
-                                    sprintf(
552
-                                        esc_html__(
553
-                                            'No configuration section has been provided while attempting to save "%s".',
554
-                                            'event_espresso'
555
-                                        ),
556
-                                        $config_class
557
-                                    )
558
-                                );
559
-                            }
560
-                            return false;
561
-                        }
562
-                        break;
563
-                    // TEST #2 : check that settings section exists
564
-                    case 2:
565
-                        if (! isset($this->{$section})) {
566
-                            if ($display_errors) {
567
-                                throw new EE_Error(
568
-                                    sprintf(
569
-                                        esc_html__('The "%s" configuration section does not exist.', 'event_espresso'),
570
-                                        $section
571
-                                    )
572
-                                );
573
-                            }
574
-                            return false;
575
-                        }
576
-                        break;
577
-                    // TEST #3 : check that section is the proper format
578
-                    case 3:
579
-                        if (
580
-                            ! ($this->{$section} instanceof EE_Config_Base || $this->{$section} instanceof stdClass)
581
-                        ) {
582
-                            if ($display_errors) {
583
-                                throw new EE_Error(
584
-                                    sprintf(
585
-                                        esc_html__(
586
-                                            'The "%s" configuration settings have not been formatted correctly.',
587
-                                            'event_espresso'
588
-                                        ),
589
-                                        $section
590
-                                    )
591
-                                );
592
-                            }
593
-                            return false;
594
-                        }
595
-                        break;
596
-                    // TEST #4 : check that config section name has been set
597
-                    case 4:
598
-                        if (empty($name)) {
599
-                            if ($display_errors) {
600
-                                throw new EE_Error(
601
-                                    esc_html__(
602
-                                        'No name has been provided for the specific configuration section.',
603
-                                        'event_espresso'
604
-                                    )
605
-                                );
606
-                            }
607
-                            return false;
608
-                        }
609
-                        break;
610
-                    // TEST #5 : check that a config class name has been set
611
-                    case 5:
612
-                        if (empty($config_class)) {
613
-                            if ($display_errors) {
614
-                                throw new EE_Error(
615
-                                    esc_html__(
616
-                                        'No class name has been provided for the specific configuration section.',
617
-                                        'event_espresso'
618
-                                    )
619
-                                );
620
-                            }
621
-                            return false;
622
-                        }
623
-                        break;
624
-                    // TEST #6 : verify config class is accessible
625
-                    case 6:
626
-                        if (! class_exists($config_class)) {
627
-                            if ($display_errors) {
628
-                                throw new EE_Error(
629
-                                    sprintf(
630
-                                        esc_html__(
631
-                                            'The "%s" class does not exist. Please ensure that an autoloader has been set for it.',
632
-                                            'event_espresso'
633
-                                        ),
634
-                                        $config_class
635
-                                    )
636
-                                );
637
-                            }
638
-                            return false;
639
-                        }
640
-                        break;
641
-                    // TEST #7 : check that config has even been set
642
-                    case 7:
643
-                        if (! isset($this->{$section}->{$name})) {
644
-                            if ($display_errors) {
645
-                                throw new EE_Error(
646
-                                    sprintf(
647
-                                        esc_html__('No configuration has been set for "%1$s->%2$s".', 'event_espresso'),
648
-                                        $section,
649
-                                        $name
650
-                                    )
651
-                                );
652
-                            }
653
-                            return false;
654
-                        } else {
655
-                            // and make sure it's not serialized
656
-                            $this->{$section}->{$name} = maybe_unserialize($this->{$section}->{$name});
657
-                        }
658
-                        break;
659
-                    // TEST #8 : check that config is the requested type
660
-                    case 8:
661
-                        if (! $this->{$section}->{$name} instanceof $config_class) {
662
-                            if ($display_errors) {
663
-                                throw new EE_Error(
664
-                                    sprintf(
665
-                                        esc_html__(
666
-                                            'The configuration for "%1$s->%2$s" is not of the "%3$s" class.',
667
-                                            'event_espresso'
668
-                                        ),
669
-                                        $section,
670
-                                        $name,
671
-                                        $config_class
672
-                                    )
673
-                                );
674
-                            }
675
-                            return false;
676
-                        }
677
-                        break;
678
-                    // TEST #9 : verify config object
679
-                    case 9:
680
-                        if (! $config_obj instanceof EE_Config_Base) {
681
-                            if ($display_errors) {
682
-                                throw new EE_Error(
683
-                                    sprintf(
684
-                                        esc_html__('The "%s" class is not an instance of EE_Config_Base.', 'event_espresso'),
685
-                                        print_r($config_obj, true)
686
-                                    )
687
-                                );
688
-                            }
689
-                            return false;
690
-                        }
691
-                        break;
692
-                }
693
-            }
694
-        } catch (EE_Error $e) {
695
-            $e->get_error();
696
-        }
697
-        // you have successfully run the gauntlet
698
-        return true;
699
-    }
700
-
701
-
702
-    /**
703
-     *    _generate_config_option_name
704
-     *
705
-     * @access        protected
706
-     * @param        string $section
707
-     * @param        string $name
708
-     * @return        string
709
-     */
710
-    private function _generate_config_option_name($section = '', $name = '')
711
-    {
712
-        return 'ee_config-' . strtolower($section . '-' . str_replace(array('EE_', 'EED_'), '', $name));
713
-    }
714
-
715
-
716
-    /**
717
-     *    _set_config_class
718
-     * ensures that a config class is set, either from a passed config class or one generated from the config name
719
-     *
720
-     * @access    private
721
-     * @param    string $config_class
722
-     * @param    string $name
723
-     * @return    string
724
-     */
725
-    private function _set_config_class($config_class = '', $name = '')
726
-    {
727
-        return ! empty($config_class)
728
-            ? $config_class
729
-            : str_replace(' ', '_', ucwords(str_replace('_', ' ', $name))) . '_Config';
730
-    }
731
-
732
-
733
-    /**
734
-     *    set_config
735
-     *
736
-     * @access    protected
737
-     * @param    string         $section
738
-     * @param    string         $name
739
-     * @param    string         $config_class
740
-     * @param    EE_Config_Base $config_obj
741
-     * @return    EE_Config_Base
742
-     */
743
-    public function set_config($section = '', $name = '', $config_class = '', EE_Config_Base $config_obj = null)
744
-    {
745
-        // ensure config class is set to something
746
-        $config_class = $this->_set_config_class($config_class, $name);
747
-        // run tests 1-4, 6, and 7 to verify all config params are set and valid
748
-        if (! $this->_verify_config_params($section, $name, $config_class, null, array(1, 2, 3, 4, 5, 6))) {
749
-            return null;
750
-        }
751
-        $config_option_name = $this->_generate_config_option_name($section, $name);
752
-        // if the config option name hasn't been added yet to the list of option names we're tracking, then do so now
753
-        if (! isset($this->_addon_option_names[ $config_option_name ])) {
754
-            $this->_addon_option_names[ $config_option_name ] = $config_class;
755
-            $this->update_addon_option_names();
756
-        }
757
-        // verify the incoming config object but suppress errors
758
-        if (! $this->_verify_config_params($section, $name, $config_class, $config_obj, array(9), false)) {
759
-            $config_obj = new $config_class();
760
-        }
761
-        if (get_option($config_option_name)) {
762
-            EE_Config::log($config_option_name);
763
-            update_option($config_option_name, $config_obj);
764
-            $this->{$section}->{$name} = $config_obj;
765
-            return $this->{$section}->{$name};
766
-        } else {
767
-            // create a wp-option for this config
768
-            if (add_option($config_option_name, $config_obj, '', 'no')) {
769
-                $this->{$section}->{$name} = maybe_unserialize($config_obj);
770
-                return $this->{$section}->{$name};
771
-            } else {
772
-                EE_Error::add_error(
773
-                    sprintf(esc_html__('The "%s" could not be saved to the database.', 'event_espresso'), $config_class),
774
-                    __FILE__,
775
-                    __FUNCTION__,
776
-                    __LINE__
777
-                );
778
-                return null;
779
-            }
780
-        }
781
-    }
782
-
783
-
784
-    /**
785
-     *    update_config
786
-     * Important: the config object must ALREADY be set, otherwise this will produce an error.
787
-     *
788
-     * @access    public
789
-     * @param    string                $section
790
-     * @param    string                $name
791
-     * @param    EE_Config_Base|string $config_obj
792
-     * @param    bool                  $throw_errors
793
-     * @return    bool
794
-     */
795
-    public function update_config($section = '', $name = '', $config_obj = '', $throw_errors = true)
796
-    {
797
-        // don't allow config updates during WP heartbeats
798
-        /** @var RequestInterface $request */
799
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
800
-        if ($request->isWordPressHeartbeat()) {
801
-            return false;
802
-        }
803
-        $config_obj = maybe_unserialize($config_obj);
804
-        // get class name of the incoming object
805
-        $config_class = get_class($config_obj);
806
-        // run tests 1-5 and 9 to verify config
807
-        if (
808
-            ! $this->_verify_config_params(
809
-                $section,
810
-                $name,
811
-                $config_class,
812
-                $config_obj,
813
-                array(1, 2, 3, 4, 7, 9)
814
-            )
815
-        ) {
816
-            return false;
817
-        }
818
-        $config_option_name = $this->_generate_config_option_name($section, $name);
819
-        // check if config object has been added to db by seeing if config option name is in $this->_addon_option_names array
820
-        if (! isset($this->_addon_option_names[ $config_option_name ])) {
821
-            // save new config to db
822
-            if ($this->set_config($section, $name, $config_class, $config_obj)) {
823
-                return true;
824
-            }
825
-        } else {
826
-            // first check if the record already exists
827
-            $existing_config = get_option($config_option_name);
828
-            $config_obj = serialize($config_obj);
829
-            // just return if db record is already up to date (NOT type safe comparison)
830
-            if ($existing_config == $config_obj) {
831
-                $this->{$section}->{$name} = $config_obj;
832
-                return true;
833
-            } elseif (update_option($config_option_name, $config_obj)) {
834
-                EE_Config::log($config_option_name);
835
-                // update wp-option for this config class
836
-                $this->{$section}->{$name} = $config_obj;
837
-                return true;
838
-            } elseif ($throw_errors) {
839
-                EE_Error::add_error(
840
-                    sprintf(
841
-                        esc_html__(
842
-                            'The "%1$s" object stored at"%2$s" was not successfully updated in the database.',
843
-                            'event_espresso'
844
-                        ),
845
-                        $config_class,
846
-                        'EE_Config->' . $section . '->' . $name
847
-                    ),
848
-                    __FILE__,
849
-                    __FUNCTION__,
850
-                    __LINE__
851
-                );
852
-            }
853
-        }
854
-        return false;
855
-    }
856
-
857
-
858
-    /**
859
-     *    get_config
860
-     *
861
-     * @access    public
862
-     * @param    string $section
863
-     * @param    string $name
864
-     * @param    string $config_class
865
-     * @return    mixed EE_Config_Base | NULL
866
-     */
867
-    public function get_config($section = '', $name = '', $config_class = '')
868
-    {
869
-        // ensure config class is set to something
870
-        $config_class = $this->_set_config_class($config_class, $name);
871
-        // run tests 1-4, 6 and 7 to verify that all params have been set
872
-        if (! $this->_verify_config_params($section, $name, $config_class, null, array(1, 2, 3, 4, 5, 6))) {
873
-            return null;
874
-        }
875
-        // now test if the requested config object exists, but suppress errors
876
-        if ($this->_verify_config_params($section, $name, $config_class, null, array(7, 8), false)) {
877
-            // config already exists, so pass it back
878
-            return $this->{$section}->{$name};
879
-        }
880
-        // load config option from db if it exists
881
-        $config_obj = $this->get_config_option($this->_generate_config_option_name($section, $name));
882
-        // verify the newly retrieved config object, but suppress errors
883
-        if ($this->_verify_config_params($section, $name, $config_class, $config_obj, array(9), false)) {
884
-            // config is good, so set it and pass it back
885
-            $this->{$section}->{$name} = $config_obj;
886
-            return $this->{$section}->{$name};
887
-        }
888
-        // oops! $config_obj is not already set and does not exist in the db, so create a new one
889
-        $config_obj = $this->set_config($section, $name, $config_class);
890
-        // verify the newly created config object
891
-        if ($this->_verify_config_params($section, $name, $config_class, $config_obj, array(9))) {
892
-            return $this->{$section}->{$name};
893
-        } else {
894
-            EE_Error::add_error(
895
-                sprintf(esc_html__('The "%s" could not be retrieved from the database.', 'event_espresso'), $config_class),
896
-                __FILE__,
897
-                __FUNCTION__,
898
-                __LINE__
899
-            );
900
-        }
901
-        return null;
902
-    }
903
-
904
-
905
-    /**
906
-     *    get_config_option
907
-     *
908
-     * @access    public
909
-     * @param    string $config_option_name
910
-     * @return    mixed EE_Config_Base | FALSE
911
-     */
912
-    public function get_config_option($config_option_name = '')
913
-    {
914
-        // retrieve the wp-option for this config class.
915
-        $config_option = maybe_unserialize(get_option($config_option_name, array()));
916
-        if (empty($config_option)) {
917
-            EE_Config::log($config_option_name . '-NOT-FOUND');
918
-        }
919
-        return $config_option;
920
-    }
921
-
922
-
923
-    /**
924
-     * log
925
-     *
926
-     * @param string $config_option_name
927
-     */
928
-    public static function log($config_option_name = '')
929
-    {
930
-        if (EE_Config::logging_enabled() && ! empty($config_option_name)) {
931
-            $config_log = get_option(EE_Config::LOG_NAME, array());
932
-            /** @var RequestParams $request */
933
-            $request = LoaderFactory::getLoader()->getShared(RequestParams::class);
934
-            $config_log[ (string) microtime(true) ] = array(
935
-                'config_name' => $config_option_name,
936
-                'request'     => $request->requestParams(),
937
-            );
938
-            update_option(EE_Config::LOG_NAME, $config_log);
939
-        }
940
-    }
941
-
942
-
943
-    /**
944
-     * trim_log
945
-     * reduces the size of the config log to the length specified by EE_Config::LOG_LENGTH
946
-     */
947
-    public static function trim_log()
948
-    {
949
-        if (! EE_Config::logging_enabled()) {
950
-            return;
951
-        }
952
-        $config_log = maybe_unserialize(get_option(EE_Config::LOG_NAME, array()));
953
-        $log_length = count($config_log);
954
-        if ($log_length > EE_Config::LOG_LENGTH) {
955
-            ksort($config_log);
956
-            $config_log = array_slice($config_log, $log_length - EE_Config::LOG_LENGTH, null, true);
957
-            update_option(EE_Config::LOG_NAME, $config_log);
958
-        }
959
-    }
960
-
961
-
962
-    /**
963
-     *    get_page_for_posts
964
-     *    if the wp-option "show_on_front" is set to "page", then this is the post_name for the post set in the
965
-     *    wp-option "page_for_posts", or "posts" if no page is selected
966
-     *
967
-     * @access    public
968
-     * @return    string
969
-     */
970
-    public static function get_page_for_posts()
971
-    {
972
-        $page_for_posts = get_option('page_for_posts');
973
-        if (! $page_for_posts) {
974
-            return 'posts';
975
-        }
976
-        global $wpdb;
977
-        $SQL = "SELECT post_name from $wpdb->posts WHERE post_type='posts' OR post_type='page' AND post_status='publish' AND ID=%d";
978
-        return $wpdb->get_var($wpdb->prepare($SQL, $page_for_posts));
979
-    }
980
-
981
-
982
-    /**
983
-     *    register_shortcodes_and_modules.
984
-     *    At this point, it's too early to tell if we're maintenance mode or not.
985
-     *    In fact, this is where we give modules a chance to let core know they exist
986
-     *    so they can help trigger maintenance mode if it's needed
987
-     *
988
-     * @access    public
989
-     * @return    void
990
-     */
991
-    public function register_shortcodes_and_modules()
992
-    {
993
-        // allow modules to set hooks for the rest of the system
994
-        EE_Registry::instance()->modules = $this->_register_modules();
995
-    }
996
-
997
-
998
-    /**
999
-     *    initialize_shortcodes_and_modules
1000
-     *    meaning they can start adding their hooks to get stuff done
1001
-     *
1002
-     * @access    public
1003
-     * @return    void
1004
-     */
1005
-    public function initialize_shortcodes_and_modules()
1006
-    {
1007
-        // allow modules to set hooks for the rest of the system
1008
-        $this->_initialize_modules();
1009
-    }
1010
-
1011
-
1012
-    /**
1013
-     *    widgets_init
1014
-     *
1015
-     * @access private
1016
-     * @return void
1017
-     */
1018
-    public function widgets_init()
1019
-    {
1020
-        // only init widgets on admin pages when not in complete maintenance, and
1021
-        // on frontend when not in any maintenance mode
1022
-        if (
1023
-            ! EE_Maintenance_Mode::instance()->level()
1024
-            || (
1025
-                is_admin()
1026
-                && EE_Maintenance_Mode::instance()->level() !== EE_Maintenance_Mode::level_2_complete_maintenance
1027
-            )
1028
-        ) {
1029
-            // grab list of installed widgets
1030
-            $widgets_to_register = glob(EE_WIDGETS . '*', GLOB_ONLYDIR);
1031
-            // filter list of modules to register
1032
-            $widgets_to_register = apply_filters(
1033
-                'FHEE__EE_Config__register_widgets__widgets_to_register',
1034
-                $widgets_to_register
1035
-            );
1036
-            if (! empty($widgets_to_register)) {
1037
-                // cycle thru widget folders
1038
-                foreach ($widgets_to_register as $widget_path) {
1039
-                    // add to list of installed widget modules
1040
-                    EE_Config::register_ee_widget($widget_path);
1041
-                }
1042
-            }
1043
-            // filter list of installed modules
1044
-            EE_Registry::instance()->widgets = apply_filters(
1045
-                'FHEE__EE_Config__register_widgets__installed_widgets',
1046
-                EE_Registry::instance()->widgets
1047
-            );
1048
-        }
1049
-    }
1050
-
1051
-
1052
-    /**
1053
-     *    register_ee_widget - makes core aware of this widget
1054
-     *
1055
-     * @access    public
1056
-     * @param    string $widget_path - full path up to and including widget folder
1057
-     * @return    void
1058
-     */
1059
-    public static function register_ee_widget($widget_path = null)
1060
-    {
1061
-        do_action('AHEE__EE_Config__register_widget__begin', $widget_path);
1062
-        $widget_ext = '.widget.php';
1063
-        // make all separators match
1064
-        $widget_path = rtrim(str_replace('\\', DS, $widget_path), DS);
1065
-        // does the file path INCLUDE the actual file name as part of the path ?
1066
-        if (strpos($widget_path, $widget_ext) !== false) {
1067
-            // grab and shortcode file name from directory name and break apart at dots
1068
-            $file_name = explode('.', basename($widget_path));
1069
-            // take first segment from file name pieces and remove class prefix if it exists
1070
-            $widget = strpos($file_name[0], 'EEW_') === 0 ? substr($file_name[0], 4) : $file_name[0];
1071
-            // sanitize shortcode directory name
1072
-            $widget = sanitize_key($widget);
1073
-            // now we need to rebuild the shortcode path
1074
-            $widget_path = explode('/', $widget_path);
1075
-            // remove last segment
1076
-            array_pop($widget_path);
1077
-            // glue it back together
1078
-            $widget_path = implode(DS, $widget_path);
1079
-        } else {
1080
-            // grab and sanitize widget directory name
1081
-            $widget = sanitize_key(basename($widget_path));
1082
-        }
1083
-        // create classname from widget directory name
1084
-        $widget = str_replace(' ', '_', ucwords(str_replace('_', ' ', $widget)));
1085
-        // add class prefix
1086
-        $widget_class = 'EEW_' . $widget;
1087
-        // does the widget exist ?
1088
-        if (! is_readable($widget_path . '/' . $widget_class . $widget_ext)) {
1089
-            $msg = sprintf(
1090
-                esc_html__(
1091
-                    'The requested %s widget file could not be found or is not readable due to file permissions. Please ensure the following path is correct: %s',
1092
-                    'event_espresso'
1093
-                ),
1094
-                $widget_class,
1095
-                $widget_path . '/' . $widget_class . $widget_ext
1096
-            );
1097
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1098
-            return;
1099
-        }
1100
-        // load the widget class file
1101
-        require_once($widget_path . '/' . $widget_class . $widget_ext);
1102
-        // verify that class exists
1103
-        if (! class_exists($widget_class)) {
1104
-            $msg = sprintf(esc_html__('The requested %s widget class does not exist.', 'event_espresso'), $widget_class);
1105
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1106
-            return;
1107
-        }
1108
-        register_widget($widget_class);
1109
-        // add to array of registered widgets
1110
-        EE_Registry::instance()->widgets->{$widget_class} = $widget_path . '/' . $widget_class . $widget_ext;
1111
-    }
1112
-
1113
-
1114
-    /**
1115
-     *        _register_modules
1116
-     *
1117
-     * @access private
1118
-     * @return array
1119
-     */
1120
-    private function _register_modules()
1121
-    {
1122
-        // grab list of installed modules
1123
-        $modules_to_register = glob(EE_MODULES . '*', GLOB_ONLYDIR);
1124
-        // filter list of modules to register
1125
-        $modules_to_register = apply_filters(
1126
-            'FHEE__EE_Config__register_modules__modules_to_register',
1127
-            $modules_to_register
1128
-        );
1129
-        if (! empty($modules_to_register)) {
1130
-            // loop through folders
1131
-            foreach ($modules_to_register as $module_path) {
1132
-                /**TEMPORARILY EXCLUDE gateways from modules for time being**/
1133
-                if (
1134
-                    $module_path !== EE_MODULES . 'zzz-copy-this-module-template'
1135
-                    && $module_path !== EE_MODULES . 'gateways'
1136
-                ) {
1137
-                    // add to list of installed modules
1138
-                    EE_Config::register_module($module_path);
1139
-                }
1140
-            }
1141
-        }
1142
-        // filter list of installed modules
1143
-        return apply_filters(
1144
-            'FHEE__EE_Config___register_modules__installed_modules',
1145
-            EE_Registry::instance()->modules
1146
-        );
1147
-    }
1148
-
1149
-
1150
-    /**
1151
-     *    register_module - makes core aware of this module
1152
-     *
1153
-     * @access    public
1154
-     * @param    string $module_path - full path up to and including module folder
1155
-     * @return    bool
1156
-     */
1157
-    public static function register_module($module_path = null)
1158
-    {
1159
-        do_action('AHEE__EE_Config__register_module__begin', $module_path);
1160
-        $module_ext = '.module.php';
1161
-        // make all separators match
1162
-        $module_path = str_replace(array('\\', '/'), '/', $module_path);
1163
-        // does the file path INCLUDE the actual file name as part of the path ?
1164
-        if (strpos($module_path, $module_ext) !== false) {
1165
-            // grab and shortcode file name from directory name and break apart at dots
1166
-            $module_file = explode('.', basename($module_path));
1167
-            // now we need to rebuild the shortcode path
1168
-            $module_path = explode('/', $module_path);
1169
-            // remove last segment
1170
-            array_pop($module_path);
1171
-            // glue it back together
1172
-            $module_path = implode('/', $module_path) . '/';
1173
-            // take first segment from file name pieces and sanitize it
1174
-            $module = preg_replace('/[^a-zA-Z0-9_\-]/', '', $module_file[0]);
1175
-            // ensure class prefix is added
1176
-            $module_class = strpos($module, 'EED_') !== 0 ? 'EED_' . $module : $module;
1177
-        } else {
1178
-            // we need to generate the filename based off of the folder name
1179
-            // grab and sanitize module name
1180
-            $module = strtolower(basename($module_path));
1181
-            $module = preg_replace('/[^a-z0-9_\-]/', '', $module);
1182
-            // like trailingslashit()
1183
-            $module_path = rtrim($module_path, '/') . '/';
1184
-            // create classname from module directory name
1185
-            $module = str_replace(' ', '_', ucwords(str_replace('_', ' ', $module)));
1186
-            // add class prefix
1187
-            $module_class = 'EED_' . $module;
1188
-        }
1189
-        // does the module exist ?
1190
-        if (! is_readable($module_path . '/' . $module_class . $module_ext)) {
1191
-            $msg = sprintf(
1192
-                esc_html__(
1193
-                    'The requested %s module file could not be found or is not readable due to file permissions.',
1194
-                    'event_espresso'
1195
-                ),
1196
-                $module
1197
-            );
1198
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1199
-            return false;
1200
-        }
1201
-        // load the module class file
1202
-        require_once($module_path . $module_class . $module_ext);
1203
-        // verify that class exists
1204
-        if (! class_exists($module_class)) {
1205
-            $msg = sprintf(esc_html__('The requested %s module class does not exist.', 'event_espresso'), $module_class);
1206
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1207
-            return false;
1208
-        }
1209
-        // add to array of registered modules
1210
-        EE_Registry::instance()->modules->{$module_class} = $module_path . $module_class . $module_ext;
1211
-        do_action(
1212
-            'AHEE__EE_Config__register_module__complete',
1213
-            $module_class,
1214
-            EE_Registry::instance()->modules->{$module_class}
1215
-        );
1216
-        return true;
1217
-    }
1218
-
1219
-
1220
-    /**
1221
-     *    _initialize_modules
1222
-     *    allow modules to set hooks for the rest of the system
1223
-     *
1224
-     * @access private
1225
-     * @return void
1226
-     */
1227
-    private function _initialize_modules()
1228
-    {
1229
-        // cycle thru shortcode folders
1230
-        foreach (EE_Registry::instance()->modules as $module_class => $module_path) {
1231
-            // fire the shortcode class's set_hooks methods in case it needs to hook into other parts of the system
1232
-            // which set hooks ?
1233
-            if (is_admin()) {
1234
-                // fire immediately
1235
-                call_user_func(array($module_class, 'set_hooks_admin'));
1236
-            } else {
1237
-                // delay until other systems are online
1238
-                add_action(
1239
-                    'AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons',
1240
-                    array($module_class, 'set_hooks')
1241
-                );
1242
-            }
1243
-        }
1244
-    }
1245
-
1246
-
1247
-    /**
1248
-     *    register_route - adds module method routes to route_map
1249
-     *
1250
-     * @access    public
1251
-     * @param    string $route       - "pretty" public alias for module method
1252
-     * @param    string $module      - module name (classname without EED_ prefix)
1253
-     * @param    string $method_name - the actual module method to be routed to
1254
-     * @param    string $key         - url param key indicating a route is being called
1255
-     * @return    bool
1256
-     */
1257
-    public static function register_route($route = null, $module = null, $method_name = null, $key = 'ee')
1258
-    {
1259
-        do_action('AHEE__EE_Config__register_route__begin', $route, $module, $method_name);
1260
-        $module = str_replace('EED_', '', $module);
1261
-        $module_class = 'EED_' . $module;
1262
-        if (! isset(EE_Registry::instance()->modules->{$module_class})) {
1263
-            $msg = sprintf(esc_html__('The module %s has not been registered.', 'event_espresso'), $module);
1264
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1265
-            return false;
1266
-        }
1267
-        if (empty($route)) {
1268
-            $msg = sprintf(esc_html__('No route has been supplied.', 'event_espresso'), $route);
1269
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1270
-            return false;
1271
-        }
1272
-        if (! method_exists('EED_' . $module, $method_name)) {
1273
-            $msg = sprintf(
1274
-                esc_html__('A valid class method for the %s route has not been supplied.', 'event_espresso'),
1275
-                $route
1276
-            );
1277
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1278
-            return false;
1279
-        }
1280
-        EE_Config::$_module_route_map[ (string) $key ][ (string) $route ] = array('EED_' . $module, $method_name);
1281
-        return true;
1282
-    }
1283
-
1284
-
1285
-    /**
1286
-     *    get_route - get module method route
1287
-     *
1288
-     * @access    public
1289
-     * @param    string $route - "pretty" public alias for module method
1290
-     * @param    string $key   - url param key indicating a route is being called
1291
-     * @return    string
1292
-     */
1293
-    public static function get_route($route = null, $key = 'ee')
1294
-    {
1295
-        do_action('AHEE__EE_Config__get_route__begin', $route);
1296
-        $route = (string) apply_filters('FHEE__EE_Config__get_route', $route);
1297
-        if (isset(EE_Config::$_module_route_map[ $key ][ $route ])) {
1298
-            return EE_Config::$_module_route_map[ $key ][ $route ];
1299
-        }
1300
-        return null;
1301
-    }
1302
-
1303
-
1304
-    /**
1305
-     *    get_routes - get ALL module method routes
1306
-     *
1307
-     * @access    public
1308
-     * @return    array
1309
-     */
1310
-    public static function get_routes()
1311
-    {
1312
-        return EE_Config::$_module_route_map;
1313
-    }
1314
-
1315
-
1316
-    /**
1317
-     *    register_forward - allows modules to forward request to another module for further processing
1318
-     *
1319
-     * @access    public
1320
-     * @param    string       $route   - "pretty" public alias for module method
1321
-     * @param    integer      $status  - integer value corresponding  to status constant strings set in module parent
1322
-     *                                 class, allows different forwards to be served based on status
1323
-     * @param    array|string $forward - function name or array( class, method )
1324
-     * @param    string       $key     - url param key indicating a route is being called
1325
-     * @return    bool
1326
-     */
1327
-    public static function register_forward($route = null, $status = 0, $forward = null, $key = 'ee')
1328
-    {
1329
-        do_action('AHEE__EE_Config__register_forward', $route, $status, $forward);
1330
-        if (! isset(EE_Config::$_module_route_map[ $key ][ $route ]) || empty($route)) {
1331
-            $msg = sprintf(
1332
-                esc_html__('The module route %s for this forward has not been registered.', 'event_espresso'),
1333
-                $route
1334
-            );
1335
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1336
-            return false;
1337
-        }
1338
-        if (empty($forward)) {
1339
-            $msg = sprintf(esc_html__('No forwarding route has been supplied.', 'event_espresso'), $route);
1340
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1341
-            return false;
1342
-        }
1343
-        if (is_array($forward)) {
1344
-            if (! isset($forward[1])) {
1345
-                $msg = sprintf(
1346
-                    esc_html__('A class method for the %s forwarding route has not been supplied.', 'event_espresso'),
1347
-                    $route
1348
-                );
1349
-                EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1350
-                return false;
1351
-            }
1352
-            if (! method_exists($forward[0], $forward[1])) {
1353
-                $msg = sprintf(
1354
-                    esc_html__('The class method %s for the %s forwarding route is in invalid.', 'event_espresso'),
1355
-                    $forward[1],
1356
-                    $route
1357
-                );
1358
-                EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1359
-                return false;
1360
-            }
1361
-        } elseif (! function_exists($forward)) {
1362
-            $msg = sprintf(
1363
-                esc_html__('The function %s for the %s forwarding route is in invalid.', 'event_espresso'),
1364
-                $forward,
1365
-                $route
1366
-            );
1367
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1368
-            return false;
1369
-        }
1370
-        EE_Config::$_module_forward_map[ $key ][ $route ][ absint($status) ] = $forward;
1371
-        return true;
1372
-    }
1373
-
1374
-
1375
-    /**
1376
-     *    get_forward - get forwarding route
1377
-     *
1378
-     * @access    public
1379
-     * @param    string  $route  - "pretty" public alias for module method
1380
-     * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1381
-     *                           allows different forwards to be served based on status
1382
-     * @param    string  $key    - url param key indicating a route is being called
1383
-     * @return    string
1384
-     */
1385
-    public static function get_forward($route = null, $status = 0, $key = 'ee')
1386
-    {
1387
-        do_action('AHEE__EE_Config__get_forward__begin', $route, $status);
1388
-        if (isset(EE_Config::$_module_forward_map[ $key ][ $route ][ $status ])) {
1389
-            return apply_filters(
1390
-                'FHEE__EE_Config__get_forward',
1391
-                EE_Config::$_module_forward_map[ $key ][ $route ][ $status ],
1392
-                $route,
1393
-                $status
1394
-            );
1395
-        }
1396
-        return null;
1397
-    }
1398
-
1399
-
1400
-    /**
1401
-     *    register_forward - allows modules to specify different view templates for different method routes and status
1402
-     *    results
1403
-     *
1404
-     * @access    public
1405
-     * @param    string  $route  - "pretty" public alias for module method
1406
-     * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1407
-     *                           allows different views to be served based on status
1408
-     * @param    string  $view
1409
-     * @param    string  $key    - url param key indicating a route is being called
1410
-     * @return    bool
1411
-     */
1412
-    public static function register_view($route = null, $status = 0, $view = null, $key = 'ee')
1413
-    {
1414
-        do_action('AHEE__EE_Config__register_view__begin', $route, $status, $view);
1415
-        if (! isset(EE_Config::$_module_route_map[ $key ][ $route ]) || empty($route)) {
1416
-            $msg = sprintf(
1417
-                esc_html__('The module route %s for this view has not been registered.', 'event_espresso'),
1418
-                $route
1419
-            );
1420
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1421
-            return false;
1422
-        }
1423
-        if (! is_readable($view)) {
1424
-            $msg = sprintf(
1425
-                esc_html__(
1426
-                    'The %s view file could not be found or is not readable due to file permissions.',
1427
-                    'event_espresso'
1428
-                ),
1429
-                $view
1430
-            );
1431
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1432
-            return false;
1433
-        }
1434
-        EE_Config::$_module_view_map[ $key ][ $route ][ absint($status) ] = $view;
1435
-        return true;
1436
-    }
1437
-
1438
-
1439
-    /**
1440
-     *    get_view - get view for route and status
1441
-     *
1442
-     * @access    public
1443
-     * @param    string  $route  - "pretty" public alias for module method
1444
-     * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1445
-     *                           allows different views to be served based on status
1446
-     * @param    string  $key    - url param key indicating a route is being called
1447
-     * @return    string
1448
-     */
1449
-    public static function get_view($route = null, $status = 0, $key = 'ee')
1450
-    {
1451
-        do_action('AHEE__EE_Config__get_view__begin', $route, $status);
1452
-        if (isset(EE_Config::$_module_view_map[ $key ][ $route ][ $status ])) {
1453
-            return apply_filters(
1454
-                'FHEE__EE_Config__get_view',
1455
-                EE_Config::$_module_view_map[ $key ][ $route ][ $status ],
1456
-                $route,
1457
-                $status
1458
-            );
1459
-        }
1460
-        return null;
1461
-    }
1462
-
1463
-
1464
-    public function update_addon_option_names()
1465
-    {
1466
-        update_option(EE_Config::ADDON_OPTION_NAMES, $this->_addon_option_names);
1467
-    }
1468
-
1469
-
1470
-    public function shutdown()
1471
-    {
1472
-        $this->update_addon_option_names();
1473
-    }
1474
-
1475
-
1476
-    /**
1477
-     * @return LegacyShortcodesManager
1478
-     */
1479
-    public static function getLegacyShortcodesManager()
1480
-    {
1481
-        if (! EE_Config::instance()->legacy_shortcodes_manager instanceof LegacyShortcodesManager) {
1482
-            EE_Config::instance()->legacy_shortcodes_manager = LoaderFactory::getLoader()->getShared(
1483
-                LegacyShortcodesManager::class
1484
-            );
1485
-        }
1486
-        return EE_Config::instance()->legacy_shortcodes_manager;
1487
-    }
1488
-
1489
-
1490
-    /**
1491
-     * register_shortcode - makes core aware of this shortcode
1492
-     *
1493
-     * @deprecated 4.9.26
1494
-     * @param    string $shortcode_path - full path up to and including shortcode folder
1495
-     * @return    bool
1496
-     */
1497
-    public static function register_shortcode($shortcode_path = null)
1498
-    {
1499
-        EE_Error::doing_it_wrong(
1500
-            __METHOD__,
1501
-            esc_html__(
1502
-                'Usage is deprecated. Use \EventEspresso\core\services\shortcodes\LegacyShortcodesManager::registerShortcode() as direct replacement, or better yet, please see the new \EventEspresso\core\services\shortcodes\ShortcodesManager class.',
1503
-                'event_espresso'
1504
-            ),
1505
-            '4.9.26'
1506
-        );
1507
-        return EE_Config::instance()->getLegacyShortcodesManager()->registerShortcode($shortcode_path);
1508
-    }
1509
-}
1510
-
1511
-/**
1512
- * Base class used for config classes. These classes should generally not have
1513
- * magic functions in use, except we'll allow them to magically set and get stuff...
1514
- * basically, they should just be well-defined stdClasses
1515
- */
1516
-class EE_Config_Base
1517
-{
1518
-    /**
1519
-     * Utility function for escaping the value of a property and returning.
1520
-     *
1521
-     * @param string $property property name (checks to see if exists).
1522
-     * @return mixed if a detected type found return the escaped value, otherwise just the raw value is returned.
1523
-     * @throws EE_Error
1524
-     */
1525
-    public function get_pretty($property)
1526
-    {
1527
-        if (! property_exists($this, $property)) {
1528
-            throw new EE_Error(
1529
-                sprintf(
1530
-                    esc_html__(
1531
-                        '%1$s::get_pretty() has been called with the property %2$s which does not exist on the %1$s config class.',
1532
-                        'event_espresso'
1533
-                    ),
1534
-                    get_class($this),
1535
-                    $property
1536
-                )
1537
-            );
1538
-        }
1539
-        // just handling escaping of strings for now.
1540
-        if (is_string($this->{$property})) {
1541
-            return stripslashes($this->{$property});
1542
-        }
1543
-        return $this->{$property};
1544
-    }
1545
-
1546
-
1547
-    public function populate()
1548
-    {
1549
-        // grab defaults via a new instance of this class.
1550
-        $class_name = get_class($this);
1551
-        $defaults = new $class_name();
1552
-        // loop through the properties for this class and see if they are set.  If they are NOT, then grab the
1553
-        // default from our $defaults object.
1554
-        foreach (get_object_vars($defaults) as $property => $value) {
1555
-            if ($this->{$property} === null) {
1556
-                $this->{$property} = $value;
1557
-            }
1558
-        }
1559
-        // cleanup
1560
-        unset($defaults);
1561
-    }
1562
-
1563
-
1564
-    /**
1565
-     *        __isset
1566
-     *
1567
-     * @param $a
1568
-     * @return bool
1569
-     */
1570
-    public function __isset($a)
1571
-    {
1572
-        return false;
1573
-    }
1574
-
1575
-
1576
-    /**
1577
-     *        __unset
1578
-     *
1579
-     * @param $a
1580
-     * @return bool
1581
-     */
1582
-    public function __unset($a)
1583
-    {
1584
-        return false;
1585
-    }
1586
-
1587
-
1588
-    /**
1589
-     *        __clone
1590
-     */
1591
-    public function __clone()
1592
-    {
1593
-    }
1594
-
1595
-
1596
-    /**
1597
-     *        __wakeup
1598
-     */
1599
-    public function __wakeup()
1600
-    {
1601
-    }
1602
-
1603
-
1604
-    /**
1605
-     *        __destruct
1606
-     */
1607
-    public function __destruct()
1608
-    {
1609
-    }
1610
-}
1611
-
1612
-/**
1613
- * Class for defining what's in the EE_Config relating to registration settings
1614
- */
1615
-class EE_Core_Config extends EE_Config_Base
1616
-{
1617
-    const OPTION_NAME_UXIP = 'ee_ueip_optin';
1618
-
1619
-
1620
-    public $current_blog_id;
1621
-
1622
-    public $ee_ueip_optin;
1623
-
1624
-    public $ee_ueip_has_notified;
1625
-
1626
-    /**
1627
-     * Not to be confused with the 4 critical page variables (See
1628
-     * get_critical_pages_array()), this is just an array of wp posts that have EE
1629
-     * shortcodes in them. Keys are slugs, values are arrays with only 1 element: where the key is the shortcode
1630
-     * in the page, and the value is the page's ID. The key 'posts' is basically a duplicate of this same array.
1631
-     *
1632
-     * @var array
1633
-     */
1634
-    public $post_shortcodes;
1635
-
1636
-    public $module_route_map;
1637
-
1638
-    public $module_forward_map;
1639
-
1640
-    public $module_view_map;
1641
-
1642
-    /**
1643
-     * The next 4 vars are the IDs of critical EE pages.
1644
-     *
1645
-     * @var int
1646
-     */
1647
-    public $reg_page_id;
1648
-
1649
-    public $txn_page_id;
1650
-
1651
-    public $thank_you_page_id;
1652
-
1653
-    public $cancel_page_id;
1654
-
1655
-    /**
1656
-     * The next 4 vars are the URLs of critical EE pages.
1657
-     *
1658
-     * @var int
1659
-     */
1660
-    public $reg_page_url;
1661
-
1662
-    public $txn_page_url;
1663
-
1664
-    public $thank_you_page_url;
1665
-
1666
-    public $cancel_page_url;
1667
-
1668
-    /**
1669
-     * The next vars relate to the custom slugs for EE CPT routes
1670
-     */
1671
-    public $event_cpt_slug;
1672
-
1673
-    /**
1674
-     * This caches the _ee_ueip_option in case this config is reset in the same
1675
-     * request across blog switches in a multisite context.
1676
-     * Avoids extra queries to the db for this option.
1677
-     *
1678
-     * @var bool
1679
-     */
1680
-    public static $ee_ueip_option;
1681
-
1682
-
1683
-    /**
1684
-     *    class constructor
1685
-     *
1686
-     * @access    public
1687
-     */
1688
-    public function __construct()
1689
-    {
1690
-        // set default organization settings
1691
-        $this->current_blog_id = get_current_blog_id();
1692
-        $this->current_blog_id = $this->current_blog_id === null ? 1 : $this->current_blog_id;
1693
-        $this->ee_ueip_optin = $this->_get_main_ee_ueip_optin();
1694
-        $this->ee_ueip_has_notified = is_main_site() ? get_option('ee_ueip_has_notified', false) : true;
1695
-        $this->post_shortcodes = array();
1696
-        $this->module_route_map = array();
1697
-        $this->module_forward_map = array();
1698
-        $this->module_view_map = array();
1699
-        // critical EE page IDs
1700
-        $this->reg_page_id = 0;
1701
-        $this->txn_page_id = 0;
1702
-        $this->thank_you_page_id = 0;
1703
-        $this->cancel_page_id = 0;
1704
-        // critical EE page URLs
1705
-        $this->reg_page_url = '';
1706
-        $this->txn_page_url = '';
1707
-        $this->thank_you_page_url = '';
1708
-        $this->cancel_page_url = '';
1709
-        // cpt slugs
1710
-        $this->event_cpt_slug = esc_html__('events', 'event_espresso');
1711
-        // ueip constant check
1712
-        if (defined('EE_DISABLE_UXIP') && EE_DISABLE_UXIP) {
1713
-            $this->ee_ueip_optin = false;
1714
-            $this->ee_ueip_has_notified = true;
1715
-        }
1716
-    }
1717
-
1718
-
1719
-    /**
1720
-     * @return array
1721
-     */
1722
-    public function get_critical_pages_array()
1723
-    {
1724
-        return array(
1725
-            $this->reg_page_id,
1726
-            $this->txn_page_id,
1727
-            $this->thank_you_page_id,
1728
-            $this->cancel_page_id,
1729
-        );
1730
-    }
1731
-
1732
-
1733
-    /**
1734
-     * @return array
1735
-     */
1736
-    public function get_critical_pages_shortcodes_array()
1737
-    {
1738
-        return array(
1739
-            $this->reg_page_id       => 'ESPRESSO_CHECKOUT',
1740
-            $this->txn_page_id       => 'ESPRESSO_TXN_PAGE',
1741
-            $this->thank_you_page_id => 'ESPRESSO_THANK_YOU',
1742
-            $this->cancel_page_id    => 'ESPRESSO_CANCELLED',
1743
-        );
1744
-    }
1745
-
1746
-
1747
-    /**
1748
-     *  gets/returns URL for EE reg_page
1749
-     *
1750
-     * @access    public
1751
-     * @return    string
1752
-     */
1753
-    public function reg_page_url()
1754
-    {
1755
-        if (! $this->reg_page_url) {
1756
-            $this->reg_page_url = add_query_arg(
1757
-                array('uts' => time()),
1758
-                get_permalink($this->reg_page_id)
1759
-            ) . '#checkout';
1760
-        }
1761
-        return $this->reg_page_url;
1762
-    }
1763
-
1764
-
1765
-    /**
1766
-     *  gets/returns URL for EE txn_page
1767
-     *
1768
-     * @param array $query_args like what gets passed to
1769
-     *                          add_query_arg() as the first argument
1770
-     * @access    public
1771
-     * @return    string
1772
-     */
1773
-    public function txn_page_url($query_args = array())
1774
-    {
1775
-        if (! $this->txn_page_url) {
1776
-            $this->txn_page_url = get_permalink($this->txn_page_id);
1777
-        }
1778
-        if ($query_args) {
1779
-            return add_query_arg($query_args, $this->txn_page_url);
1780
-        } else {
1781
-            return $this->txn_page_url;
1782
-        }
1783
-    }
1784
-
1785
-
1786
-    /**
1787
-     *  gets/returns URL for EE thank_you_page
1788
-     *
1789
-     * @param array $query_args like what gets passed to
1790
-     *                          add_query_arg() as the first argument
1791
-     * @access    public
1792
-     * @return    string
1793
-     */
1794
-    public function thank_you_page_url($query_args = array())
1795
-    {
1796
-        if (! $this->thank_you_page_url) {
1797
-            $this->thank_you_page_url = get_permalink($this->thank_you_page_id);
1798
-        }
1799
-        if ($query_args) {
1800
-            return add_query_arg($query_args, $this->thank_you_page_url);
1801
-        } else {
1802
-            return $this->thank_you_page_url;
1803
-        }
1804
-    }
1805
-
1806
-
1807
-    /**
1808
-     *  gets/returns URL for EE cancel_page
1809
-     *
1810
-     * @access    public
1811
-     * @return    string
1812
-     */
1813
-    public function cancel_page_url()
1814
-    {
1815
-        if (! $this->cancel_page_url) {
1816
-            $this->cancel_page_url = get_permalink($this->cancel_page_id);
1817
-        }
1818
-        return $this->cancel_page_url;
1819
-    }
1820
-
1821
-
1822
-    /**
1823
-     * Resets all critical page urls to their original state.  Used primarily by the __sleep() magic method currently.
1824
-     *
1825
-     * @since 4.7.5
1826
-     */
1827
-    protected function _reset_urls()
1828
-    {
1829
-        $this->reg_page_url = '';
1830
-        $this->txn_page_url = '';
1831
-        $this->cancel_page_url = '';
1832
-        $this->thank_you_page_url = '';
1833
-    }
1834
-
1835
-
1836
-    /**
1837
-     * Used to return what the optin value is set for the EE User Experience Program.
1838
-     * This accounts for multisite and this value being requested for a subsite.  In multisite, the value is set
1839
-     * on the main site only.
1840
-     *
1841
-     * @return bool
1842
-     */
1843
-    protected function _get_main_ee_ueip_optin()
1844
-    {
1845
-        // if this is the main site then we can just bypass our direct query.
1846
-        if (is_main_site()) {
1847
-            return get_option(self::OPTION_NAME_UXIP, false);
1848
-        }
1849
-        // is this already cached for this request?  If so use it.
1850
-        if (EE_Core_Config::$ee_ueip_option !== null) {
1851
-            return EE_Core_Config::$ee_ueip_option;
1852
-        }
1853
-        global $wpdb;
1854
-        $current_network_main_site = is_multisite() ? get_current_site() : null;
1855
-        $current_main_site_id = ! empty($current_network_main_site) ? $current_network_main_site->blog_id : 1;
1856
-        $option = self::OPTION_NAME_UXIP;
1857
-        // set correct table for query
1858
-        $table_name = $wpdb->get_blog_prefix($current_main_site_id) . 'options';
1859
-        // rather than getting blog option for the $current_main_site_id, we do a direct $wpdb query because
1860
-        // get_blog_option() does a switch_to_blog an that could cause infinite recursion because EE_Core_Config might be
1861
-        // re-constructed on the blog switch.  Note, we are still executing any core wp filters on this option retrieval.
1862
-        // this bit of code is basically a direct copy of get_option without any caching because we are NOT switched to the blog
1863
-        // for the purpose of caching.
1864
-        $pre = apply_filters('pre_option_' . $option, false, $option);
1865
-        if (false !== $pre) {
1866
-            EE_Core_Config::$ee_ueip_option = $pre;
1867
-            return EE_Core_Config::$ee_ueip_option;
1868
-        }
1869
-        $row = $wpdb->get_row(
1870
-            $wpdb->prepare(
1871
-                "SELECT option_value FROM $table_name WHERE option_name = %s LIMIT 1",
1872
-                $option
1873
-            )
1874
-        );
1875
-        if (is_object($row)) {
1876
-            $value = $row->option_value;
1877
-        } else { // option does not exist so use default.
1878
-            EE_Core_Config::$ee_ueip_option =  apply_filters('default_option_' . $option, false, $option);
1879
-            return EE_Core_Config::$ee_ueip_option;
1880
-        }
1881
-        EE_Core_Config::$ee_ueip_option = apply_filters('option_' . $option, maybe_unserialize($value), $option);
1882
-        return EE_Core_Config::$ee_ueip_option;
1883
-    }
1884
-
1885
-
1886
-    /**
1887
-     * Utility function for escaping the value of a property and returning.
1888
-     *
1889
-     * @param string $property property name (checks to see if exists).
1890
-     * @return mixed if a detected type found return the escaped value, otherwise just the raw value is returned.
1891
-     * @throws EE_Error
1892
-     */
1893
-    public function get_pretty($property)
1894
-    {
1895
-        if ($property === self::OPTION_NAME_UXIP) {
1896
-            return $this->ee_ueip_optin ? 'yes' : 'no';
1897
-        }
1898
-        return parent::get_pretty($property);
1899
-    }
1900
-
1901
-
1902
-    /**
1903
-     * Currently used to ensure critical page urls have initial values saved to the db instead of any current set values
1904
-     * on the object.
1905
-     *
1906
-     * @return array
1907
-     */
1908
-    public function __sleep()
1909
-    {
1910
-        // reset all url properties
1911
-        $this->_reset_urls();
1912
-        // return what to save to db
1913
-        return array_keys(get_object_vars($this));
1914
-    }
1915
-}
1916
-
1917
-/**
1918
- * Config class for storing info on the Organization
1919
- */
1920
-class EE_Organization_Config extends EE_Config_Base
1921
-{
1922
-    /**
1923
-     * @var string $name
1924
-     * eg EE4.1
1925
-     */
1926
-    public $name;
1927
-
1928
-    /**
1929
-     * @var string $address_1
1930
-     * eg 123 Onna Road
1931
-     */
1932
-    public $address_1 = '';
1933
-
1934
-    /**
1935
-     * @var string $address_2
1936
-     * eg PO Box 123
1937
-     */
1938
-    public $address_2 = '';
1939
-
1940
-    /**
1941
-     * @var string $city
1942
-     * eg Inna City
1943
-     */
1944
-    public $city = '';
1945
-
1946
-    /**
1947
-     * @var int $STA_ID
1948
-     * eg 4
1949
-     */
1950
-    public $STA_ID = 0;
1951
-
1952
-    /**
1953
-     * @var string $CNT_ISO
1954
-     * eg US
1955
-     */
1956
-    public $CNT_ISO = '';
1957
-
1958
-    /**
1959
-     * @var string $zip
1960
-     * eg 12345  or V1A 2B3
1961
-     */
1962
-    public $zip = '';
1963
-
1964
-    /**
1965
-     * @var string $email
1966
-     * eg [email protected]
1967
-     */
1968
-    public $email;
1969
-
1970
-    /**
1971
-     * @var string $phone
1972
-     * eg. 111-111-1111
1973
-     */
1974
-    public $phone = '';
1975
-
1976
-    /**
1977
-     * @var string $vat
1978
-     * VAT/Tax Number
1979
-     */
1980
-    public $vat = '';
1981
-
1982
-    /**
1983
-     * @var string $logo_url
1984
-     * eg http://www.somedomain.com/wp-content/uploads/kittehs.jpg
1985
-     */
1986
-    public $logo_url = '';
1987
-
1988
-    /**
1989
-     * The below are all various properties for holding links to organization social network profiles
1990
-     *
1991
-     * @var string
1992
-     */
1993
-    /**
1994
-     * facebook (facebook.com/profile.name)
1995
-     *
1996
-     * @var string
1997
-     */
1998
-    public $facebook = '';
1999
-
2000
-    /**
2001
-     * twitter (twitter.com/twitter_handle)
2002
-     *
2003
-     * @var string
2004
-     */
2005
-    public $twitter = '';
2006
-
2007
-    /**
2008
-     * linkedin (linkedin.com/in/profile_name)
2009
-     *
2010
-     * @var string
2011
-     */
2012
-    public $linkedin = '';
2013
-
2014
-    /**
2015
-     * pinterest (www.pinterest.com/profile_name)
2016
-     *
2017
-     * @var string
2018
-     */
2019
-    public $pinterest = '';
2020
-
2021
-    /**
2022
-     * google+ (google.com/+profileName)
2023
-     *
2024
-     * @var string
2025
-     */
2026
-    public $google = '';
2027
-
2028
-    /**
2029
-     * instagram (instagram.com/handle)
2030
-     *
2031
-     * @var string
2032
-     */
2033
-    public $instagram = '';
2034
-
2035
-
2036
-    /**
2037
-     *    class constructor
2038
-     *
2039
-     * @access    public
2040
-     */
2041
-    public function __construct()
2042
-    {
2043
-        // set default organization settings
2044
-        // decode HTML entities from the WP blogname, because it's stored in the DB with HTML entities encoded
2045
-        $this->name = wp_specialchars_decode(get_bloginfo('name'), ENT_QUOTES);
2046
-        $this->email = get_bloginfo('admin_email');
2047
-    }
2048
-}
2049
-
2050
-/**
2051
- * Class for defining what's in the EE_Config relating to currency
2052
- */
2053
-class EE_Currency_Config extends EE_Config_Base
2054
-{
2055
-    /**
2056
-     * @var string $code
2057
-     * eg 'USD', 'CAD', 'EUR'
2058
-     */
2059
-    public $code;
2060
-
2061
-    /**
2062
-     * locale to use for currency ex: 'en_US'
2063
-     *
2064
-     * @var string
2065
-     */
2066
-    private $locale = 'en_US';
2067
-
2068
-    /**
2069
-     * @var string $name
2070
-     * eg 'Dollar'
2071
-     */
2072
-    public $name;
2073
-
2074
-    /**
2075
-     * plural name
2076
-     *
2077
-     * @var string $plural
2078
-     * eg 'Dollars'
2079
-     */
2080
-    public $plural;
2081
-
2082
-    /**
2083
-     * currency sign
2084
-     *
2085
-     * @var string $sign
2086
-     * eg '$'
2087
-     */
2088
-    public $sign;
2089
-
2090
-    /**
2091
-     * Whether the currency sign should come before the number or not
2092
-     *
2093
-     * @var boolean $sign_b4
2094
-     */
2095
-    public $sign_b4;
2096
-
2097
-    /**
2098
-     * How many digits should come after the decimal place
2099
-     *
2100
-     * @var int $dec_plc
2101
-     */
2102
-    public $dec_plc;
2103
-
2104
-    /**
2105
-     * Symbol to use for decimal mark
2106
-     *
2107
-     * @var string $dec_mrk
2108
-     * eg '.'
2109
-     */
2110
-    public $dec_mrk;
2111
-
2112
-    /**
2113
-     * Symbol to use for thousands
2114
-     *
2115
-     * @var string $thsnds
2116
-     * eg ','
2117
-     */
2118
-    public $thsnds;
2119
-
2120
-
2121
-    /**
2122
-     *    class constructor
2123
-     *
2124
-     * @access    public
2125
-     * @param string $CNT_ISO
2126
-     * @throws EE_Error
2127
-     * @throws ReflectionException
2128
-     */
2129
-    public function __construct($CNT_ISO = '')
2130
-    {
2131
-        /** @var TableAnalysis $table_analysis */
2132
-        $table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
2133
-        // get country code from organization settings or use default
2134
-        $ORG_CNT = isset(EE_Registry::instance()->CFG->organization)
2135
-                   && EE_Registry::instance()->CFG->organization instanceof EE_Organization_Config
2136
-            ? EE_Registry::instance()->CFG->organization->CNT_ISO
2137
-            : '';
2138
-        // but override if requested
2139
-        $CNT_ISO = ! empty($CNT_ISO) ? $CNT_ISO : $ORG_CNT;
2140
-        // so if that all went well, and we are not in M-Mode (cuz you can't query the db in M-Mode) and double-check the countries table exists
2141
-        if (
2142
-            ! empty($CNT_ISO)
2143
-            && EE_Maintenance_Mode::instance()->models_can_query()
2144
-            && $table_analysis->tableExists(EE_Registry::instance()->load_model('Country')->table())
2145
-        ) {
2146
-            // retrieve the country settings from the db, just in case they have been customized
2147
-            $country = EE_Registry::instance()->load_model('Country')->get_one_by_ID($CNT_ISO);
2148
-            if ($country instanceof EE_Country) {
2149
-                $this->code = $country->currency_code();    // currency code: USD, CAD, EUR
2150
-                $this->name = $country->currency_name_single();    // Dollar
2151
-                $this->plural = $country->currency_name_plural();    // Dollars
2152
-                $this->sign = $country->currency_sign();            // currency sign: $
2153
-                $this->sign_b4 = $country->currency_sign_before(
2154
-                );        // currency sign before or after: $TRUE  or  FALSE$
2155
-                $this->dec_plc = $country->currency_decimal_places();    // decimal places: 2 = 0.00  3 = 0.000
2156
-                $this->dec_mrk = $country->currency_decimal_mark(
2157
-                );    // decimal mark: (comma) ',' = 0,01   or (decimal) '.' = 0.01
2158
-                $this->thsnds = $country->currency_thousands_separator(
2159
-                );    // thousands separator: (comma) ',' = 1,000   or (decimal) '.' = 1.000
2160
-            }
2161
-        }
2162
-        // fallback to hardcoded defaults, in case the above failed
2163
-        if (empty($this->code)) {
2164
-            // set default currency settings
2165
-            $this->code = 'USD';    // currency code: USD, CAD, EUR
2166
-            $this->locale = 'en_US';
2167
-            $this->name = esc_html__('Dollar', 'event_espresso');    // Dollar
2168
-            $this->plural = esc_html__('Dollars', 'event_espresso');    // Dollars
2169
-            $this->sign = '$';    // currency sign: $
2170
-            $this->sign_b4 = true;    // currency sign before or after: $TRUE  or  FALSE$
2171
-            $this->dec_plc = 2;    // decimal places: 2 = 0.00  3 = 0.000
2172
-            $this->dec_mrk = '.';    // decimal mark: (comma) ',' = 0,01   or (decimal) '.' = 0.01
2173
-            $this->thsnds = ',';    // thousands separator: (comma) ',' = 1,000   or (decimal) '.' = 1.000
2174
-        }
2175
-        if (empty($this->locale)) {
2176
-            $this->locale = get_site_option('WPLANG');
2177
-        }
2178
-    }
2179
-
2180
-
2181
-    /**
2182
-     * @return string
2183
-     */
2184
-    public function locale()
2185
-    {
2186
-        return $this->locale;
2187
-    }
2188
-
2189
-
2190
-    /**
2191
-     * @param string $locale
2192
-     */
2193
-    public function setLocale($locale)
2194
-    {
2195
-        $this->locale = sanitize_text_field($locale);
2196
-    }
2197
-}
2198
-
2199
-
2200
-/**
2201
- * Class for defining what's in the EE_Config relating to registration settings
2202
- */
2203
-class EE_Registration_Config extends EE_Config_Base
2204
-{
2205
-    /**
2206
-     * Default registration status
2207
-     *
2208
-     * @var string $default_STS_ID
2209
-     * eg 'RPP'
2210
-     */
2211
-    public $default_STS_ID;
2212
-
2213
-    /**
2214
-     * For new events, this will be the default value for the maximum number of tickets (equivalent to maximum number of
2215
-     * registrations)
2216
-     *
2217
-     * @var int
2218
-     */
2219
-    public $default_maximum_number_of_tickets;
2220
-
2221
-    /**
2222
-     * level of validation to apply to email addresses
2223
-     *
2224
-     * @var string $email_validation_level
2225
-     * options: 'basic', 'wp_default', 'i18n', 'i18n_dns'
2226
-     */
2227
-    public $email_validation_level;
2228
-
2229
-    /**
2230
-     *    whether or not to show alternate payment options during the reg process if payment status is pending
2231
-     *
2232
-     * @var boolean $show_pending_payment_options
2233
-     */
2234
-    public $show_pending_payment_options;
2235
-
2236
-    /**
2237
-     * Whether to skip the registration confirmation page
2238
-     *
2239
-     * @var boolean $skip_reg_confirmation
2240
-     */
2241
-    public $skip_reg_confirmation;
2242
-
2243
-    /**
2244
-     * an array of SPCO reg steps where:
2245
-     *        the keys denotes the reg step order
2246
-     *        each element consists of an array with the following elements:
2247
-     *            "file_path" => the file path to the EE_SPCO_Reg_Step class
2248
-     *            "class_name" => the specific EE_SPCO_Reg_Step child class name
2249
-     *            "slug" => the URL param used to trigger the reg step
2250
-     *
2251
-     * @var array $reg_steps
2252
-     */
2253
-    public $reg_steps;
2254
-
2255
-    /**
2256
-     * Whether registration confirmation should be the last page of SPCO
2257
-     *
2258
-     * @var boolean $reg_confirmation_last
2259
-     */
2260
-    public $reg_confirmation_last;
2261
-
2262
-    /**
2263
-     * Whether or not to enable the EE Bot Trap
2264
-     *
2265
-     * @var boolean $use_bot_trap
2266
-     */
2267
-    public $use_bot_trap;
2268
-
2269
-    /**
2270
-     * Whether or not to encrypt some data sent by the EE Bot Trap
2271
-     *
2272
-     * @var boolean $use_encryption
2273
-     */
2274
-    public $use_encryption;
2275
-
2276
-    /**
2277
-     * Whether or not to use ReCaptcha
2278
-     *
2279
-     * @var boolean $use_captcha
2280
-     */
2281
-    public $use_captcha;
2282
-
2283
-    /**
2284
-     * ReCaptcha Theme
2285
-     *
2286
-     * @var string $recaptcha_theme
2287
-     *    options: 'dark', 'light', 'invisible'
2288
-     */
2289
-    public $recaptcha_theme;
2290
-
2291
-    /**
2292
-     * ReCaptcha Badge - determines the position of the reCAPTCHA badge if using Invisible ReCaptcha.
2293
-     *
2294
-     * @var string $recaptcha_badge
2295
-     *    options: 'bottomright', 'bottomleft', 'inline'
2296
-     */
2297
-    public $recaptcha_badge;
2298
-
2299
-    /**
2300
-     * ReCaptcha Type
2301
-     *
2302
-     * @var string $recaptcha_type
2303
-     *    options: 'audio', 'image'
2304
-     */
2305
-    public $recaptcha_type;
2306
-
2307
-    /**
2308
-     * ReCaptcha language
2309
-     *
2310
-     * @var string $recaptcha_language
2311
-     * eg 'en'
2312
-     */
2313
-    public $recaptcha_language;
2314
-
2315
-    /**
2316
-     * ReCaptcha public key
2317
-     *
2318
-     * @var string $recaptcha_publickey
2319
-     */
2320
-    public $recaptcha_publickey;
2321
-
2322
-    /**
2323
-     * ReCaptcha private key
2324
-     *
2325
-     * @var string $recaptcha_privatekey
2326
-     */
2327
-    public $recaptcha_privatekey;
21
+	const OPTION_NAME = 'ee_config';
22
+
23
+	const LOG_NAME = 'ee_config_log';
24
+
25
+	const LOG_LENGTH = 100;
26
+
27
+	const ADDON_OPTION_NAMES = 'ee_config_option_names';
28
+
29
+	/**
30
+	 *    instance of the EE_Config object
31
+	 *
32
+	 * @var    EE_Config $_instance
33
+	 * @access    private
34
+	 */
35
+	private static $_instance;
36
+
37
+	/**
38
+	 * @var boolean $_logging_enabled
39
+	 */
40
+	private static $_logging_enabled = false;
41
+
42
+	/**
43
+	 * @var LegacyShortcodesManager $legacy_shortcodes_manager
44
+	 */
45
+	private $legacy_shortcodes_manager;
46
+
47
+	/**
48
+	 * An StdClass whose property names are addon slugs,
49
+	 * and values are their config classes
50
+	 *
51
+	 * @var StdClass
52
+	 */
53
+	public $addons;
54
+
55
+	/**
56
+	 * @var EE_Admin_Config
57
+	 */
58
+	public $admin;
59
+
60
+	/**
61
+	 * @var EE_Core_Config
62
+	 */
63
+	public $core;
64
+
65
+	/**
66
+	 * @var EE_Currency_Config
67
+	 */
68
+	public $currency;
69
+
70
+	/**
71
+	 * @var EE_Organization_Config
72
+	 */
73
+	public $organization;
74
+
75
+	/**
76
+	 * @var EE_Registration_Config
77
+	 */
78
+	public $registration;
79
+
80
+	/**
81
+	 * @var EE_Template_Config
82
+	 */
83
+	public $template_settings;
84
+
85
+	/**
86
+	 * Holds EE environment values.
87
+	 *
88
+	 * @var EE_Environment_Config
89
+	 */
90
+	public $environment;
91
+
92
+	/**
93
+	 * settings pertaining to Google maps
94
+	 *
95
+	 * @var EE_Map_Config
96
+	 */
97
+	public $map_settings;
98
+
99
+	/**
100
+	 * settings pertaining to Taxes
101
+	 *
102
+	 * @var EE_Tax_Config
103
+	 */
104
+	public $tax_settings;
105
+
106
+	/**
107
+	 * Settings pertaining to global messages settings.
108
+	 *
109
+	 * @var EE_Messages_Config
110
+	 */
111
+	public $messages;
112
+
113
+	/**
114
+	 * @deprecated
115
+	 * @var EE_Gateway_Config
116
+	 */
117
+	public $gateway;
118
+
119
+	/**
120
+	 * @var    array $_addon_option_names
121
+	 * @access    private
122
+	 */
123
+	private $_addon_option_names = array();
124
+
125
+	/**
126
+	 * @var    array $_module_route_map
127
+	 * @access    private
128
+	 */
129
+	private static $_module_route_map = array();
130
+
131
+	/**
132
+	 * @var    array $_module_forward_map
133
+	 * @access    private
134
+	 */
135
+	private static $_module_forward_map = array();
136
+
137
+	/**
138
+	 * @var    array $_module_view_map
139
+	 * @access    private
140
+	 */
141
+	private static $_module_view_map = array();
142
+
143
+
144
+	/**
145
+	 * @singleton method used to instantiate class object
146
+	 * @access    public
147
+	 * @return EE_Config instance
148
+	 */
149
+	public static function instance()
150
+	{
151
+		// check if class object is instantiated, and instantiated properly
152
+		if (! self::$_instance instanceof EE_Config) {
153
+			self::$_instance = new self();
154
+		}
155
+		return self::$_instance;
156
+	}
157
+
158
+
159
+	/**
160
+	 * Resets the config
161
+	 *
162
+	 * @param bool    $hard_reset    if TRUE, sets EE_CONFig back to its original settings in the database. If FALSE
163
+	 *                               (default) leaves the database alone, and merely resets the EE_Config object to
164
+	 *                               reflect its state in the database
165
+	 * @param boolean $reinstantiate if TRUE (default) call instance() and return it. Otherwise, just leave
166
+	 *                               $_instance as NULL. Useful in case you want to forget about the old instance on
167
+	 *                               EE_Config, but might not be ready to instantiate EE_Config currently (eg if the
168
+	 *                               site was put into maintenance mode)
169
+	 * @return EE_Config
170
+	 */
171
+	public static function reset($hard_reset = false, $reinstantiate = true)
172
+	{
173
+		if (self::$_instance instanceof EE_Config) {
174
+			if ($hard_reset) {
175
+				self::$_instance->legacy_shortcodes_manager = null;
176
+				self::$_instance->_addon_option_names = array();
177
+				self::$_instance->_initialize_config();
178
+				self::$_instance->update_espresso_config();
179
+			}
180
+			self::$_instance->update_addon_option_names();
181
+		}
182
+		self::$_instance = null;
183
+		// we don't need to reset the static properties imo because those should
184
+		// only change when a module is added or removed. Currently we don't
185
+		// support removing a module during a request when it previously existed
186
+		if ($reinstantiate) {
187
+			return self::instance();
188
+		} else {
189
+			return null;
190
+		}
191
+	}
192
+
193
+
194
+	/**
195
+	 *    class constructor
196
+	 *
197
+	 * @access    private
198
+	 */
199
+	private function __construct()
200
+	{
201
+		do_action('AHEE__EE_Config__construct__begin', $this);
202
+		EE_Config::$_logging_enabled = apply_filters('FHEE__EE_Config___construct__logging_enabled', false);
203
+		// setup empty config classes
204
+		$this->_initialize_config();
205
+		// load existing EE site settings
206
+		$this->_load_core_config();
207
+		// confirm everything loaded correctly and set filtered defaults if not
208
+		$this->_verify_config();
209
+		//  register shortcodes and modules
210
+		add_action(
211
+			'AHEE__EE_System__register_shortcodes_modules_and_widgets',
212
+			array($this, 'register_shortcodes_and_modules'),
213
+			999
214
+		);
215
+		//  initialize shortcodes and modules
216
+		add_action('AHEE__EE_System__core_loaded_and_ready', array($this, 'initialize_shortcodes_and_modules'));
217
+		// register widgets
218
+		add_action('widgets_init', array($this, 'widgets_init'), 10);
219
+		// shutdown
220
+		add_action('shutdown', array($this, 'shutdown'), 10);
221
+		// construct__end hook
222
+		do_action('AHEE__EE_Config__construct__end', $this);
223
+		// hardcoded hack
224
+		$this->template_settings->current_espresso_theme = 'Espresso_Arabica_2014';
225
+	}
226
+
227
+
228
+	/**
229
+	 * @return boolean
230
+	 */
231
+	public static function logging_enabled()
232
+	{
233
+		return self::$_logging_enabled;
234
+	}
235
+
236
+
237
+	/**
238
+	 * use to get the current theme if needed from static context
239
+	 *
240
+	 * @return string current theme set.
241
+	 */
242
+	public static function get_current_theme()
243
+	{
244
+		return isset(self::$_instance->template_settings->current_espresso_theme)
245
+			? self::$_instance->template_settings->current_espresso_theme : 'Espresso_Arabica_2014';
246
+	}
247
+
248
+
249
+	/**
250
+	 *        _initialize_config
251
+	 *
252
+	 * @access private
253
+	 * @return void
254
+	 */
255
+	private function _initialize_config()
256
+	{
257
+		EE_Config::trim_log();
258
+		// set defaults
259
+		$this->_addon_option_names = get_option(EE_Config::ADDON_OPTION_NAMES, array());
260
+		$this->addons = new stdClass();
261
+		// set _module_route_map
262
+		EE_Config::$_module_route_map = array();
263
+		// set _module_forward_map
264
+		EE_Config::$_module_forward_map = array();
265
+		// set _module_view_map
266
+		EE_Config::$_module_view_map = array();
267
+	}
268
+
269
+
270
+	/**
271
+	 *        load core plugin configuration
272
+	 *
273
+	 * @access private
274
+	 * @return void
275
+	 */
276
+	private function _load_core_config()
277
+	{
278
+		// load_core_config__start hook
279
+		do_action('AHEE__EE_Config___load_core_config__start', $this);
280
+		$espresso_config = $this->get_espresso_config();
281
+		foreach ($espresso_config as $config => $settings) {
282
+			// load_core_config__start hook
283
+			$settings = apply_filters(
284
+				'FHEE__EE_Config___load_core_config__config_settings',
285
+				$settings,
286
+				$config,
287
+				$this
288
+			);
289
+			if (is_object($settings) && property_exists($this, $config)) {
290
+				$this->{$config} = apply_filters('FHEE__EE_Config___load_core_config__' . $config, $settings);
291
+				// call configs populate method to ensure any defaults are set for empty values.
292
+				if (method_exists($settings, 'populate')) {
293
+					$this->{$config}->populate();
294
+				}
295
+				if (method_exists($settings, 'do_hooks')) {
296
+					$this->{$config}->do_hooks();
297
+				}
298
+			}
299
+		}
300
+		if (apply_filters('FHEE__EE_Config___load_core_config__update_espresso_config', false)) {
301
+			$this->update_espresso_config();
302
+		}
303
+		// load_core_config__end hook
304
+		do_action('AHEE__EE_Config___load_core_config__end', $this);
305
+	}
306
+
307
+
308
+	/**
309
+	 *    _verify_config
310
+	 *
311
+	 * @access    protected
312
+	 * @return    void
313
+	 */
314
+	protected function _verify_config()
315
+	{
316
+		$this->core = $this->core instanceof EE_Core_Config
317
+			? $this->core
318
+			: new EE_Core_Config();
319
+		$this->core = apply_filters('FHEE__EE_Config___initialize_config__core', $this->core);
320
+		$this->organization = $this->organization instanceof EE_Organization_Config
321
+			? $this->organization
322
+			: new EE_Organization_Config();
323
+		$this->organization = apply_filters(
324
+			'FHEE__EE_Config___initialize_config__organization',
325
+			$this->organization
326
+		);
327
+		$this->currency = $this->currency instanceof EE_Currency_Config
328
+			? $this->currency
329
+			: new EE_Currency_Config();
330
+		$this->currency = apply_filters('FHEE__EE_Config___initialize_config__currency', $this->currency);
331
+		$this->registration = $this->registration instanceof EE_Registration_Config
332
+			? $this->registration
333
+			: new EE_Registration_Config();
334
+		$this->registration = apply_filters(
335
+			'FHEE__EE_Config___initialize_config__registration',
336
+			$this->registration
337
+		);
338
+		$this->admin = $this->admin instanceof EE_Admin_Config
339
+			? $this->admin
340
+			: new EE_Admin_Config();
341
+		$this->admin = apply_filters('FHEE__EE_Config___initialize_config__admin', $this->admin);
342
+		$this->template_settings = $this->template_settings instanceof EE_Template_Config
343
+			? $this->template_settings
344
+			: new EE_Template_Config();
345
+		$this->template_settings = apply_filters(
346
+			'FHEE__EE_Config___initialize_config__template_settings',
347
+			$this->template_settings
348
+		);
349
+		$this->map_settings = $this->map_settings instanceof EE_Map_Config
350
+			? $this->map_settings
351
+			: new EE_Map_Config();
352
+		$this->map_settings = apply_filters(
353
+			'FHEE__EE_Config___initialize_config__map_settings',
354
+			$this->map_settings
355
+		);
356
+		$this->environment = $this->environment instanceof EE_Environment_Config
357
+			? $this->environment
358
+			: new EE_Environment_Config();
359
+		$this->environment = apply_filters(
360
+			'FHEE__EE_Config___initialize_config__environment',
361
+			$this->environment
362
+		);
363
+		$this->tax_settings = $this->tax_settings instanceof EE_Tax_Config
364
+			? $this->tax_settings
365
+			: new EE_Tax_Config();
366
+		$this->tax_settings = apply_filters(
367
+			'FHEE__EE_Config___initialize_config__tax_settings',
368
+			$this->tax_settings
369
+		);
370
+		$this->messages = apply_filters('FHEE__EE_Config__initialize_config__messages', $this->messages);
371
+		$this->messages = $this->messages instanceof EE_Messages_Config
372
+			? $this->messages
373
+			: new EE_Messages_Config();
374
+		$this->gateway = $this->gateway instanceof EE_Gateway_Config
375
+			? $this->gateway
376
+			: new EE_Gateway_Config();
377
+		$this->gateway = apply_filters('FHEE__EE_Config___initialize_config__gateway', $this->gateway);
378
+		$this->legacy_shortcodes_manager = null;
379
+	}
380
+
381
+
382
+	/**
383
+	 *    get_espresso_config
384
+	 *
385
+	 * @access    public
386
+	 * @return    array of espresso config stuff
387
+	 */
388
+	public function get_espresso_config()
389
+	{
390
+		// grab espresso configuration
391
+		return apply_filters(
392
+			'FHEE__EE_Config__get_espresso_config__CFG',
393
+			get_option(EE_Config::OPTION_NAME, array())
394
+		);
395
+	}
396
+
397
+
398
+	/**
399
+	 *    double_check_config_comparison
400
+	 *
401
+	 * @access    public
402
+	 * @param string $option
403
+	 * @param        $old_value
404
+	 * @param        $value
405
+	 */
406
+	public function double_check_config_comparison($option, $old_value, $value)
407
+	{
408
+		// make sure we're checking the ee config
409
+		if ($option === EE_Config::OPTION_NAME) {
410
+			// run a loose comparison of the old value against the new value for type and properties,
411
+			// but NOT exact instance like WP update_option does (ie: NOT type safe comparison)
412
+			if ($value != $old_value) {
413
+				// if they are NOT the same, then remove the hook,
414
+				// which means the subsequent update results will be based solely on the update query results
415
+				// the reason we do this is because, as stated above,
416
+				// WP update_option performs an exact instance comparison (===) on any update values passed to it
417
+				// this happens PRIOR to serialization and any subsequent update.
418
+				// If values are found to match their previous old value,
419
+				// then WP bails before performing any update.
420
+				// Since we are passing the EE_Config object, it is comparing the EXACT instance of the saved version
421
+				// it just pulled from the db, with the one being passed to it (which will not match).
422
+				// HOWEVER, once the object is serialized and passed off to MySQL to update,
423
+				// MySQL MAY ALSO NOT perform the update because
424
+				// the string it sees in the db looks the same as the new one it has been passed!!!
425
+				// This results in the query returning an "affected rows" value of ZERO,
426
+				// which gets returned immediately by WP update_option and looks like an error.
427
+				remove_action('update_option', array($this, 'check_config_updated'));
428
+			}
429
+		}
430
+	}
431
+
432
+
433
+	/**
434
+	 *    update_espresso_config
435
+	 *
436
+	 * @access   public
437
+	 */
438
+	protected function _reset_espresso_addon_config()
439
+	{
440
+		$this->_addon_option_names = array();
441
+		foreach ($this->addons as $addon_name => $addon_config_obj) {
442
+			$addon_config_obj = maybe_unserialize($addon_config_obj);
443
+			if ($addon_config_obj instanceof EE_Config_Base) {
444
+				$this->update_config('addons', $addon_name, $addon_config_obj, false);
445
+			}
446
+			$this->addons->{$addon_name} = null;
447
+		}
448
+	}
449
+
450
+
451
+	/**
452
+	 *    update_espresso_config
453
+	 *
454
+	 * @access   public
455
+	 * @param   bool $add_success
456
+	 * @param   bool $add_error
457
+	 * @return   bool
458
+	 */
459
+	public function update_espresso_config($add_success = false, $add_error = true)
460
+	{
461
+		// don't allow config updates during WP heartbeats
462
+		/** @var RequestInterface $request */
463
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
464
+		if ($request->isWordPressHeartbeat()) {
465
+			return false;
466
+		}
467
+		// commented out the following re: https://events.codebasehq.com/projects/event-espresso/tickets/8197
468
+		// $clone = clone( self::$_instance );
469
+		// self::$_instance = NULL;
470
+		do_action('AHEE__EE_Config__update_espresso_config__begin', $this);
471
+		$this->_reset_espresso_addon_config();
472
+		// hook into update_option because that happens AFTER the ( $value === $old_value ) conditional
473
+		// but BEFORE the actual update occurs
474
+		add_action('update_option', array($this, 'double_check_config_comparison'), 1, 3);
475
+		// don't want to persist legacy_shortcodes_manager, but don't want to lose it either
476
+		$legacy_shortcodes_manager = $this->legacy_shortcodes_manager;
477
+		$this->legacy_shortcodes_manager = null;
478
+		// now update "ee_config"
479
+		$saved = update_option(EE_Config::OPTION_NAME, $this);
480
+		$this->legacy_shortcodes_manager = $legacy_shortcodes_manager;
481
+		EE_Config::log(EE_Config::OPTION_NAME);
482
+		// if not saved... check if the hook we just added still exists;
483
+		// if it does, it means one of two things:
484
+		// that update_option bailed at the($value === $old_value) conditional,
485
+		// or...
486
+		// the db update query returned 0 rows affected
487
+		// (probably because the data  value was the same from it's perspective)
488
+		// so the existence of the hook means that a negative result from update_option is NOT an error,
489
+		// but just means no update occurred, so don't display an error to the user.
490
+		// BUT... if update_option returns FALSE, AND the hook is missing,
491
+		// then it means that something truly went wrong
492
+		$saved = ! $saved ? has_action('update_option', array($this, 'double_check_config_comparison')) : $saved;
493
+		// remove our action since we don't want it in the system anymore
494
+		remove_action('update_option', array($this, 'double_check_config_comparison'), 1);
495
+		do_action('AHEE__EE_Config__update_espresso_config__end', $this, $saved);
496
+		// self::$_instance = $clone;
497
+		// unset( $clone );
498
+		// if config remains the same or was updated successfully
499
+		if ($saved) {
500
+			if ($add_success) {
501
+				EE_Error::add_success(
502
+					esc_html__('The Event Espresso Configuration Settings have been successfully updated.', 'event_espresso'),
503
+					__FILE__,
504
+					__FUNCTION__,
505
+					__LINE__
506
+				);
507
+			}
508
+			return true;
509
+		} else {
510
+			if ($add_error) {
511
+				EE_Error::add_error(
512
+					esc_html__('The Event Espresso Configuration Settings were not updated.', 'event_espresso'),
513
+					__FILE__,
514
+					__FUNCTION__,
515
+					__LINE__
516
+				);
517
+			}
518
+			return false;
519
+		}
520
+	}
521
+
522
+
523
+	/**
524
+	 *    _verify_config_params
525
+	 *
526
+	 * @access    private
527
+	 * @param    string         $section
528
+	 * @param    string         $name
529
+	 * @param    string         $config_class
530
+	 * @param    EE_Config_Base $config_obj
531
+	 * @param    array          $tests_to_run
532
+	 * @param    bool           $display_errors
533
+	 * @return    bool    TRUE on success, FALSE on fail
534
+	 */
535
+	private function _verify_config_params(
536
+		$section = '',
537
+		$name = '',
538
+		$config_class = '',
539
+		$config_obj = null,
540
+		$tests_to_run = array(1, 2, 3, 4, 5, 6, 7, 8),
541
+		$display_errors = true
542
+	) {
543
+		try {
544
+			foreach ($tests_to_run as $test) {
545
+				switch ($test) {
546
+					// TEST #1 : check that section was set
547
+					case 1:
548
+						if (empty($section)) {
549
+							if ($display_errors) {
550
+								throw new EE_Error(
551
+									sprintf(
552
+										esc_html__(
553
+											'No configuration section has been provided while attempting to save "%s".',
554
+											'event_espresso'
555
+										),
556
+										$config_class
557
+									)
558
+								);
559
+							}
560
+							return false;
561
+						}
562
+						break;
563
+					// TEST #2 : check that settings section exists
564
+					case 2:
565
+						if (! isset($this->{$section})) {
566
+							if ($display_errors) {
567
+								throw new EE_Error(
568
+									sprintf(
569
+										esc_html__('The "%s" configuration section does not exist.', 'event_espresso'),
570
+										$section
571
+									)
572
+								);
573
+							}
574
+							return false;
575
+						}
576
+						break;
577
+					// TEST #3 : check that section is the proper format
578
+					case 3:
579
+						if (
580
+							! ($this->{$section} instanceof EE_Config_Base || $this->{$section} instanceof stdClass)
581
+						) {
582
+							if ($display_errors) {
583
+								throw new EE_Error(
584
+									sprintf(
585
+										esc_html__(
586
+											'The "%s" configuration settings have not been formatted correctly.',
587
+											'event_espresso'
588
+										),
589
+										$section
590
+									)
591
+								);
592
+							}
593
+							return false;
594
+						}
595
+						break;
596
+					// TEST #4 : check that config section name has been set
597
+					case 4:
598
+						if (empty($name)) {
599
+							if ($display_errors) {
600
+								throw new EE_Error(
601
+									esc_html__(
602
+										'No name has been provided for the specific configuration section.',
603
+										'event_espresso'
604
+									)
605
+								);
606
+							}
607
+							return false;
608
+						}
609
+						break;
610
+					// TEST #5 : check that a config class name has been set
611
+					case 5:
612
+						if (empty($config_class)) {
613
+							if ($display_errors) {
614
+								throw new EE_Error(
615
+									esc_html__(
616
+										'No class name has been provided for the specific configuration section.',
617
+										'event_espresso'
618
+									)
619
+								);
620
+							}
621
+							return false;
622
+						}
623
+						break;
624
+					// TEST #6 : verify config class is accessible
625
+					case 6:
626
+						if (! class_exists($config_class)) {
627
+							if ($display_errors) {
628
+								throw new EE_Error(
629
+									sprintf(
630
+										esc_html__(
631
+											'The "%s" class does not exist. Please ensure that an autoloader has been set for it.',
632
+											'event_espresso'
633
+										),
634
+										$config_class
635
+									)
636
+								);
637
+							}
638
+							return false;
639
+						}
640
+						break;
641
+					// TEST #7 : check that config has even been set
642
+					case 7:
643
+						if (! isset($this->{$section}->{$name})) {
644
+							if ($display_errors) {
645
+								throw new EE_Error(
646
+									sprintf(
647
+										esc_html__('No configuration has been set for "%1$s->%2$s".', 'event_espresso'),
648
+										$section,
649
+										$name
650
+									)
651
+								);
652
+							}
653
+							return false;
654
+						} else {
655
+							// and make sure it's not serialized
656
+							$this->{$section}->{$name} = maybe_unserialize($this->{$section}->{$name});
657
+						}
658
+						break;
659
+					// TEST #8 : check that config is the requested type
660
+					case 8:
661
+						if (! $this->{$section}->{$name} instanceof $config_class) {
662
+							if ($display_errors) {
663
+								throw new EE_Error(
664
+									sprintf(
665
+										esc_html__(
666
+											'The configuration for "%1$s->%2$s" is not of the "%3$s" class.',
667
+											'event_espresso'
668
+										),
669
+										$section,
670
+										$name,
671
+										$config_class
672
+									)
673
+								);
674
+							}
675
+							return false;
676
+						}
677
+						break;
678
+					// TEST #9 : verify config object
679
+					case 9:
680
+						if (! $config_obj instanceof EE_Config_Base) {
681
+							if ($display_errors) {
682
+								throw new EE_Error(
683
+									sprintf(
684
+										esc_html__('The "%s" class is not an instance of EE_Config_Base.', 'event_espresso'),
685
+										print_r($config_obj, true)
686
+									)
687
+								);
688
+							}
689
+							return false;
690
+						}
691
+						break;
692
+				}
693
+			}
694
+		} catch (EE_Error $e) {
695
+			$e->get_error();
696
+		}
697
+		// you have successfully run the gauntlet
698
+		return true;
699
+	}
700
+
701
+
702
+	/**
703
+	 *    _generate_config_option_name
704
+	 *
705
+	 * @access        protected
706
+	 * @param        string $section
707
+	 * @param        string $name
708
+	 * @return        string
709
+	 */
710
+	private function _generate_config_option_name($section = '', $name = '')
711
+	{
712
+		return 'ee_config-' . strtolower($section . '-' . str_replace(array('EE_', 'EED_'), '', $name));
713
+	}
714
+
715
+
716
+	/**
717
+	 *    _set_config_class
718
+	 * ensures that a config class is set, either from a passed config class or one generated from the config name
719
+	 *
720
+	 * @access    private
721
+	 * @param    string $config_class
722
+	 * @param    string $name
723
+	 * @return    string
724
+	 */
725
+	private function _set_config_class($config_class = '', $name = '')
726
+	{
727
+		return ! empty($config_class)
728
+			? $config_class
729
+			: str_replace(' ', '_', ucwords(str_replace('_', ' ', $name))) . '_Config';
730
+	}
731
+
732
+
733
+	/**
734
+	 *    set_config
735
+	 *
736
+	 * @access    protected
737
+	 * @param    string         $section
738
+	 * @param    string         $name
739
+	 * @param    string         $config_class
740
+	 * @param    EE_Config_Base $config_obj
741
+	 * @return    EE_Config_Base
742
+	 */
743
+	public function set_config($section = '', $name = '', $config_class = '', EE_Config_Base $config_obj = null)
744
+	{
745
+		// ensure config class is set to something
746
+		$config_class = $this->_set_config_class($config_class, $name);
747
+		// run tests 1-4, 6, and 7 to verify all config params are set and valid
748
+		if (! $this->_verify_config_params($section, $name, $config_class, null, array(1, 2, 3, 4, 5, 6))) {
749
+			return null;
750
+		}
751
+		$config_option_name = $this->_generate_config_option_name($section, $name);
752
+		// if the config option name hasn't been added yet to the list of option names we're tracking, then do so now
753
+		if (! isset($this->_addon_option_names[ $config_option_name ])) {
754
+			$this->_addon_option_names[ $config_option_name ] = $config_class;
755
+			$this->update_addon_option_names();
756
+		}
757
+		// verify the incoming config object but suppress errors
758
+		if (! $this->_verify_config_params($section, $name, $config_class, $config_obj, array(9), false)) {
759
+			$config_obj = new $config_class();
760
+		}
761
+		if (get_option($config_option_name)) {
762
+			EE_Config::log($config_option_name);
763
+			update_option($config_option_name, $config_obj);
764
+			$this->{$section}->{$name} = $config_obj;
765
+			return $this->{$section}->{$name};
766
+		} else {
767
+			// create a wp-option for this config
768
+			if (add_option($config_option_name, $config_obj, '', 'no')) {
769
+				$this->{$section}->{$name} = maybe_unserialize($config_obj);
770
+				return $this->{$section}->{$name};
771
+			} else {
772
+				EE_Error::add_error(
773
+					sprintf(esc_html__('The "%s" could not be saved to the database.', 'event_espresso'), $config_class),
774
+					__FILE__,
775
+					__FUNCTION__,
776
+					__LINE__
777
+				);
778
+				return null;
779
+			}
780
+		}
781
+	}
782
+
783
+
784
+	/**
785
+	 *    update_config
786
+	 * Important: the config object must ALREADY be set, otherwise this will produce an error.
787
+	 *
788
+	 * @access    public
789
+	 * @param    string                $section
790
+	 * @param    string                $name
791
+	 * @param    EE_Config_Base|string $config_obj
792
+	 * @param    bool                  $throw_errors
793
+	 * @return    bool
794
+	 */
795
+	public function update_config($section = '', $name = '', $config_obj = '', $throw_errors = true)
796
+	{
797
+		// don't allow config updates during WP heartbeats
798
+		/** @var RequestInterface $request */
799
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
800
+		if ($request->isWordPressHeartbeat()) {
801
+			return false;
802
+		}
803
+		$config_obj = maybe_unserialize($config_obj);
804
+		// get class name of the incoming object
805
+		$config_class = get_class($config_obj);
806
+		// run tests 1-5 and 9 to verify config
807
+		if (
808
+			! $this->_verify_config_params(
809
+				$section,
810
+				$name,
811
+				$config_class,
812
+				$config_obj,
813
+				array(1, 2, 3, 4, 7, 9)
814
+			)
815
+		) {
816
+			return false;
817
+		}
818
+		$config_option_name = $this->_generate_config_option_name($section, $name);
819
+		// check if config object has been added to db by seeing if config option name is in $this->_addon_option_names array
820
+		if (! isset($this->_addon_option_names[ $config_option_name ])) {
821
+			// save new config to db
822
+			if ($this->set_config($section, $name, $config_class, $config_obj)) {
823
+				return true;
824
+			}
825
+		} else {
826
+			// first check if the record already exists
827
+			$existing_config = get_option($config_option_name);
828
+			$config_obj = serialize($config_obj);
829
+			// just return if db record is already up to date (NOT type safe comparison)
830
+			if ($existing_config == $config_obj) {
831
+				$this->{$section}->{$name} = $config_obj;
832
+				return true;
833
+			} elseif (update_option($config_option_name, $config_obj)) {
834
+				EE_Config::log($config_option_name);
835
+				// update wp-option for this config class
836
+				$this->{$section}->{$name} = $config_obj;
837
+				return true;
838
+			} elseif ($throw_errors) {
839
+				EE_Error::add_error(
840
+					sprintf(
841
+						esc_html__(
842
+							'The "%1$s" object stored at"%2$s" was not successfully updated in the database.',
843
+							'event_espresso'
844
+						),
845
+						$config_class,
846
+						'EE_Config->' . $section . '->' . $name
847
+					),
848
+					__FILE__,
849
+					__FUNCTION__,
850
+					__LINE__
851
+				);
852
+			}
853
+		}
854
+		return false;
855
+	}
856
+
857
+
858
+	/**
859
+	 *    get_config
860
+	 *
861
+	 * @access    public
862
+	 * @param    string $section
863
+	 * @param    string $name
864
+	 * @param    string $config_class
865
+	 * @return    mixed EE_Config_Base | NULL
866
+	 */
867
+	public function get_config($section = '', $name = '', $config_class = '')
868
+	{
869
+		// ensure config class is set to something
870
+		$config_class = $this->_set_config_class($config_class, $name);
871
+		// run tests 1-4, 6 and 7 to verify that all params have been set
872
+		if (! $this->_verify_config_params($section, $name, $config_class, null, array(1, 2, 3, 4, 5, 6))) {
873
+			return null;
874
+		}
875
+		// now test if the requested config object exists, but suppress errors
876
+		if ($this->_verify_config_params($section, $name, $config_class, null, array(7, 8), false)) {
877
+			// config already exists, so pass it back
878
+			return $this->{$section}->{$name};
879
+		}
880
+		// load config option from db if it exists
881
+		$config_obj = $this->get_config_option($this->_generate_config_option_name($section, $name));
882
+		// verify the newly retrieved config object, but suppress errors
883
+		if ($this->_verify_config_params($section, $name, $config_class, $config_obj, array(9), false)) {
884
+			// config is good, so set it and pass it back
885
+			$this->{$section}->{$name} = $config_obj;
886
+			return $this->{$section}->{$name};
887
+		}
888
+		// oops! $config_obj is not already set and does not exist in the db, so create a new one
889
+		$config_obj = $this->set_config($section, $name, $config_class);
890
+		// verify the newly created config object
891
+		if ($this->_verify_config_params($section, $name, $config_class, $config_obj, array(9))) {
892
+			return $this->{$section}->{$name};
893
+		} else {
894
+			EE_Error::add_error(
895
+				sprintf(esc_html__('The "%s" could not be retrieved from the database.', 'event_espresso'), $config_class),
896
+				__FILE__,
897
+				__FUNCTION__,
898
+				__LINE__
899
+			);
900
+		}
901
+		return null;
902
+	}
903
+
904
+
905
+	/**
906
+	 *    get_config_option
907
+	 *
908
+	 * @access    public
909
+	 * @param    string $config_option_name
910
+	 * @return    mixed EE_Config_Base | FALSE
911
+	 */
912
+	public function get_config_option($config_option_name = '')
913
+	{
914
+		// retrieve the wp-option for this config class.
915
+		$config_option = maybe_unserialize(get_option($config_option_name, array()));
916
+		if (empty($config_option)) {
917
+			EE_Config::log($config_option_name . '-NOT-FOUND');
918
+		}
919
+		return $config_option;
920
+	}
921
+
922
+
923
+	/**
924
+	 * log
925
+	 *
926
+	 * @param string $config_option_name
927
+	 */
928
+	public static function log($config_option_name = '')
929
+	{
930
+		if (EE_Config::logging_enabled() && ! empty($config_option_name)) {
931
+			$config_log = get_option(EE_Config::LOG_NAME, array());
932
+			/** @var RequestParams $request */
933
+			$request = LoaderFactory::getLoader()->getShared(RequestParams::class);
934
+			$config_log[ (string) microtime(true) ] = array(
935
+				'config_name' => $config_option_name,
936
+				'request'     => $request->requestParams(),
937
+			);
938
+			update_option(EE_Config::LOG_NAME, $config_log);
939
+		}
940
+	}
941
+
942
+
943
+	/**
944
+	 * trim_log
945
+	 * reduces the size of the config log to the length specified by EE_Config::LOG_LENGTH
946
+	 */
947
+	public static function trim_log()
948
+	{
949
+		if (! EE_Config::logging_enabled()) {
950
+			return;
951
+		}
952
+		$config_log = maybe_unserialize(get_option(EE_Config::LOG_NAME, array()));
953
+		$log_length = count($config_log);
954
+		if ($log_length > EE_Config::LOG_LENGTH) {
955
+			ksort($config_log);
956
+			$config_log = array_slice($config_log, $log_length - EE_Config::LOG_LENGTH, null, true);
957
+			update_option(EE_Config::LOG_NAME, $config_log);
958
+		}
959
+	}
960
+
961
+
962
+	/**
963
+	 *    get_page_for_posts
964
+	 *    if the wp-option "show_on_front" is set to "page", then this is the post_name for the post set in the
965
+	 *    wp-option "page_for_posts", or "posts" if no page is selected
966
+	 *
967
+	 * @access    public
968
+	 * @return    string
969
+	 */
970
+	public static function get_page_for_posts()
971
+	{
972
+		$page_for_posts = get_option('page_for_posts');
973
+		if (! $page_for_posts) {
974
+			return 'posts';
975
+		}
976
+		global $wpdb;
977
+		$SQL = "SELECT post_name from $wpdb->posts WHERE post_type='posts' OR post_type='page' AND post_status='publish' AND ID=%d";
978
+		return $wpdb->get_var($wpdb->prepare($SQL, $page_for_posts));
979
+	}
980
+
981
+
982
+	/**
983
+	 *    register_shortcodes_and_modules.
984
+	 *    At this point, it's too early to tell if we're maintenance mode or not.
985
+	 *    In fact, this is where we give modules a chance to let core know they exist
986
+	 *    so they can help trigger maintenance mode if it's needed
987
+	 *
988
+	 * @access    public
989
+	 * @return    void
990
+	 */
991
+	public function register_shortcodes_and_modules()
992
+	{
993
+		// allow modules to set hooks for the rest of the system
994
+		EE_Registry::instance()->modules = $this->_register_modules();
995
+	}
996
+
997
+
998
+	/**
999
+	 *    initialize_shortcodes_and_modules
1000
+	 *    meaning they can start adding their hooks to get stuff done
1001
+	 *
1002
+	 * @access    public
1003
+	 * @return    void
1004
+	 */
1005
+	public function initialize_shortcodes_and_modules()
1006
+	{
1007
+		// allow modules to set hooks for the rest of the system
1008
+		$this->_initialize_modules();
1009
+	}
1010
+
1011
+
1012
+	/**
1013
+	 *    widgets_init
1014
+	 *
1015
+	 * @access private
1016
+	 * @return void
1017
+	 */
1018
+	public function widgets_init()
1019
+	{
1020
+		// only init widgets on admin pages when not in complete maintenance, and
1021
+		// on frontend when not in any maintenance mode
1022
+		if (
1023
+			! EE_Maintenance_Mode::instance()->level()
1024
+			|| (
1025
+				is_admin()
1026
+				&& EE_Maintenance_Mode::instance()->level() !== EE_Maintenance_Mode::level_2_complete_maintenance
1027
+			)
1028
+		) {
1029
+			// grab list of installed widgets
1030
+			$widgets_to_register = glob(EE_WIDGETS . '*', GLOB_ONLYDIR);
1031
+			// filter list of modules to register
1032
+			$widgets_to_register = apply_filters(
1033
+				'FHEE__EE_Config__register_widgets__widgets_to_register',
1034
+				$widgets_to_register
1035
+			);
1036
+			if (! empty($widgets_to_register)) {
1037
+				// cycle thru widget folders
1038
+				foreach ($widgets_to_register as $widget_path) {
1039
+					// add to list of installed widget modules
1040
+					EE_Config::register_ee_widget($widget_path);
1041
+				}
1042
+			}
1043
+			// filter list of installed modules
1044
+			EE_Registry::instance()->widgets = apply_filters(
1045
+				'FHEE__EE_Config__register_widgets__installed_widgets',
1046
+				EE_Registry::instance()->widgets
1047
+			);
1048
+		}
1049
+	}
1050
+
1051
+
1052
+	/**
1053
+	 *    register_ee_widget - makes core aware of this widget
1054
+	 *
1055
+	 * @access    public
1056
+	 * @param    string $widget_path - full path up to and including widget folder
1057
+	 * @return    void
1058
+	 */
1059
+	public static function register_ee_widget($widget_path = null)
1060
+	{
1061
+		do_action('AHEE__EE_Config__register_widget__begin', $widget_path);
1062
+		$widget_ext = '.widget.php';
1063
+		// make all separators match
1064
+		$widget_path = rtrim(str_replace('\\', DS, $widget_path), DS);
1065
+		// does the file path INCLUDE the actual file name as part of the path ?
1066
+		if (strpos($widget_path, $widget_ext) !== false) {
1067
+			// grab and shortcode file name from directory name and break apart at dots
1068
+			$file_name = explode('.', basename($widget_path));
1069
+			// take first segment from file name pieces and remove class prefix if it exists
1070
+			$widget = strpos($file_name[0], 'EEW_') === 0 ? substr($file_name[0], 4) : $file_name[0];
1071
+			// sanitize shortcode directory name
1072
+			$widget = sanitize_key($widget);
1073
+			// now we need to rebuild the shortcode path
1074
+			$widget_path = explode('/', $widget_path);
1075
+			// remove last segment
1076
+			array_pop($widget_path);
1077
+			// glue it back together
1078
+			$widget_path = implode(DS, $widget_path);
1079
+		} else {
1080
+			// grab and sanitize widget directory name
1081
+			$widget = sanitize_key(basename($widget_path));
1082
+		}
1083
+		// create classname from widget directory name
1084
+		$widget = str_replace(' ', '_', ucwords(str_replace('_', ' ', $widget)));
1085
+		// add class prefix
1086
+		$widget_class = 'EEW_' . $widget;
1087
+		// does the widget exist ?
1088
+		if (! is_readable($widget_path . '/' . $widget_class . $widget_ext)) {
1089
+			$msg = sprintf(
1090
+				esc_html__(
1091
+					'The requested %s widget file could not be found or is not readable due to file permissions. Please ensure the following path is correct: %s',
1092
+					'event_espresso'
1093
+				),
1094
+				$widget_class,
1095
+				$widget_path . '/' . $widget_class . $widget_ext
1096
+			);
1097
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1098
+			return;
1099
+		}
1100
+		// load the widget class file
1101
+		require_once($widget_path . '/' . $widget_class . $widget_ext);
1102
+		// verify that class exists
1103
+		if (! class_exists($widget_class)) {
1104
+			$msg = sprintf(esc_html__('The requested %s widget class does not exist.', 'event_espresso'), $widget_class);
1105
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1106
+			return;
1107
+		}
1108
+		register_widget($widget_class);
1109
+		// add to array of registered widgets
1110
+		EE_Registry::instance()->widgets->{$widget_class} = $widget_path . '/' . $widget_class . $widget_ext;
1111
+	}
1112
+
1113
+
1114
+	/**
1115
+	 *        _register_modules
1116
+	 *
1117
+	 * @access private
1118
+	 * @return array
1119
+	 */
1120
+	private function _register_modules()
1121
+	{
1122
+		// grab list of installed modules
1123
+		$modules_to_register = glob(EE_MODULES . '*', GLOB_ONLYDIR);
1124
+		// filter list of modules to register
1125
+		$modules_to_register = apply_filters(
1126
+			'FHEE__EE_Config__register_modules__modules_to_register',
1127
+			$modules_to_register
1128
+		);
1129
+		if (! empty($modules_to_register)) {
1130
+			// loop through folders
1131
+			foreach ($modules_to_register as $module_path) {
1132
+				/**TEMPORARILY EXCLUDE gateways from modules for time being**/
1133
+				if (
1134
+					$module_path !== EE_MODULES . 'zzz-copy-this-module-template'
1135
+					&& $module_path !== EE_MODULES . 'gateways'
1136
+				) {
1137
+					// add to list of installed modules
1138
+					EE_Config::register_module($module_path);
1139
+				}
1140
+			}
1141
+		}
1142
+		// filter list of installed modules
1143
+		return apply_filters(
1144
+			'FHEE__EE_Config___register_modules__installed_modules',
1145
+			EE_Registry::instance()->modules
1146
+		);
1147
+	}
1148
+
1149
+
1150
+	/**
1151
+	 *    register_module - makes core aware of this module
1152
+	 *
1153
+	 * @access    public
1154
+	 * @param    string $module_path - full path up to and including module folder
1155
+	 * @return    bool
1156
+	 */
1157
+	public static function register_module($module_path = null)
1158
+	{
1159
+		do_action('AHEE__EE_Config__register_module__begin', $module_path);
1160
+		$module_ext = '.module.php';
1161
+		// make all separators match
1162
+		$module_path = str_replace(array('\\', '/'), '/', $module_path);
1163
+		// does the file path INCLUDE the actual file name as part of the path ?
1164
+		if (strpos($module_path, $module_ext) !== false) {
1165
+			// grab and shortcode file name from directory name and break apart at dots
1166
+			$module_file = explode('.', basename($module_path));
1167
+			// now we need to rebuild the shortcode path
1168
+			$module_path = explode('/', $module_path);
1169
+			// remove last segment
1170
+			array_pop($module_path);
1171
+			// glue it back together
1172
+			$module_path = implode('/', $module_path) . '/';
1173
+			// take first segment from file name pieces and sanitize it
1174
+			$module = preg_replace('/[^a-zA-Z0-9_\-]/', '', $module_file[0]);
1175
+			// ensure class prefix is added
1176
+			$module_class = strpos($module, 'EED_') !== 0 ? 'EED_' . $module : $module;
1177
+		} else {
1178
+			// we need to generate the filename based off of the folder name
1179
+			// grab and sanitize module name
1180
+			$module = strtolower(basename($module_path));
1181
+			$module = preg_replace('/[^a-z0-9_\-]/', '', $module);
1182
+			// like trailingslashit()
1183
+			$module_path = rtrim($module_path, '/') . '/';
1184
+			// create classname from module directory name
1185
+			$module = str_replace(' ', '_', ucwords(str_replace('_', ' ', $module)));
1186
+			// add class prefix
1187
+			$module_class = 'EED_' . $module;
1188
+		}
1189
+		// does the module exist ?
1190
+		if (! is_readable($module_path . '/' . $module_class . $module_ext)) {
1191
+			$msg = sprintf(
1192
+				esc_html__(
1193
+					'The requested %s module file could not be found or is not readable due to file permissions.',
1194
+					'event_espresso'
1195
+				),
1196
+				$module
1197
+			);
1198
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1199
+			return false;
1200
+		}
1201
+		// load the module class file
1202
+		require_once($module_path . $module_class . $module_ext);
1203
+		// verify that class exists
1204
+		if (! class_exists($module_class)) {
1205
+			$msg = sprintf(esc_html__('The requested %s module class does not exist.', 'event_espresso'), $module_class);
1206
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1207
+			return false;
1208
+		}
1209
+		// add to array of registered modules
1210
+		EE_Registry::instance()->modules->{$module_class} = $module_path . $module_class . $module_ext;
1211
+		do_action(
1212
+			'AHEE__EE_Config__register_module__complete',
1213
+			$module_class,
1214
+			EE_Registry::instance()->modules->{$module_class}
1215
+		);
1216
+		return true;
1217
+	}
1218
+
1219
+
1220
+	/**
1221
+	 *    _initialize_modules
1222
+	 *    allow modules to set hooks for the rest of the system
1223
+	 *
1224
+	 * @access private
1225
+	 * @return void
1226
+	 */
1227
+	private function _initialize_modules()
1228
+	{
1229
+		// cycle thru shortcode folders
1230
+		foreach (EE_Registry::instance()->modules as $module_class => $module_path) {
1231
+			// fire the shortcode class's set_hooks methods in case it needs to hook into other parts of the system
1232
+			// which set hooks ?
1233
+			if (is_admin()) {
1234
+				// fire immediately
1235
+				call_user_func(array($module_class, 'set_hooks_admin'));
1236
+			} else {
1237
+				// delay until other systems are online
1238
+				add_action(
1239
+					'AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons',
1240
+					array($module_class, 'set_hooks')
1241
+				);
1242
+			}
1243
+		}
1244
+	}
1245
+
1246
+
1247
+	/**
1248
+	 *    register_route - adds module method routes to route_map
1249
+	 *
1250
+	 * @access    public
1251
+	 * @param    string $route       - "pretty" public alias for module method
1252
+	 * @param    string $module      - module name (classname without EED_ prefix)
1253
+	 * @param    string $method_name - the actual module method to be routed to
1254
+	 * @param    string $key         - url param key indicating a route is being called
1255
+	 * @return    bool
1256
+	 */
1257
+	public static function register_route($route = null, $module = null, $method_name = null, $key = 'ee')
1258
+	{
1259
+		do_action('AHEE__EE_Config__register_route__begin', $route, $module, $method_name);
1260
+		$module = str_replace('EED_', '', $module);
1261
+		$module_class = 'EED_' . $module;
1262
+		if (! isset(EE_Registry::instance()->modules->{$module_class})) {
1263
+			$msg = sprintf(esc_html__('The module %s has not been registered.', 'event_espresso'), $module);
1264
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1265
+			return false;
1266
+		}
1267
+		if (empty($route)) {
1268
+			$msg = sprintf(esc_html__('No route has been supplied.', 'event_espresso'), $route);
1269
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1270
+			return false;
1271
+		}
1272
+		if (! method_exists('EED_' . $module, $method_name)) {
1273
+			$msg = sprintf(
1274
+				esc_html__('A valid class method for the %s route has not been supplied.', 'event_espresso'),
1275
+				$route
1276
+			);
1277
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1278
+			return false;
1279
+		}
1280
+		EE_Config::$_module_route_map[ (string) $key ][ (string) $route ] = array('EED_' . $module, $method_name);
1281
+		return true;
1282
+	}
1283
+
1284
+
1285
+	/**
1286
+	 *    get_route - get module method route
1287
+	 *
1288
+	 * @access    public
1289
+	 * @param    string $route - "pretty" public alias for module method
1290
+	 * @param    string $key   - url param key indicating a route is being called
1291
+	 * @return    string
1292
+	 */
1293
+	public static function get_route($route = null, $key = 'ee')
1294
+	{
1295
+		do_action('AHEE__EE_Config__get_route__begin', $route);
1296
+		$route = (string) apply_filters('FHEE__EE_Config__get_route', $route);
1297
+		if (isset(EE_Config::$_module_route_map[ $key ][ $route ])) {
1298
+			return EE_Config::$_module_route_map[ $key ][ $route ];
1299
+		}
1300
+		return null;
1301
+	}
1302
+
1303
+
1304
+	/**
1305
+	 *    get_routes - get ALL module method routes
1306
+	 *
1307
+	 * @access    public
1308
+	 * @return    array
1309
+	 */
1310
+	public static function get_routes()
1311
+	{
1312
+		return EE_Config::$_module_route_map;
1313
+	}
1314
+
1315
+
1316
+	/**
1317
+	 *    register_forward - allows modules to forward request to another module for further processing
1318
+	 *
1319
+	 * @access    public
1320
+	 * @param    string       $route   - "pretty" public alias for module method
1321
+	 * @param    integer      $status  - integer value corresponding  to status constant strings set in module parent
1322
+	 *                                 class, allows different forwards to be served based on status
1323
+	 * @param    array|string $forward - function name or array( class, method )
1324
+	 * @param    string       $key     - url param key indicating a route is being called
1325
+	 * @return    bool
1326
+	 */
1327
+	public static function register_forward($route = null, $status = 0, $forward = null, $key = 'ee')
1328
+	{
1329
+		do_action('AHEE__EE_Config__register_forward', $route, $status, $forward);
1330
+		if (! isset(EE_Config::$_module_route_map[ $key ][ $route ]) || empty($route)) {
1331
+			$msg = sprintf(
1332
+				esc_html__('The module route %s for this forward has not been registered.', 'event_espresso'),
1333
+				$route
1334
+			);
1335
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1336
+			return false;
1337
+		}
1338
+		if (empty($forward)) {
1339
+			$msg = sprintf(esc_html__('No forwarding route has been supplied.', 'event_espresso'), $route);
1340
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1341
+			return false;
1342
+		}
1343
+		if (is_array($forward)) {
1344
+			if (! isset($forward[1])) {
1345
+				$msg = sprintf(
1346
+					esc_html__('A class method for the %s forwarding route has not been supplied.', 'event_espresso'),
1347
+					$route
1348
+				);
1349
+				EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1350
+				return false;
1351
+			}
1352
+			if (! method_exists($forward[0], $forward[1])) {
1353
+				$msg = sprintf(
1354
+					esc_html__('The class method %s for the %s forwarding route is in invalid.', 'event_espresso'),
1355
+					$forward[1],
1356
+					$route
1357
+				);
1358
+				EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1359
+				return false;
1360
+			}
1361
+		} elseif (! function_exists($forward)) {
1362
+			$msg = sprintf(
1363
+				esc_html__('The function %s for the %s forwarding route is in invalid.', 'event_espresso'),
1364
+				$forward,
1365
+				$route
1366
+			);
1367
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1368
+			return false;
1369
+		}
1370
+		EE_Config::$_module_forward_map[ $key ][ $route ][ absint($status) ] = $forward;
1371
+		return true;
1372
+	}
1373
+
1374
+
1375
+	/**
1376
+	 *    get_forward - get forwarding route
1377
+	 *
1378
+	 * @access    public
1379
+	 * @param    string  $route  - "pretty" public alias for module method
1380
+	 * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1381
+	 *                           allows different forwards to be served based on status
1382
+	 * @param    string  $key    - url param key indicating a route is being called
1383
+	 * @return    string
1384
+	 */
1385
+	public static function get_forward($route = null, $status = 0, $key = 'ee')
1386
+	{
1387
+		do_action('AHEE__EE_Config__get_forward__begin', $route, $status);
1388
+		if (isset(EE_Config::$_module_forward_map[ $key ][ $route ][ $status ])) {
1389
+			return apply_filters(
1390
+				'FHEE__EE_Config__get_forward',
1391
+				EE_Config::$_module_forward_map[ $key ][ $route ][ $status ],
1392
+				$route,
1393
+				$status
1394
+			);
1395
+		}
1396
+		return null;
1397
+	}
1398
+
1399
+
1400
+	/**
1401
+	 *    register_forward - allows modules to specify different view templates for different method routes and status
1402
+	 *    results
1403
+	 *
1404
+	 * @access    public
1405
+	 * @param    string  $route  - "pretty" public alias for module method
1406
+	 * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1407
+	 *                           allows different views to be served based on status
1408
+	 * @param    string  $view
1409
+	 * @param    string  $key    - url param key indicating a route is being called
1410
+	 * @return    bool
1411
+	 */
1412
+	public static function register_view($route = null, $status = 0, $view = null, $key = 'ee')
1413
+	{
1414
+		do_action('AHEE__EE_Config__register_view__begin', $route, $status, $view);
1415
+		if (! isset(EE_Config::$_module_route_map[ $key ][ $route ]) || empty($route)) {
1416
+			$msg = sprintf(
1417
+				esc_html__('The module route %s for this view has not been registered.', 'event_espresso'),
1418
+				$route
1419
+			);
1420
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1421
+			return false;
1422
+		}
1423
+		if (! is_readable($view)) {
1424
+			$msg = sprintf(
1425
+				esc_html__(
1426
+					'The %s view file could not be found or is not readable due to file permissions.',
1427
+					'event_espresso'
1428
+				),
1429
+				$view
1430
+			);
1431
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1432
+			return false;
1433
+		}
1434
+		EE_Config::$_module_view_map[ $key ][ $route ][ absint($status) ] = $view;
1435
+		return true;
1436
+	}
1437
+
1438
+
1439
+	/**
1440
+	 *    get_view - get view for route and status
1441
+	 *
1442
+	 * @access    public
1443
+	 * @param    string  $route  - "pretty" public alias for module method
1444
+	 * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1445
+	 *                           allows different views to be served based on status
1446
+	 * @param    string  $key    - url param key indicating a route is being called
1447
+	 * @return    string
1448
+	 */
1449
+	public static function get_view($route = null, $status = 0, $key = 'ee')
1450
+	{
1451
+		do_action('AHEE__EE_Config__get_view__begin', $route, $status);
1452
+		if (isset(EE_Config::$_module_view_map[ $key ][ $route ][ $status ])) {
1453
+			return apply_filters(
1454
+				'FHEE__EE_Config__get_view',
1455
+				EE_Config::$_module_view_map[ $key ][ $route ][ $status ],
1456
+				$route,
1457
+				$status
1458
+			);
1459
+		}
1460
+		return null;
1461
+	}
1462
+
1463
+
1464
+	public function update_addon_option_names()
1465
+	{
1466
+		update_option(EE_Config::ADDON_OPTION_NAMES, $this->_addon_option_names);
1467
+	}
1468
+
1469
+
1470
+	public function shutdown()
1471
+	{
1472
+		$this->update_addon_option_names();
1473
+	}
1474
+
1475
+
1476
+	/**
1477
+	 * @return LegacyShortcodesManager
1478
+	 */
1479
+	public static function getLegacyShortcodesManager()
1480
+	{
1481
+		if (! EE_Config::instance()->legacy_shortcodes_manager instanceof LegacyShortcodesManager) {
1482
+			EE_Config::instance()->legacy_shortcodes_manager = LoaderFactory::getLoader()->getShared(
1483
+				LegacyShortcodesManager::class
1484
+			);
1485
+		}
1486
+		return EE_Config::instance()->legacy_shortcodes_manager;
1487
+	}
1488
+
1489
+
1490
+	/**
1491
+	 * register_shortcode - makes core aware of this shortcode
1492
+	 *
1493
+	 * @deprecated 4.9.26
1494
+	 * @param    string $shortcode_path - full path up to and including shortcode folder
1495
+	 * @return    bool
1496
+	 */
1497
+	public static function register_shortcode($shortcode_path = null)
1498
+	{
1499
+		EE_Error::doing_it_wrong(
1500
+			__METHOD__,
1501
+			esc_html__(
1502
+				'Usage is deprecated. Use \EventEspresso\core\services\shortcodes\LegacyShortcodesManager::registerShortcode() as direct replacement, or better yet, please see the new \EventEspresso\core\services\shortcodes\ShortcodesManager class.',
1503
+				'event_espresso'
1504
+			),
1505
+			'4.9.26'
1506
+		);
1507
+		return EE_Config::instance()->getLegacyShortcodesManager()->registerShortcode($shortcode_path);
1508
+	}
1509
+}
2328 1510
 
2329
-    /**
2330
-     * array of form names protected by ReCaptcha
2331
-     *
2332
-     * @var array $recaptcha_protected_forms
2333
-     */
2334
-    public $recaptcha_protected_forms;
1511
+/**
1512
+ * Base class used for config classes. These classes should generally not have
1513
+ * magic functions in use, except we'll allow them to magically set and get stuff...
1514
+ * basically, they should just be well-defined stdClasses
1515
+ */
1516
+class EE_Config_Base
1517
+{
1518
+	/**
1519
+	 * Utility function for escaping the value of a property and returning.
1520
+	 *
1521
+	 * @param string $property property name (checks to see if exists).
1522
+	 * @return mixed if a detected type found return the escaped value, otherwise just the raw value is returned.
1523
+	 * @throws EE_Error
1524
+	 */
1525
+	public function get_pretty($property)
1526
+	{
1527
+		if (! property_exists($this, $property)) {
1528
+			throw new EE_Error(
1529
+				sprintf(
1530
+					esc_html__(
1531
+						'%1$s::get_pretty() has been called with the property %2$s which does not exist on the %1$s config class.',
1532
+						'event_espresso'
1533
+					),
1534
+					get_class($this),
1535
+					$property
1536
+				)
1537
+			);
1538
+		}
1539
+		// just handling escaping of strings for now.
1540
+		if (is_string($this->{$property})) {
1541
+			return stripslashes($this->{$property});
1542
+		}
1543
+		return $this->{$property};
1544
+	}
1545
+
1546
+
1547
+	public function populate()
1548
+	{
1549
+		// grab defaults via a new instance of this class.
1550
+		$class_name = get_class($this);
1551
+		$defaults = new $class_name();
1552
+		// loop through the properties for this class and see if they are set.  If they are NOT, then grab the
1553
+		// default from our $defaults object.
1554
+		foreach (get_object_vars($defaults) as $property => $value) {
1555
+			if ($this->{$property} === null) {
1556
+				$this->{$property} = $value;
1557
+			}
1558
+		}
1559
+		// cleanup
1560
+		unset($defaults);
1561
+	}
1562
+
1563
+
1564
+	/**
1565
+	 *        __isset
1566
+	 *
1567
+	 * @param $a
1568
+	 * @return bool
1569
+	 */
1570
+	public function __isset($a)
1571
+	{
1572
+		return false;
1573
+	}
1574
+
1575
+
1576
+	/**
1577
+	 *        __unset
1578
+	 *
1579
+	 * @param $a
1580
+	 * @return bool
1581
+	 */
1582
+	public function __unset($a)
1583
+	{
1584
+		return false;
1585
+	}
1586
+
1587
+
1588
+	/**
1589
+	 *        __clone
1590
+	 */
1591
+	public function __clone()
1592
+	{
1593
+	}
1594
+
1595
+
1596
+	/**
1597
+	 *        __wakeup
1598
+	 */
1599
+	public function __wakeup()
1600
+	{
1601
+	}
1602
+
1603
+
1604
+	/**
1605
+	 *        __destruct
1606
+	 */
1607
+	public function __destruct()
1608
+	{
1609
+	}
1610
+}
2335 1611
 
2336
-    /**
2337
-     * ReCaptcha width
2338
-     *
2339
-     * @var int $recaptcha_width
2340
-     * @deprecated
2341
-     */
2342
-    public $recaptcha_width;
1612
+/**
1613
+ * Class for defining what's in the EE_Config relating to registration settings
1614
+ */
1615
+class EE_Core_Config extends EE_Config_Base
1616
+{
1617
+	const OPTION_NAME_UXIP = 'ee_ueip_optin';
1618
+
1619
+
1620
+	public $current_blog_id;
1621
+
1622
+	public $ee_ueip_optin;
1623
+
1624
+	public $ee_ueip_has_notified;
1625
+
1626
+	/**
1627
+	 * Not to be confused with the 4 critical page variables (See
1628
+	 * get_critical_pages_array()), this is just an array of wp posts that have EE
1629
+	 * shortcodes in them. Keys are slugs, values are arrays with only 1 element: where the key is the shortcode
1630
+	 * in the page, and the value is the page's ID. The key 'posts' is basically a duplicate of this same array.
1631
+	 *
1632
+	 * @var array
1633
+	 */
1634
+	public $post_shortcodes;
1635
+
1636
+	public $module_route_map;
1637
+
1638
+	public $module_forward_map;
1639
+
1640
+	public $module_view_map;
1641
+
1642
+	/**
1643
+	 * The next 4 vars are the IDs of critical EE pages.
1644
+	 *
1645
+	 * @var int
1646
+	 */
1647
+	public $reg_page_id;
1648
+
1649
+	public $txn_page_id;
1650
+
1651
+	public $thank_you_page_id;
1652
+
1653
+	public $cancel_page_id;
1654
+
1655
+	/**
1656
+	 * The next 4 vars are the URLs of critical EE pages.
1657
+	 *
1658
+	 * @var int
1659
+	 */
1660
+	public $reg_page_url;
1661
+
1662
+	public $txn_page_url;
1663
+
1664
+	public $thank_you_page_url;
1665
+
1666
+	public $cancel_page_url;
1667
+
1668
+	/**
1669
+	 * The next vars relate to the custom slugs for EE CPT routes
1670
+	 */
1671
+	public $event_cpt_slug;
1672
+
1673
+	/**
1674
+	 * This caches the _ee_ueip_option in case this config is reset in the same
1675
+	 * request across blog switches in a multisite context.
1676
+	 * Avoids extra queries to the db for this option.
1677
+	 *
1678
+	 * @var bool
1679
+	 */
1680
+	public static $ee_ueip_option;
1681
+
1682
+
1683
+	/**
1684
+	 *    class constructor
1685
+	 *
1686
+	 * @access    public
1687
+	 */
1688
+	public function __construct()
1689
+	{
1690
+		// set default organization settings
1691
+		$this->current_blog_id = get_current_blog_id();
1692
+		$this->current_blog_id = $this->current_blog_id === null ? 1 : $this->current_blog_id;
1693
+		$this->ee_ueip_optin = $this->_get_main_ee_ueip_optin();
1694
+		$this->ee_ueip_has_notified = is_main_site() ? get_option('ee_ueip_has_notified', false) : true;
1695
+		$this->post_shortcodes = array();
1696
+		$this->module_route_map = array();
1697
+		$this->module_forward_map = array();
1698
+		$this->module_view_map = array();
1699
+		// critical EE page IDs
1700
+		$this->reg_page_id = 0;
1701
+		$this->txn_page_id = 0;
1702
+		$this->thank_you_page_id = 0;
1703
+		$this->cancel_page_id = 0;
1704
+		// critical EE page URLs
1705
+		$this->reg_page_url = '';
1706
+		$this->txn_page_url = '';
1707
+		$this->thank_you_page_url = '';
1708
+		$this->cancel_page_url = '';
1709
+		// cpt slugs
1710
+		$this->event_cpt_slug = esc_html__('events', 'event_espresso');
1711
+		// ueip constant check
1712
+		if (defined('EE_DISABLE_UXIP') && EE_DISABLE_UXIP) {
1713
+			$this->ee_ueip_optin = false;
1714
+			$this->ee_ueip_has_notified = true;
1715
+		}
1716
+	}
1717
+
1718
+
1719
+	/**
1720
+	 * @return array
1721
+	 */
1722
+	public function get_critical_pages_array()
1723
+	{
1724
+		return array(
1725
+			$this->reg_page_id,
1726
+			$this->txn_page_id,
1727
+			$this->thank_you_page_id,
1728
+			$this->cancel_page_id,
1729
+		);
1730
+	}
1731
+
1732
+
1733
+	/**
1734
+	 * @return array
1735
+	 */
1736
+	public function get_critical_pages_shortcodes_array()
1737
+	{
1738
+		return array(
1739
+			$this->reg_page_id       => 'ESPRESSO_CHECKOUT',
1740
+			$this->txn_page_id       => 'ESPRESSO_TXN_PAGE',
1741
+			$this->thank_you_page_id => 'ESPRESSO_THANK_YOU',
1742
+			$this->cancel_page_id    => 'ESPRESSO_CANCELLED',
1743
+		);
1744
+	}
1745
+
1746
+
1747
+	/**
1748
+	 *  gets/returns URL for EE reg_page
1749
+	 *
1750
+	 * @access    public
1751
+	 * @return    string
1752
+	 */
1753
+	public function reg_page_url()
1754
+	{
1755
+		if (! $this->reg_page_url) {
1756
+			$this->reg_page_url = add_query_arg(
1757
+				array('uts' => time()),
1758
+				get_permalink($this->reg_page_id)
1759
+			) . '#checkout';
1760
+		}
1761
+		return $this->reg_page_url;
1762
+	}
1763
+
1764
+
1765
+	/**
1766
+	 *  gets/returns URL for EE txn_page
1767
+	 *
1768
+	 * @param array $query_args like what gets passed to
1769
+	 *                          add_query_arg() as the first argument
1770
+	 * @access    public
1771
+	 * @return    string
1772
+	 */
1773
+	public function txn_page_url($query_args = array())
1774
+	{
1775
+		if (! $this->txn_page_url) {
1776
+			$this->txn_page_url = get_permalink($this->txn_page_id);
1777
+		}
1778
+		if ($query_args) {
1779
+			return add_query_arg($query_args, $this->txn_page_url);
1780
+		} else {
1781
+			return $this->txn_page_url;
1782
+		}
1783
+	}
1784
+
1785
+
1786
+	/**
1787
+	 *  gets/returns URL for EE thank_you_page
1788
+	 *
1789
+	 * @param array $query_args like what gets passed to
1790
+	 *                          add_query_arg() as the first argument
1791
+	 * @access    public
1792
+	 * @return    string
1793
+	 */
1794
+	public function thank_you_page_url($query_args = array())
1795
+	{
1796
+		if (! $this->thank_you_page_url) {
1797
+			$this->thank_you_page_url = get_permalink($this->thank_you_page_id);
1798
+		}
1799
+		if ($query_args) {
1800
+			return add_query_arg($query_args, $this->thank_you_page_url);
1801
+		} else {
1802
+			return $this->thank_you_page_url;
1803
+		}
1804
+	}
1805
+
1806
+
1807
+	/**
1808
+	 *  gets/returns URL for EE cancel_page
1809
+	 *
1810
+	 * @access    public
1811
+	 * @return    string
1812
+	 */
1813
+	public function cancel_page_url()
1814
+	{
1815
+		if (! $this->cancel_page_url) {
1816
+			$this->cancel_page_url = get_permalink($this->cancel_page_id);
1817
+		}
1818
+		return $this->cancel_page_url;
1819
+	}
1820
+
1821
+
1822
+	/**
1823
+	 * Resets all critical page urls to their original state.  Used primarily by the __sleep() magic method currently.
1824
+	 *
1825
+	 * @since 4.7.5
1826
+	 */
1827
+	protected function _reset_urls()
1828
+	{
1829
+		$this->reg_page_url = '';
1830
+		$this->txn_page_url = '';
1831
+		$this->cancel_page_url = '';
1832
+		$this->thank_you_page_url = '';
1833
+	}
1834
+
1835
+
1836
+	/**
1837
+	 * Used to return what the optin value is set for the EE User Experience Program.
1838
+	 * This accounts for multisite and this value being requested for a subsite.  In multisite, the value is set
1839
+	 * on the main site only.
1840
+	 *
1841
+	 * @return bool
1842
+	 */
1843
+	protected function _get_main_ee_ueip_optin()
1844
+	{
1845
+		// if this is the main site then we can just bypass our direct query.
1846
+		if (is_main_site()) {
1847
+			return get_option(self::OPTION_NAME_UXIP, false);
1848
+		}
1849
+		// is this already cached for this request?  If so use it.
1850
+		if (EE_Core_Config::$ee_ueip_option !== null) {
1851
+			return EE_Core_Config::$ee_ueip_option;
1852
+		}
1853
+		global $wpdb;
1854
+		$current_network_main_site = is_multisite() ? get_current_site() : null;
1855
+		$current_main_site_id = ! empty($current_network_main_site) ? $current_network_main_site->blog_id : 1;
1856
+		$option = self::OPTION_NAME_UXIP;
1857
+		// set correct table for query
1858
+		$table_name = $wpdb->get_blog_prefix($current_main_site_id) . 'options';
1859
+		// rather than getting blog option for the $current_main_site_id, we do a direct $wpdb query because
1860
+		// get_blog_option() does a switch_to_blog an that could cause infinite recursion because EE_Core_Config might be
1861
+		// re-constructed on the blog switch.  Note, we are still executing any core wp filters on this option retrieval.
1862
+		// this bit of code is basically a direct copy of get_option without any caching because we are NOT switched to the blog
1863
+		// for the purpose of caching.
1864
+		$pre = apply_filters('pre_option_' . $option, false, $option);
1865
+		if (false !== $pre) {
1866
+			EE_Core_Config::$ee_ueip_option = $pre;
1867
+			return EE_Core_Config::$ee_ueip_option;
1868
+		}
1869
+		$row = $wpdb->get_row(
1870
+			$wpdb->prepare(
1871
+				"SELECT option_value FROM $table_name WHERE option_name = %s LIMIT 1",
1872
+				$option
1873
+			)
1874
+		);
1875
+		if (is_object($row)) {
1876
+			$value = $row->option_value;
1877
+		} else { // option does not exist so use default.
1878
+			EE_Core_Config::$ee_ueip_option =  apply_filters('default_option_' . $option, false, $option);
1879
+			return EE_Core_Config::$ee_ueip_option;
1880
+		}
1881
+		EE_Core_Config::$ee_ueip_option = apply_filters('option_' . $option, maybe_unserialize($value), $option);
1882
+		return EE_Core_Config::$ee_ueip_option;
1883
+	}
1884
+
1885
+
1886
+	/**
1887
+	 * Utility function for escaping the value of a property and returning.
1888
+	 *
1889
+	 * @param string $property property name (checks to see if exists).
1890
+	 * @return mixed if a detected type found return the escaped value, otherwise just the raw value is returned.
1891
+	 * @throws EE_Error
1892
+	 */
1893
+	public function get_pretty($property)
1894
+	{
1895
+		if ($property === self::OPTION_NAME_UXIP) {
1896
+			return $this->ee_ueip_optin ? 'yes' : 'no';
1897
+		}
1898
+		return parent::get_pretty($property);
1899
+	}
1900
+
1901
+
1902
+	/**
1903
+	 * Currently used to ensure critical page urls have initial values saved to the db instead of any current set values
1904
+	 * on the object.
1905
+	 *
1906
+	 * @return array
1907
+	 */
1908
+	public function __sleep()
1909
+	{
1910
+		// reset all url properties
1911
+		$this->_reset_urls();
1912
+		// return what to save to db
1913
+		return array_keys(get_object_vars($this));
1914
+	}
1915
+}
2343 1916
 
2344
-    /**
2345
-     * Whether or not invalid attempts to directly access the registration checkout page should be tracked.
2346
-     *
2347
-     * @var boolean $track_invalid_checkout_access
2348
-     */
2349
-    protected $track_invalid_checkout_access = true;
1917
+/**
1918
+ * Config class for storing info on the Organization
1919
+ */
1920
+class EE_Organization_Config extends EE_Config_Base
1921
+{
1922
+	/**
1923
+	 * @var string $name
1924
+	 * eg EE4.1
1925
+	 */
1926
+	public $name;
1927
+
1928
+	/**
1929
+	 * @var string $address_1
1930
+	 * eg 123 Onna Road
1931
+	 */
1932
+	public $address_1 = '';
1933
+
1934
+	/**
1935
+	 * @var string $address_2
1936
+	 * eg PO Box 123
1937
+	 */
1938
+	public $address_2 = '';
1939
+
1940
+	/**
1941
+	 * @var string $city
1942
+	 * eg Inna City
1943
+	 */
1944
+	public $city = '';
1945
+
1946
+	/**
1947
+	 * @var int $STA_ID
1948
+	 * eg 4
1949
+	 */
1950
+	public $STA_ID = 0;
1951
+
1952
+	/**
1953
+	 * @var string $CNT_ISO
1954
+	 * eg US
1955
+	 */
1956
+	public $CNT_ISO = '';
1957
+
1958
+	/**
1959
+	 * @var string $zip
1960
+	 * eg 12345  or V1A 2B3
1961
+	 */
1962
+	public $zip = '';
1963
+
1964
+	/**
1965
+	 * @var string $email
1966
+	 * eg [email protected]
1967
+	 */
1968
+	public $email;
1969
+
1970
+	/**
1971
+	 * @var string $phone
1972
+	 * eg. 111-111-1111
1973
+	 */
1974
+	public $phone = '';
1975
+
1976
+	/**
1977
+	 * @var string $vat
1978
+	 * VAT/Tax Number
1979
+	 */
1980
+	public $vat = '';
1981
+
1982
+	/**
1983
+	 * @var string $logo_url
1984
+	 * eg http://www.somedomain.com/wp-content/uploads/kittehs.jpg
1985
+	 */
1986
+	public $logo_url = '';
1987
+
1988
+	/**
1989
+	 * The below are all various properties for holding links to organization social network profiles
1990
+	 *
1991
+	 * @var string
1992
+	 */
1993
+	/**
1994
+	 * facebook (facebook.com/profile.name)
1995
+	 *
1996
+	 * @var string
1997
+	 */
1998
+	public $facebook = '';
1999
+
2000
+	/**
2001
+	 * twitter (twitter.com/twitter_handle)
2002
+	 *
2003
+	 * @var string
2004
+	 */
2005
+	public $twitter = '';
2006
+
2007
+	/**
2008
+	 * linkedin (linkedin.com/in/profile_name)
2009
+	 *
2010
+	 * @var string
2011
+	 */
2012
+	public $linkedin = '';
2013
+
2014
+	/**
2015
+	 * pinterest (www.pinterest.com/profile_name)
2016
+	 *
2017
+	 * @var string
2018
+	 */
2019
+	public $pinterest = '';
2020
+
2021
+	/**
2022
+	 * google+ (google.com/+profileName)
2023
+	 *
2024
+	 * @var string
2025
+	 */
2026
+	public $google = '';
2027
+
2028
+	/**
2029
+	 * instagram (instagram.com/handle)
2030
+	 *
2031
+	 * @var string
2032
+	 */
2033
+	public $instagram = '';
2034
+
2035
+
2036
+	/**
2037
+	 *    class constructor
2038
+	 *
2039
+	 * @access    public
2040
+	 */
2041
+	public function __construct()
2042
+	{
2043
+		// set default organization settings
2044
+		// decode HTML entities from the WP blogname, because it's stored in the DB with HTML entities encoded
2045
+		$this->name = wp_specialchars_decode(get_bloginfo('name'), ENT_QUOTES);
2046
+		$this->email = get_bloginfo('admin_email');
2047
+	}
2048
+}
2350 2049
 
2351
-    /**
2352
-     * Whether or not to show the privacy policy consent checkbox
2353
-     *
2354
-     * @var bool
2355
-     */
2356
-    public $consent_checkbox_enabled;
2050
+/**
2051
+ * Class for defining what's in the EE_Config relating to currency
2052
+ */
2053
+class EE_Currency_Config extends EE_Config_Base
2054
+{
2055
+	/**
2056
+	 * @var string $code
2057
+	 * eg 'USD', 'CAD', 'EUR'
2058
+	 */
2059
+	public $code;
2060
+
2061
+	/**
2062
+	 * locale to use for currency ex: 'en_US'
2063
+	 *
2064
+	 * @var string
2065
+	 */
2066
+	private $locale = 'en_US';
2067
+
2068
+	/**
2069
+	 * @var string $name
2070
+	 * eg 'Dollar'
2071
+	 */
2072
+	public $name;
2073
+
2074
+	/**
2075
+	 * plural name
2076
+	 *
2077
+	 * @var string $plural
2078
+	 * eg 'Dollars'
2079
+	 */
2080
+	public $plural;
2081
+
2082
+	/**
2083
+	 * currency sign
2084
+	 *
2085
+	 * @var string $sign
2086
+	 * eg '$'
2087
+	 */
2088
+	public $sign;
2089
+
2090
+	/**
2091
+	 * Whether the currency sign should come before the number or not
2092
+	 *
2093
+	 * @var boolean $sign_b4
2094
+	 */
2095
+	public $sign_b4;
2096
+
2097
+	/**
2098
+	 * How many digits should come after the decimal place
2099
+	 *
2100
+	 * @var int $dec_plc
2101
+	 */
2102
+	public $dec_plc;
2103
+
2104
+	/**
2105
+	 * Symbol to use for decimal mark
2106
+	 *
2107
+	 * @var string $dec_mrk
2108
+	 * eg '.'
2109
+	 */
2110
+	public $dec_mrk;
2111
+
2112
+	/**
2113
+	 * Symbol to use for thousands
2114
+	 *
2115
+	 * @var string $thsnds
2116
+	 * eg ','
2117
+	 */
2118
+	public $thsnds;
2119
+
2120
+
2121
+	/**
2122
+	 *    class constructor
2123
+	 *
2124
+	 * @access    public
2125
+	 * @param string $CNT_ISO
2126
+	 * @throws EE_Error
2127
+	 * @throws ReflectionException
2128
+	 */
2129
+	public function __construct($CNT_ISO = '')
2130
+	{
2131
+		/** @var TableAnalysis $table_analysis */
2132
+		$table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
2133
+		// get country code from organization settings or use default
2134
+		$ORG_CNT = isset(EE_Registry::instance()->CFG->organization)
2135
+				   && EE_Registry::instance()->CFG->organization instanceof EE_Organization_Config
2136
+			? EE_Registry::instance()->CFG->organization->CNT_ISO
2137
+			: '';
2138
+		// but override if requested
2139
+		$CNT_ISO = ! empty($CNT_ISO) ? $CNT_ISO : $ORG_CNT;
2140
+		// so if that all went well, and we are not in M-Mode (cuz you can't query the db in M-Mode) and double-check the countries table exists
2141
+		if (
2142
+			! empty($CNT_ISO)
2143
+			&& EE_Maintenance_Mode::instance()->models_can_query()
2144
+			&& $table_analysis->tableExists(EE_Registry::instance()->load_model('Country')->table())
2145
+		) {
2146
+			// retrieve the country settings from the db, just in case they have been customized
2147
+			$country = EE_Registry::instance()->load_model('Country')->get_one_by_ID($CNT_ISO);
2148
+			if ($country instanceof EE_Country) {
2149
+				$this->code = $country->currency_code();    // currency code: USD, CAD, EUR
2150
+				$this->name = $country->currency_name_single();    // Dollar
2151
+				$this->plural = $country->currency_name_plural();    // Dollars
2152
+				$this->sign = $country->currency_sign();            // currency sign: $
2153
+				$this->sign_b4 = $country->currency_sign_before(
2154
+				);        // currency sign before or after: $TRUE  or  FALSE$
2155
+				$this->dec_plc = $country->currency_decimal_places();    // decimal places: 2 = 0.00  3 = 0.000
2156
+				$this->dec_mrk = $country->currency_decimal_mark(
2157
+				);    // decimal mark: (comma) ',' = 0,01   or (decimal) '.' = 0.01
2158
+				$this->thsnds = $country->currency_thousands_separator(
2159
+				);    // thousands separator: (comma) ',' = 1,000   or (decimal) '.' = 1.000
2160
+			}
2161
+		}
2162
+		// fallback to hardcoded defaults, in case the above failed
2163
+		if (empty($this->code)) {
2164
+			// set default currency settings
2165
+			$this->code = 'USD';    // currency code: USD, CAD, EUR
2166
+			$this->locale = 'en_US';
2167
+			$this->name = esc_html__('Dollar', 'event_espresso');    // Dollar
2168
+			$this->plural = esc_html__('Dollars', 'event_espresso');    // Dollars
2169
+			$this->sign = '$';    // currency sign: $
2170
+			$this->sign_b4 = true;    // currency sign before or after: $TRUE  or  FALSE$
2171
+			$this->dec_plc = 2;    // decimal places: 2 = 0.00  3 = 0.000
2172
+			$this->dec_mrk = '.';    // decimal mark: (comma) ',' = 0,01   or (decimal) '.' = 0.01
2173
+			$this->thsnds = ',';    // thousands separator: (comma) ',' = 1,000   or (decimal) '.' = 1.000
2174
+		}
2175
+		if (empty($this->locale)) {
2176
+			$this->locale = get_site_option('WPLANG');
2177
+		}
2178
+	}
2179
+
2180
+
2181
+	/**
2182
+	 * @return string
2183
+	 */
2184
+	public function locale()
2185
+	{
2186
+		return $this->locale;
2187
+	}
2188
+
2189
+
2190
+	/**
2191
+	 * @param string $locale
2192
+	 */
2193
+	public function setLocale($locale)
2194
+	{
2195
+		$this->locale = sanitize_text_field($locale);
2196
+	}
2197
+}
2357 2198
 
2358
-    /**
2359
-     * Label text to show on the checkbox
2360
-     *
2361
-     * @var string
2362
-     */
2363
-    public $consent_checkbox_label_text;
2364 2199
 
2365
-    /*
2200
+/**
2201
+ * Class for defining what's in the EE_Config relating to registration settings
2202
+ */
2203
+class EE_Registration_Config extends EE_Config_Base
2204
+{
2205
+	/**
2206
+	 * Default registration status
2207
+	 *
2208
+	 * @var string $default_STS_ID
2209
+	 * eg 'RPP'
2210
+	 */
2211
+	public $default_STS_ID;
2212
+
2213
+	/**
2214
+	 * For new events, this will be the default value for the maximum number of tickets (equivalent to maximum number of
2215
+	 * registrations)
2216
+	 *
2217
+	 * @var int
2218
+	 */
2219
+	public $default_maximum_number_of_tickets;
2220
+
2221
+	/**
2222
+	 * level of validation to apply to email addresses
2223
+	 *
2224
+	 * @var string $email_validation_level
2225
+	 * options: 'basic', 'wp_default', 'i18n', 'i18n_dns'
2226
+	 */
2227
+	public $email_validation_level;
2228
+
2229
+	/**
2230
+	 *    whether or not to show alternate payment options during the reg process if payment status is pending
2231
+	 *
2232
+	 * @var boolean $show_pending_payment_options
2233
+	 */
2234
+	public $show_pending_payment_options;
2235
+
2236
+	/**
2237
+	 * Whether to skip the registration confirmation page
2238
+	 *
2239
+	 * @var boolean $skip_reg_confirmation
2240
+	 */
2241
+	public $skip_reg_confirmation;
2242
+
2243
+	/**
2244
+	 * an array of SPCO reg steps where:
2245
+	 *        the keys denotes the reg step order
2246
+	 *        each element consists of an array with the following elements:
2247
+	 *            "file_path" => the file path to the EE_SPCO_Reg_Step class
2248
+	 *            "class_name" => the specific EE_SPCO_Reg_Step child class name
2249
+	 *            "slug" => the URL param used to trigger the reg step
2250
+	 *
2251
+	 * @var array $reg_steps
2252
+	 */
2253
+	public $reg_steps;
2254
+
2255
+	/**
2256
+	 * Whether registration confirmation should be the last page of SPCO
2257
+	 *
2258
+	 * @var boolean $reg_confirmation_last
2259
+	 */
2260
+	public $reg_confirmation_last;
2261
+
2262
+	/**
2263
+	 * Whether or not to enable the EE Bot Trap
2264
+	 *
2265
+	 * @var boolean $use_bot_trap
2266
+	 */
2267
+	public $use_bot_trap;
2268
+
2269
+	/**
2270
+	 * Whether or not to encrypt some data sent by the EE Bot Trap
2271
+	 *
2272
+	 * @var boolean $use_encryption
2273
+	 */
2274
+	public $use_encryption;
2275
+
2276
+	/**
2277
+	 * Whether or not to use ReCaptcha
2278
+	 *
2279
+	 * @var boolean $use_captcha
2280
+	 */
2281
+	public $use_captcha;
2282
+
2283
+	/**
2284
+	 * ReCaptcha Theme
2285
+	 *
2286
+	 * @var string $recaptcha_theme
2287
+	 *    options: 'dark', 'light', 'invisible'
2288
+	 */
2289
+	public $recaptcha_theme;
2290
+
2291
+	/**
2292
+	 * ReCaptcha Badge - determines the position of the reCAPTCHA badge if using Invisible ReCaptcha.
2293
+	 *
2294
+	 * @var string $recaptcha_badge
2295
+	 *    options: 'bottomright', 'bottomleft', 'inline'
2296
+	 */
2297
+	public $recaptcha_badge;
2298
+
2299
+	/**
2300
+	 * ReCaptcha Type
2301
+	 *
2302
+	 * @var string $recaptcha_type
2303
+	 *    options: 'audio', 'image'
2304
+	 */
2305
+	public $recaptcha_type;
2306
+
2307
+	/**
2308
+	 * ReCaptcha language
2309
+	 *
2310
+	 * @var string $recaptcha_language
2311
+	 * eg 'en'
2312
+	 */
2313
+	public $recaptcha_language;
2314
+
2315
+	/**
2316
+	 * ReCaptcha public key
2317
+	 *
2318
+	 * @var string $recaptcha_publickey
2319
+	 */
2320
+	public $recaptcha_publickey;
2321
+
2322
+	/**
2323
+	 * ReCaptcha private key
2324
+	 *
2325
+	 * @var string $recaptcha_privatekey
2326
+	 */
2327
+	public $recaptcha_privatekey;
2328
+
2329
+	/**
2330
+	 * array of form names protected by ReCaptcha
2331
+	 *
2332
+	 * @var array $recaptcha_protected_forms
2333
+	 */
2334
+	public $recaptcha_protected_forms;
2335
+
2336
+	/**
2337
+	 * ReCaptcha width
2338
+	 *
2339
+	 * @var int $recaptcha_width
2340
+	 * @deprecated
2341
+	 */
2342
+	public $recaptcha_width;
2343
+
2344
+	/**
2345
+	 * Whether or not invalid attempts to directly access the registration checkout page should be tracked.
2346
+	 *
2347
+	 * @var boolean $track_invalid_checkout_access
2348
+	 */
2349
+	protected $track_invalid_checkout_access = true;
2350
+
2351
+	/**
2352
+	 * Whether or not to show the privacy policy consent checkbox
2353
+	 *
2354
+	 * @var bool
2355
+	 */
2356
+	public $consent_checkbox_enabled;
2357
+
2358
+	/**
2359
+	 * Label text to show on the checkbox
2360
+	 *
2361
+	 * @var string
2362
+	 */
2363
+	public $consent_checkbox_label_text;
2364
+
2365
+	/*
2366 2366
      * String describing how long to keep payment logs. Passed into DateTime constructor
2367 2367
      * @var string
2368 2368
      */
2369
-    public $gateway_log_lifespan = '1 week';
2370
-
2371
-    /**
2372
-     * Enable copy attendee info at form
2373
-     *
2374
-     * @var boolean $enable_copy_attendee
2375
-     */
2376
-    protected $copy_attendee_info = true;
2377
-
2378
-
2379
-    /**
2380
-     *    class constructor
2381
-     *
2382
-     * @access    public
2383
-     */
2384
-    public function __construct()
2385
-    {
2386
-        // set default registration settings
2387
-        $this->default_STS_ID = EEM_Registration::status_id_pending_payment;
2388
-        $this->email_validation_level = 'wp_default';
2389
-        $this->show_pending_payment_options = true;
2390
-        $this->skip_reg_confirmation = true;
2391
-        $this->reg_steps = array();
2392
-        $this->reg_confirmation_last = false;
2393
-        $this->use_bot_trap = true;
2394
-        $this->use_encryption = true;
2395
-        $this->use_captcha = false;
2396
-        $this->recaptcha_theme = 'light';
2397
-        $this->recaptcha_badge = 'bottomleft';
2398
-        $this->recaptcha_type = 'image';
2399
-        $this->recaptcha_language = 'en';
2400
-        $this->recaptcha_publickey = null;
2401
-        $this->recaptcha_privatekey = null;
2402
-        $this->recaptcha_protected_forms = array();
2403
-        $this->recaptcha_width = 500;
2404
-        $this->default_maximum_number_of_tickets = 10;
2405
-        $this->consent_checkbox_enabled = false;
2406
-        $this->consent_checkbox_label_text = '';
2407
-        $this->gateway_log_lifespan = '7 days';
2408
-        $this->copy_attendee_info = true;
2409
-    }
2410
-
2411
-
2412
-    /**
2413
-     * This is called by the config loader and hooks are initialized AFTER the config has been populated.
2414
-     *
2415
-     * @since 4.8.8.rc.019
2416
-     */
2417
-    public function do_hooks()
2418
-    {
2419
-        add_action('AHEE__EE_Config___load_core_config__end', array($this, 'set_default_reg_status_on_EEM_Event'));
2420
-        add_action('AHEE__EE_Config___load_core_config__end', array($this, 'set_default_max_ticket_on_EEM_Event'));
2421
-        add_action('setup_theme', array($this, 'setDefaultCheckboxLabelText'));
2422
-    }
2423
-
2424
-
2425
-    /**
2426
-     * Hooked into `AHEE__EE_Config___load_core_config__end` to ensure the default for the
2427
-     * EVT_default_registration_status field matches the config setting for default_STS_ID.
2428
-     */
2429
-    public function set_default_reg_status_on_EEM_Event()
2430
-    {
2431
-        EEM_Event::set_default_reg_status($this->default_STS_ID);
2432
-    }
2433
-
2434
-
2435
-    /**
2436
-     * Hooked into `AHEE__EE_Config___load_core_config__end` to ensure the default for the EVT_additional_limit field
2437
-     * for Events matches the config setting for default_maximum_number_of_tickets
2438
-     */
2439
-    public function set_default_max_ticket_on_EEM_Event()
2440
-    {
2441
-        EEM_Event::set_default_additional_limit($this->default_maximum_number_of_tickets);
2442
-    }
2443
-
2444
-
2445
-    /**
2446
-     * Sets the default consent checkbox text. This needs to be done a bit later than when EE_Registration_Config is
2447
-     * constructed because that happens before we can get the privacy policy page's permalink.
2448
-     *
2449
-     * @throws InvalidArgumentException
2450
-     * @throws InvalidDataTypeException
2451
-     * @throws InvalidInterfaceException
2452
-     */
2453
-    public function setDefaultCheckboxLabelText()
2454
-    {
2455
-        if (
2456
-            $this->getConsentCheckboxLabelText() === null
2457
-            || $this->getConsentCheckboxLabelText() === ''
2458
-        ) {
2459
-            $opening_a_tag = '';
2460
-            $closing_a_tag = '';
2461
-            if (function_exists('get_privacy_policy_url')) {
2462
-                $privacy_page_url = get_privacy_policy_url();
2463
-                if (! empty($privacy_page_url)) {
2464
-                    $opening_a_tag = '<a href="' . $privacy_page_url . '" target="_blank">';
2465
-                    $closing_a_tag = '</a>';
2466
-                }
2467
-            }
2468
-            $loader = LoaderFactory::getLoader();
2469
-            $org_config = $loader->getShared('EE_Organization_Config');
2470
-            /**
2471
-             * @var $org_config EE_Organization_Config
2472
-             */
2473
-
2474
-            $this->setConsentCheckboxLabelText(
2475
-                sprintf(
2476
-                    esc_html__(
2477
-                        'I consent to %1$s storing and using my personal information, according to their %2$sprivacy policy%3$s.',
2478
-                        'event_espresso'
2479
-                    ),
2480
-                    $org_config->name,
2481
-                    $opening_a_tag,
2482
-                    $closing_a_tag
2483
-                )
2484
-            );
2485
-        }
2486
-    }
2487
-
2488
-
2489
-    /**
2490
-     * @return boolean
2491
-     */
2492
-    public function track_invalid_checkout_access()
2493
-    {
2494
-        return $this->track_invalid_checkout_access;
2495
-    }
2496
-
2497
-
2498
-    /**
2499
-     * @param boolean $track_invalid_checkout_access
2500
-     */
2501
-    public function set_track_invalid_checkout_access($track_invalid_checkout_access)
2502
-    {
2503
-        $this->track_invalid_checkout_access = filter_var(
2504
-            $track_invalid_checkout_access,
2505
-            FILTER_VALIDATE_BOOLEAN
2506
-        );
2507
-    }
2508
-
2509
-    /**
2510
-     * @return boolean
2511
-     */
2512
-    public function copyAttendeeInfo()
2513
-    {
2514
-        return $this->copy_attendee_info;
2515
-    }
2516
-
2517
-
2518
-    /**
2519
-     * @param boolean $copy_attendee_info
2520
-     */
2521
-    public function setCopyAttendeeInfo($copy_attendee_info)
2522
-    {
2523
-        $this->copy_attendee_info = filter_var(
2524
-            $copy_attendee_info,
2525
-            FILTER_VALIDATE_BOOLEAN
2526
-        );
2527
-    }
2528
-
2529
-
2530
-    /**
2531
-     * Gets the options to make availalbe for the gateway log lifespan
2532
-     * @return array
2533
-     */
2534
-    public function gatewayLogLifespanOptions()
2535
-    {
2536
-        return (array) apply_filters(
2537
-            'FHEE_EE_Admin_Config__gatewayLogLifespanOptions',
2538
-            array(
2539
-                '1 second' => esc_html__('Don\'t Log At All', 'event_espresso'),
2540
-                '1 day' => esc_html__('1 Day', 'event_espresso'),
2541
-                '7 days' => esc_html__('7 Days', 'event_espresso'),
2542
-                '14 days' => esc_html__('14 Days', 'event_espresso'),
2543
-                '30 days' => esc_html__('30 Days', 'event_espresso')
2544
-            )
2545
-        );
2546
-    }
2547
-
2548
-
2549
-    /**
2550
-     * @return bool
2551
-     */
2552
-    public function isConsentCheckboxEnabled()
2553
-    {
2554
-        return $this->consent_checkbox_enabled;
2555
-    }
2556
-
2557
-
2558
-    /**
2559
-     * @param bool $consent_checkbox_enabled
2560
-     */
2561
-    public function setConsentCheckboxEnabled($consent_checkbox_enabled)
2562
-    {
2563
-        $this->consent_checkbox_enabled = filter_var(
2564
-            $consent_checkbox_enabled,
2565
-            FILTER_VALIDATE_BOOLEAN
2566
-        );
2567
-    }
2568
-
2569
-
2570
-    /**
2571
-     * @return string
2572
-     */
2573
-    public function getConsentCheckboxLabelText()
2574
-    {
2575
-        return $this->consent_checkbox_label_text;
2576
-    }
2577
-
2578
-
2579
-    /**
2580
-     * @param string $consent_checkbox_label_text
2581
-     */
2582
-    public function setConsentCheckboxLabelText($consent_checkbox_label_text)
2583
-    {
2584
-        $this->consent_checkbox_label_text = (string) $consent_checkbox_label_text;
2585
-    }
2369
+	public $gateway_log_lifespan = '1 week';
2370
+
2371
+	/**
2372
+	 * Enable copy attendee info at form
2373
+	 *
2374
+	 * @var boolean $enable_copy_attendee
2375
+	 */
2376
+	protected $copy_attendee_info = true;
2377
+
2378
+
2379
+	/**
2380
+	 *    class constructor
2381
+	 *
2382
+	 * @access    public
2383
+	 */
2384
+	public function __construct()
2385
+	{
2386
+		// set default registration settings
2387
+		$this->default_STS_ID = EEM_Registration::status_id_pending_payment;
2388
+		$this->email_validation_level = 'wp_default';
2389
+		$this->show_pending_payment_options = true;
2390
+		$this->skip_reg_confirmation = true;
2391
+		$this->reg_steps = array();
2392
+		$this->reg_confirmation_last = false;
2393
+		$this->use_bot_trap = true;
2394
+		$this->use_encryption = true;
2395
+		$this->use_captcha = false;
2396
+		$this->recaptcha_theme = 'light';
2397
+		$this->recaptcha_badge = 'bottomleft';
2398
+		$this->recaptcha_type = 'image';
2399
+		$this->recaptcha_language = 'en';
2400
+		$this->recaptcha_publickey = null;
2401
+		$this->recaptcha_privatekey = null;
2402
+		$this->recaptcha_protected_forms = array();
2403
+		$this->recaptcha_width = 500;
2404
+		$this->default_maximum_number_of_tickets = 10;
2405
+		$this->consent_checkbox_enabled = false;
2406
+		$this->consent_checkbox_label_text = '';
2407
+		$this->gateway_log_lifespan = '7 days';
2408
+		$this->copy_attendee_info = true;
2409
+	}
2410
+
2411
+
2412
+	/**
2413
+	 * This is called by the config loader and hooks are initialized AFTER the config has been populated.
2414
+	 *
2415
+	 * @since 4.8.8.rc.019
2416
+	 */
2417
+	public function do_hooks()
2418
+	{
2419
+		add_action('AHEE__EE_Config___load_core_config__end', array($this, 'set_default_reg_status_on_EEM_Event'));
2420
+		add_action('AHEE__EE_Config___load_core_config__end', array($this, 'set_default_max_ticket_on_EEM_Event'));
2421
+		add_action('setup_theme', array($this, 'setDefaultCheckboxLabelText'));
2422
+	}
2423
+
2424
+
2425
+	/**
2426
+	 * Hooked into `AHEE__EE_Config___load_core_config__end` to ensure the default for the
2427
+	 * EVT_default_registration_status field matches the config setting for default_STS_ID.
2428
+	 */
2429
+	public function set_default_reg_status_on_EEM_Event()
2430
+	{
2431
+		EEM_Event::set_default_reg_status($this->default_STS_ID);
2432
+	}
2433
+
2434
+
2435
+	/**
2436
+	 * Hooked into `AHEE__EE_Config___load_core_config__end` to ensure the default for the EVT_additional_limit field
2437
+	 * for Events matches the config setting for default_maximum_number_of_tickets
2438
+	 */
2439
+	public function set_default_max_ticket_on_EEM_Event()
2440
+	{
2441
+		EEM_Event::set_default_additional_limit($this->default_maximum_number_of_tickets);
2442
+	}
2443
+
2444
+
2445
+	/**
2446
+	 * Sets the default consent checkbox text. This needs to be done a bit later than when EE_Registration_Config is
2447
+	 * constructed because that happens before we can get the privacy policy page's permalink.
2448
+	 *
2449
+	 * @throws InvalidArgumentException
2450
+	 * @throws InvalidDataTypeException
2451
+	 * @throws InvalidInterfaceException
2452
+	 */
2453
+	public function setDefaultCheckboxLabelText()
2454
+	{
2455
+		if (
2456
+			$this->getConsentCheckboxLabelText() === null
2457
+			|| $this->getConsentCheckboxLabelText() === ''
2458
+		) {
2459
+			$opening_a_tag = '';
2460
+			$closing_a_tag = '';
2461
+			if (function_exists('get_privacy_policy_url')) {
2462
+				$privacy_page_url = get_privacy_policy_url();
2463
+				if (! empty($privacy_page_url)) {
2464
+					$opening_a_tag = '<a href="' . $privacy_page_url . '" target="_blank">';
2465
+					$closing_a_tag = '</a>';
2466
+				}
2467
+			}
2468
+			$loader = LoaderFactory::getLoader();
2469
+			$org_config = $loader->getShared('EE_Organization_Config');
2470
+			/**
2471
+			 * @var $org_config EE_Organization_Config
2472
+			 */
2473
+
2474
+			$this->setConsentCheckboxLabelText(
2475
+				sprintf(
2476
+					esc_html__(
2477
+						'I consent to %1$s storing and using my personal information, according to their %2$sprivacy policy%3$s.',
2478
+						'event_espresso'
2479
+					),
2480
+					$org_config->name,
2481
+					$opening_a_tag,
2482
+					$closing_a_tag
2483
+				)
2484
+			);
2485
+		}
2486
+	}
2487
+
2488
+
2489
+	/**
2490
+	 * @return boolean
2491
+	 */
2492
+	public function track_invalid_checkout_access()
2493
+	{
2494
+		return $this->track_invalid_checkout_access;
2495
+	}
2496
+
2497
+
2498
+	/**
2499
+	 * @param boolean $track_invalid_checkout_access
2500
+	 */
2501
+	public function set_track_invalid_checkout_access($track_invalid_checkout_access)
2502
+	{
2503
+		$this->track_invalid_checkout_access = filter_var(
2504
+			$track_invalid_checkout_access,
2505
+			FILTER_VALIDATE_BOOLEAN
2506
+		);
2507
+	}
2508
+
2509
+	/**
2510
+	 * @return boolean
2511
+	 */
2512
+	public function copyAttendeeInfo()
2513
+	{
2514
+		return $this->copy_attendee_info;
2515
+	}
2516
+
2517
+
2518
+	/**
2519
+	 * @param boolean $copy_attendee_info
2520
+	 */
2521
+	public function setCopyAttendeeInfo($copy_attendee_info)
2522
+	{
2523
+		$this->copy_attendee_info = filter_var(
2524
+			$copy_attendee_info,
2525
+			FILTER_VALIDATE_BOOLEAN
2526
+		);
2527
+	}
2528
+
2529
+
2530
+	/**
2531
+	 * Gets the options to make availalbe for the gateway log lifespan
2532
+	 * @return array
2533
+	 */
2534
+	public function gatewayLogLifespanOptions()
2535
+	{
2536
+		return (array) apply_filters(
2537
+			'FHEE_EE_Admin_Config__gatewayLogLifespanOptions',
2538
+			array(
2539
+				'1 second' => esc_html__('Don\'t Log At All', 'event_espresso'),
2540
+				'1 day' => esc_html__('1 Day', 'event_espresso'),
2541
+				'7 days' => esc_html__('7 Days', 'event_espresso'),
2542
+				'14 days' => esc_html__('14 Days', 'event_espresso'),
2543
+				'30 days' => esc_html__('30 Days', 'event_espresso')
2544
+			)
2545
+		);
2546
+	}
2547
+
2548
+
2549
+	/**
2550
+	 * @return bool
2551
+	 */
2552
+	public function isConsentCheckboxEnabled()
2553
+	{
2554
+		return $this->consent_checkbox_enabled;
2555
+	}
2556
+
2557
+
2558
+	/**
2559
+	 * @param bool $consent_checkbox_enabled
2560
+	 */
2561
+	public function setConsentCheckboxEnabled($consent_checkbox_enabled)
2562
+	{
2563
+		$this->consent_checkbox_enabled = filter_var(
2564
+			$consent_checkbox_enabled,
2565
+			FILTER_VALIDATE_BOOLEAN
2566
+		);
2567
+	}
2568
+
2569
+
2570
+	/**
2571
+	 * @return string
2572
+	 */
2573
+	public function getConsentCheckboxLabelText()
2574
+	{
2575
+		return $this->consent_checkbox_label_text;
2576
+	}
2577
+
2578
+
2579
+	/**
2580
+	 * @param string $consent_checkbox_label_text
2581
+	 */
2582
+	public function setConsentCheckboxLabelText($consent_checkbox_label_text)
2583
+	{
2584
+		$this->consent_checkbox_label_text = (string) $consent_checkbox_label_text;
2585
+	}
2586 2586
 }
2587 2587
 
2588 2588
 /**
@@ -2590,143 +2590,143 @@  discard block
 block discarded – undo
2590 2590
  */
2591 2591
 class EE_Admin_Config extends EE_Config_Base
2592 2592
 {
2593
-    /**
2594
-     * @var boolean $use_personnel_manager
2595
-     */
2596
-    public $use_personnel_manager;
2597
-
2598
-    /**
2599
-     * @var boolean $use_dashboard_widget
2600
-     */
2601
-    public $use_dashboard_widget;
2602
-
2603
-    /**
2604
-     * @var int $events_in_dashboard
2605
-     */
2606
-    public $events_in_dashboard;
2607
-
2608
-    /**
2609
-     * @var boolean $use_event_timezones
2610
-     */
2611
-    public $use_event_timezones;
2612
-
2613
-    /**
2614
-     * @var string $log_file_name
2615
-     */
2616
-    public $log_file_name;
2617
-
2618
-    /**
2619
-     * @var string $debug_file_name
2620
-     */
2621
-    public $debug_file_name;
2622
-
2623
-    /**
2624
-     * @var boolean $use_remote_logging
2625
-     */
2626
-    public $use_remote_logging;
2627
-
2628
-    /**
2629
-     * @var string $remote_logging_url
2630
-     */
2631
-    public $remote_logging_url;
2632
-
2633
-    /**
2634
-     * @var boolean $show_reg_footer
2635
-     */
2636
-    public $show_reg_footer;
2637
-
2638
-    /**
2639
-     * @var string $affiliate_id
2640
-     */
2641
-    public $affiliate_id;
2642
-
2643
-    /**
2644
-     * adds extra layer of encoding to session data to prevent serialization errors
2645
-     * but is incompatible with some server configuration errors
2646
-     * if you get "500 internal server errors" during registration, try turning this on
2647
-     * if you get PHP fatal errors regarding base 64 methods not defined, then turn this off
2648
-     *
2649
-     * @var boolean $encode_session_data
2650
-     */
2651
-    private $encode_session_data = false;
2652
-
2653
-
2654
-    /**
2655
-     *    class constructor
2656
-     *
2657
-     * @access    public
2658
-     */
2659
-    public function __construct()
2660
-    {
2661
-        // set default general admin settings
2662
-        $this->use_personnel_manager = true;
2663
-        $this->use_dashboard_widget = true;
2664
-        $this->events_in_dashboard = 30;
2665
-        $this->use_event_timezones = false;
2666
-        $this->use_remote_logging = false;
2667
-        $this->remote_logging_url = null;
2668
-        $this->show_reg_footer = apply_filters(
2669
-            'FHEE__EE_Admin_Config__show_reg_footer__default',
2670
-            false
2671
-        );
2672
-        $this->affiliate_id = 'default';
2673
-        $this->encode_session_data = false;
2674
-    }
2675
-
2676
-
2677
-    /**
2678
-     * @param bool $reset
2679
-     * @return string
2680
-     */
2681
-    public function log_file_name($reset = false)
2682
-    {
2683
-        if (empty($this->log_file_name) || $reset) {
2684
-            $this->log_file_name = sanitize_key('espresso_log_' . md5(uniqid('', true))) . '.txt';
2685
-            EE_Config::instance()->update_espresso_config(false, false);
2686
-        }
2687
-        return $this->log_file_name;
2688
-    }
2689
-
2690
-
2691
-    /**
2692
-     * @param bool $reset
2693
-     * @return string
2694
-     */
2695
-    public function debug_file_name($reset = false)
2696
-    {
2697
-        if (empty($this->debug_file_name) || $reset) {
2698
-            $this->debug_file_name = sanitize_key('espresso_debug_' . md5(uniqid('', true))) . '.txt';
2699
-            EE_Config::instance()->update_espresso_config(false, false);
2700
-        }
2701
-        return $this->debug_file_name;
2702
-    }
2703
-
2704
-
2705
-    /**
2706
-     * @return string
2707
-     */
2708
-    public function affiliate_id()
2709
-    {
2710
-        return ! empty($this->affiliate_id) ? $this->affiliate_id : 'default';
2711
-    }
2712
-
2713
-
2714
-    /**
2715
-     * @return boolean
2716
-     */
2717
-    public function encode_session_data()
2718
-    {
2719
-        return filter_var($this->encode_session_data, FILTER_VALIDATE_BOOLEAN);
2720
-    }
2721
-
2722
-
2723
-    /**
2724
-     * @param boolean $encode_session_data
2725
-     */
2726
-    public function set_encode_session_data($encode_session_data)
2727
-    {
2728
-        $this->encode_session_data = filter_var($encode_session_data, FILTER_VALIDATE_BOOLEAN);
2729
-    }
2593
+	/**
2594
+	 * @var boolean $use_personnel_manager
2595
+	 */
2596
+	public $use_personnel_manager;
2597
+
2598
+	/**
2599
+	 * @var boolean $use_dashboard_widget
2600
+	 */
2601
+	public $use_dashboard_widget;
2602
+
2603
+	/**
2604
+	 * @var int $events_in_dashboard
2605
+	 */
2606
+	public $events_in_dashboard;
2607
+
2608
+	/**
2609
+	 * @var boolean $use_event_timezones
2610
+	 */
2611
+	public $use_event_timezones;
2612
+
2613
+	/**
2614
+	 * @var string $log_file_name
2615
+	 */
2616
+	public $log_file_name;
2617
+
2618
+	/**
2619
+	 * @var string $debug_file_name
2620
+	 */
2621
+	public $debug_file_name;
2622
+
2623
+	/**
2624
+	 * @var boolean $use_remote_logging
2625
+	 */
2626
+	public $use_remote_logging;
2627
+
2628
+	/**
2629
+	 * @var string $remote_logging_url
2630
+	 */
2631
+	public $remote_logging_url;
2632
+
2633
+	/**
2634
+	 * @var boolean $show_reg_footer
2635
+	 */
2636
+	public $show_reg_footer;
2637
+
2638
+	/**
2639
+	 * @var string $affiliate_id
2640
+	 */
2641
+	public $affiliate_id;
2642
+
2643
+	/**
2644
+	 * adds extra layer of encoding to session data to prevent serialization errors
2645
+	 * but is incompatible with some server configuration errors
2646
+	 * if you get "500 internal server errors" during registration, try turning this on
2647
+	 * if you get PHP fatal errors regarding base 64 methods not defined, then turn this off
2648
+	 *
2649
+	 * @var boolean $encode_session_data
2650
+	 */
2651
+	private $encode_session_data = false;
2652
+
2653
+
2654
+	/**
2655
+	 *    class constructor
2656
+	 *
2657
+	 * @access    public
2658
+	 */
2659
+	public function __construct()
2660
+	{
2661
+		// set default general admin settings
2662
+		$this->use_personnel_manager = true;
2663
+		$this->use_dashboard_widget = true;
2664
+		$this->events_in_dashboard = 30;
2665
+		$this->use_event_timezones = false;
2666
+		$this->use_remote_logging = false;
2667
+		$this->remote_logging_url = null;
2668
+		$this->show_reg_footer = apply_filters(
2669
+			'FHEE__EE_Admin_Config__show_reg_footer__default',
2670
+			false
2671
+		);
2672
+		$this->affiliate_id = 'default';
2673
+		$this->encode_session_data = false;
2674
+	}
2675
+
2676
+
2677
+	/**
2678
+	 * @param bool $reset
2679
+	 * @return string
2680
+	 */
2681
+	public function log_file_name($reset = false)
2682
+	{
2683
+		if (empty($this->log_file_name) || $reset) {
2684
+			$this->log_file_name = sanitize_key('espresso_log_' . md5(uniqid('', true))) . '.txt';
2685
+			EE_Config::instance()->update_espresso_config(false, false);
2686
+		}
2687
+		return $this->log_file_name;
2688
+	}
2689
+
2690
+
2691
+	/**
2692
+	 * @param bool $reset
2693
+	 * @return string
2694
+	 */
2695
+	public function debug_file_name($reset = false)
2696
+	{
2697
+		if (empty($this->debug_file_name) || $reset) {
2698
+			$this->debug_file_name = sanitize_key('espresso_debug_' . md5(uniqid('', true))) . '.txt';
2699
+			EE_Config::instance()->update_espresso_config(false, false);
2700
+		}
2701
+		return $this->debug_file_name;
2702
+	}
2703
+
2704
+
2705
+	/**
2706
+	 * @return string
2707
+	 */
2708
+	public function affiliate_id()
2709
+	{
2710
+		return ! empty($this->affiliate_id) ? $this->affiliate_id : 'default';
2711
+	}
2712
+
2713
+
2714
+	/**
2715
+	 * @return boolean
2716
+	 */
2717
+	public function encode_session_data()
2718
+	{
2719
+		return filter_var($this->encode_session_data, FILTER_VALIDATE_BOOLEAN);
2720
+	}
2721
+
2722
+
2723
+	/**
2724
+	 * @param boolean $encode_session_data
2725
+	 */
2726
+	public function set_encode_session_data($encode_session_data)
2727
+	{
2728
+		$this->encode_session_data = filter_var($encode_session_data, FILTER_VALIDATE_BOOLEAN);
2729
+	}
2730 2730
 }
2731 2731
 
2732 2732
 /**
@@ -2734,70 +2734,70 @@  discard block
 block discarded – undo
2734 2734
  */
2735 2735
 class EE_Template_Config extends EE_Config_Base
2736 2736
 {
2737
-    /**
2738
-     * @var boolean $enable_default_style
2739
-     */
2740
-    public $enable_default_style;
2741
-
2742
-    /**
2743
-     * @var string $custom_style_sheet
2744
-     */
2745
-    public $custom_style_sheet;
2746
-
2747
-    /**
2748
-     * @var boolean $display_address_in_regform
2749
-     */
2750
-    public $display_address_in_regform;
2751
-
2752
-    /**
2753
-     * @var int $display_description_on_multi_reg_page
2754
-     */
2755
-    public $display_description_on_multi_reg_page;
2756
-
2757
-    /**
2758
-     * @var boolean $use_custom_templates
2759
-     */
2760
-    public $use_custom_templates;
2761
-
2762
-    /**
2763
-     * @var string $current_espresso_theme
2764
-     */
2765
-    public $current_espresso_theme;
2766
-
2767
-    /**
2768
-     * @var EE_Ticket_Selector_Config $EED_Ticket_Selector
2769
-     */
2770
-    public $EED_Ticket_Selector;
2771
-
2772
-    /**
2773
-     * @var EE_Event_Single_Config $EED_Event_Single
2774
-     */
2775
-    public $EED_Event_Single;
2776
-
2777
-    /**
2778
-     * @var EE_Events_Archive_Config $EED_Events_Archive
2779
-     */
2780
-    public $EED_Events_Archive;
2781
-
2782
-
2783
-    /**
2784
-     *    class constructor
2785
-     *
2786
-     * @access    public
2787
-     */
2788
-    public function __construct()
2789
-    {
2790
-        // set default template settings
2791
-        $this->enable_default_style = true;
2792
-        $this->custom_style_sheet = null;
2793
-        $this->display_address_in_regform = true;
2794
-        $this->display_description_on_multi_reg_page = false;
2795
-        $this->use_custom_templates = false;
2796
-        $this->current_espresso_theme = 'Espresso_Arabica_2014';
2797
-        $this->EED_Event_Single = null;
2798
-        $this->EED_Events_Archive = null;
2799
-        $this->EED_Ticket_Selector = null;
2800
-    }
2737
+	/**
2738
+	 * @var boolean $enable_default_style
2739
+	 */
2740
+	public $enable_default_style;
2741
+
2742
+	/**
2743
+	 * @var string $custom_style_sheet
2744
+	 */
2745
+	public $custom_style_sheet;
2746
+
2747
+	/**
2748
+	 * @var boolean $display_address_in_regform
2749
+	 */
2750
+	public $display_address_in_regform;
2751
+
2752
+	/**
2753
+	 * @var int $display_description_on_multi_reg_page
2754
+	 */
2755
+	public $display_description_on_multi_reg_page;
2756
+
2757
+	/**
2758
+	 * @var boolean $use_custom_templates
2759
+	 */
2760
+	public $use_custom_templates;
2761
+
2762
+	/**
2763
+	 * @var string $current_espresso_theme
2764
+	 */
2765
+	public $current_espresso_theme;
2766
+
2767
+	/**
2768
+	 * @var EE_Ticket_Selector_Config $EED_Ticket_Selector
2769
+	 */
2770
+	public $EED_Ticket_Selector;
2771
+
2772
+	/**
2773
+	 * @var EE_Event_Single_Config $EED_Event_Single
2774
+	 */
2775
+	public $EED_Event_Single;
2776
+
2777
+	/**
2778
+	 * @var EE_Events_Archive_Config $EED_Events_Archive
2779
+	 */
2780
+	public $EED_Events_Archive;
2781
+
2782
+
2783
+	/**
2784
+	 *    class constructor
2785
+	 *
2786
+	 * @access    public
2787
+	 */
2788
+	public function __construct()
2789
+	{
2790
+		// set default template settings
2791
+		$this->enable_default_style = true;
2792
+		$this->custom_style_sheet = null;
2793
+		$this->display_address_in_regform = true;
2794
+		$this->display_description_on_multi_reg_page = false;
2795
+		$this->use_custom_templates = false;
2796
+		$this->current_espresso_theme = 'Espresso_Arabica_2014';
2797
+		$this->EED_Event_Single = null;
2798
+		$this->EED_Events_Archive = null;
2799
+		$this->EED_Ticket_Selector = null;
2800
+	}
2801 2801
 }
2802 2802
 
2803 2803
 /**
@@ -2805,114 +2805,114 @@  discard block
 block discarded – undo
2805 2805
  */
2806 2806
 class EE_Map_Config extends EE_Config_Base
2807 2807
 {
2808
-    /**
2809
-     * @var boolean $use_google_maps
2810
-     */
2811
-    public $use_google_maps;
2812
-
2813
-    /**
2814
-     * @var string $api_key
2815
-     */
2816
-    public $google_map_api_key;
2817
-
2818
-    /**
2819
-     * @var int $event_details_map_width
2820
-     */
2821
-    public $event_details_map_width;
2822
-
2823
-    /**
2824
-     * @var int $event_details_map_height
2825
-     */
2826
-    public $event_details_map_height;
2827
-
2828
-    /**
2829
-     * @var int $event_details_map_zoom
2830
-     */
2831
-    public $event_details_map_zoom;
2832
-
2833
-    /**
2834
-     * @var boolean $event_details_display_nav
2835
-     */
2836
-    public $event_details_display_nav;
2837
-
2838
-    /**
2839
-     * @var boolean $event_details_nav_size
2840
-     */
2841
-    public $event_details_nav_size;
2842
-
2843
-    /**
2844
-     * @var string $event_details_control_type
2845
-     */
2846
-    public $event_details_control_type;
2847
-
2848
-    /**
2849
-     * @var string $event_details_map_align
2850
-     */
2851
-    public $event_details_map_align;
2852
-
2853
-    /**
2854
-     * @var int $event_list_map_width
2855
-     */
2856
-    public $event_list_map_width;
2857
-
2858
-    /**
2859
-     * @var int $event_list_map_height
2860
-     */
2861
-    public $event_list_map_height;
2862
-
2863
-    /**
2864
-     * @var int $event_list_map_zoom
2865
-     */
2866
-    public $event_list_map_zoom;
2867
-
2868
-    /**
2869
-     * @var boolean $event_list_display_nav
2870
-     */
2871
-    public $event_list_display_nav;
2872
-
2873
-    /**
2874
-     * @var boolean $event_list_nav_size
2875
-     */
2876
-    public $event_list_nav_size;
2877
-
2878
-    /**
2879
-     * @var string $event_list_control_type
2880
-     */
2881
-    public $event_list_control_type;
2882
-
2883
-    /**
2884
-     * @var string $event_list_map_align
2885
-     */
2886
-    public $event_list_map_align;
2887
-
2888
-
2889
-    /**
2890
-     *    class constructor
2891
-     *
2892
-     * @access    public
2893
-     */
2894
-    public function __construct()
2895
-    {
2896
-        // set default map settings
2897
-        $this->use_google_maps = true;
2898
-        $this->google_map_api_key = '';
2899
-        // for event details pages (reg page)
2900
-        $this->event_details_map_width = 585;            // ee_map_width_single
2901
-        $this->event_details_map_height = 362;            // ee_map_height_single
2902
-        $this->event_details_map_zoom = 14;            // ee_map_zoom_single
2903
-        $this->event_details_display_nav = true;            // ee_map_nav_display_single
2904
-        $this->event_details_nav_size = false;            // ee_map_nav_size_single
2905
-        $this->event_details_control_type = 'default';        // ee_map_type_control_single
2906
-        $this->event_details_map_align = 'center';            // ee_map_align_single
2907
-        // for event list pages
2908
-        $this->event_list_map_width = 300;            // ee_map_width
2909
-        $this->event_list_map_height = 185;        // ee_map_height
2910
-        $this->event_list_map_zoom = 12;            // ee_map_zoom
2911
-        $this->event_list_display_nav = false;        // ee_map_nav_display
2912
-        $this->event_list_nav_size = true;            // ee_map_nav_size
2913
-        $this->event_list_control_type = 'dropdown';        // ee_map_type_control
2914
-        $this->event_list_map_align = 'center';            // ee_map_align
2915
-    }
2808
+	/**
2809
+	 * @var boolean $use_google_maps
2810
+	 */
2811
+	public $use_google_maps;
2812
+
2813
+	/**
2814
+	 * @var string $api_key
2815
+	 */
2816
+	public $google_map_api_key;
2817
+
2818
+	/**
2819
+	 * @var int $event_details_map_width
2820
+	 */
2821
+	public $event_details_map_width;
2822
+
2823
+	/**
2824
+	 * @var int $event_details_map_height
2825
+	 */
2826
+	public $event_details_map_height;
2827
+
2828
+	/**
2829
+	 * @var int $event_details_map_zoom
2830
+	 */
2831
+	public $event_details_map_zoom;
2832
+
2833
+	/**
2834
+	 * @var boolean $event_details_display_nav
2835
+	 */
2836
+	public $event_details_display_nav;
2837
+
2838
+	/**
2839
+	 * @var boolean $event_details_nav_size
2840
+	 */
2841
+	public $event_details_nav_size;
2842
+
2843
+	/**
2844
+	 * @var string $event_details_control_type
2845
+	 */
2846
+	public $event_details_control_type;
2847
+
2848
+	/**
2849
+	 * @var string $event_details_map_align
2850
+	 */
2851
+	public $event_details_map_align;
2852
+
2853
+	/**
2854
+	 * @var int $event_list_map_width
2855
+	 */
2856
+	public $event_list_map_width;
2857
+
2858
+	/**
2859
+	 * @var int $event_list_map_height
2860
+	 */
2861
+	public $event_list_map_height;
2862
+
2863
+	/**
2864
+	 * @var int $event_list_map_zoom
2865
+	 */
2866
+	public $event_list_map_zoom;
2867
+
2868
+	/**
2869
+	 * @var boolean $event_list_display_nav
2870
+	 */
2871
+	public $event_list_display_nav;
2872
+
2873
+	/**
2874
+	 * @var boolean $event_list_nav_size
2875
+	 */
2876
+	public $event_list_nav_size;
2877
+
2878
+	/**
2879
+	 * @var string $event_list_control_type
2880
+	 */
2881
+	public $event_list_control_type;
2882
+
2883
+	/**
2884
+	 * @var string $event_list_map_align
2885
+	 */
2886
+	public $event_list_map_align;
2887
+
2888
+
2889
+	/**
2890
+	 *    class constructor
2891
+	 *
2892
+	 * @access    public
2893
+	 */
2894
+	public function __construct()
2895
+	{
2896
+		// set default map settings
2897
+		$this->use_google_maps = true;
2898
+		$this->google_map_api_key = '';
2899
+		// for event details pages (reg page)
2900
+		$this->event_details_map_width = 585;            // ee_map_width_single
2901
+		$this->event_details_map_height = 362;            // ee_map_height_single
2902
+		$this->event_details_map_zoom = 14;            // ee_map_zoom_single
2903
+		$this->event_details_display_nav = true;            // ee_map_nav_display_single
2904
+		$this->event_details_nav_size = false;            // ee_map_nav_size_single
2905
+		$this->event_details_control_type = 'default';        // ee_map_type_control_single
2906
+		$this->event_details_map_align = 'center';            // ee_map_align_single
2907
+		// for event list pages
2908
+		$this->event_list_map_width = 300;            // ee_map_width
2909
+		$this->event_list_map_height = 185;        // ee_map_height
2910
+		$this->event_list_map_zoom = 12;            // ee_map_zoom
2911
+		$this->event_list_display_nav = false;        // ee_map_nav_display
2912
+		$this->event_list_nav_size = true;            // ee_map_nav_size
2913
+		$this->event_list_control_type = 'dropdown';        // ee_map_type_control
2914
+		$this->event_list_map_align = 'center';            // ee_map_align
2915
+	}
2916 2916
 }
2917 2917
 
2918 2918
 /**
@@ -2920,46 +2920,46 @@  discard block
 block discarded – undo
2920 2920
  */
2921 2921
 class EE_Events_Archive_Config extends EE_Config_Base
2922 2922
 {
2923
-    public $display_status_banner;
2923
+	public $display_status_banner;
2924 2924
 
2925
-    public $display_description;
2925
+	public $display_description;
2926 2926
 
2927
-    public $display_ticket_selector;
2927
+	public $display_ticket_selector;
2928 2928
 
2929
-    public $display_datetimes;
2929
+	public $display_datetimes;
2930 2930
 
2931
-    public $display_venue;
2931
+	public $display_venue;
2932 2932
 
2933
-    public $display_expired_events;
2933
+	public $display_expired_events;
2934 2934
 
2935
-    public $use_sortable_display_order;
2935
+	public $use_sortable_display_order;
2936 2936
 
2937
-    public $display_order_tickets;
2937
+	public $display_order_tickets;
2938 2938
 
2939
-    public $display_order_datetimes;
2939
+	public $display_order_datetimes;
2940 2940
 
2941
-    public $display_order_event;
2941
+	public $display_order_event;
2942 2942
 
2943
-    public $display_order_venue;
2943
+	public $display_order_venue;
2944 2944
 
2945 2945
 
2946
-    /**
2947
-     *    class constructor
2948
-     */
2949
-    public function __construct()
2950
-    {
2951
-        $this->display_status_banner = 0;
2952
-        $this->display_description = 1;
2953
-        $this->display_ticket_selector = 0;
2954
-        $this->display_datetimes = 1;
2955
-        $this->display_venue = 0;
2956
-        $this->display_expired_events = 0;
2957
-        $this->use_sortable_display_order = false;
2958
-        $this->display_order_tickets = 100;
2959
-        $this->display_order_datetimes = 110;
2960
-        $this->display_order_event = 120;
2961
-        $this->display_order_venue = 130;
2962
-    }
2946
+	/**
2947
+	 *    class constructor
2948
+	 */
2949
+	public function __construct()
2950
+	{
2951
+		$this->display_status_banner = 0;
2952
+		$this->display_description = 1;
2953
+		$this->display_ticket_selector = 0;
2954
+		$this->display_datetimes = 1;
2955
+		$this->display_venue = 0;
2956
+		$this->display_expired_events = 0;
2957
+		$this->use_sortable_display_order = false;
2958
+		$this->display_order_tickets = 100;
2959
+		$this->display_order_datetimes = 110;
2960
+		$this->display_order_event = 120;
2961
+		$this->display_order_venue = 130;
2962
+	}
2963 2963
 }
2964 2964
 
2965 2965
 /**
@@ -2967,34 +2967,34 @@  discard block
 block discarded – undo
2967 2967
  */
2968 2968
 class EE_Event_Single_Config extends EE_Config_Base
2969 2969
 {
2970
-    public $display_status_banner_single;
2970
+	public $display_status_banner_single;
2971 2971
 
2972
-    public $display_venue;
2972
+	public $display_venue;
2973 2973
 
2974
-    public $use_sortable_display_order;
2974
+	public $use_sortable_display_order;
2975 2975
 
2976
-    public $display_order_tickets;
2976
+	public $display_order_tickets;
2977 2977
 
2978
-    public $display_order_datetimes;
2978
+	public $display_order_datetimes;
2979 2979
 
2980
-    public $display_order_event;
2980
+	public $display_order_event;
2981 2981
 
2982
-    public $display_order_venue;
2982
+	public $display_order_venue;
2983 2983
 
2984 2984
 
2985
-    /**
2986
-     *    class constructor
2987
-     */
2988
-    public function __construct()
2989
-    {
2990
-        $this->display_status_banner_single = 0;
2991
-        $this->display_venue = 1;
2992
-        $this->use_sortable_display_order = false;
2993
-        $this->display_order_tickets = 100;
2994
-        $this->display_order_datetimes = 110;
2995
-        $this->display_order_event = 120;
2996
-        $this->display_order_venue = 130;
2997
-    }
2985
+	/**
2986
+	 *    class constructor
2987
+	 */
2988
+	public function __construct()
2989
+	{
2990
+		$this->display_status_banner_single = 0;
2991
+		$this->display_venue = 1;
2992
+		$this->use_sortable_display_order = false;
2993
+		$this->display_order_tickets = 100;
2994
+		$this->display_order_datetimes = 110;
2995
+		$this->display_order_event = 120;
2996
+		$this->display_order_venue = 130;
2997
+	}
2998 2998
 }
2999 2999
 
3000 3000
 /**
@@ -3002,172 +3002,172 @@  discard block
 block discarded – undo
3002 3002
  */
3003 3003
 class EE_Ticket_Selector_Config extends EE_Config_Base
3004 3004
 {
3005
-    /**
3006
-     * constant to indicate that a datetime selector should NEVER be shown for ticket selectors
3007
-     */
3008
-    const DO_NOT_SHOW_DATETIME_SELECTOR = 'no_datetime_selector';
3009
-
3010
-    /**
3011
-     * constant to indicate that a datetime selector should only be shown for ticket selectors
3012
-     * when the number of datetimes for the event matches the value set for $datetime_selector_threshold
3013
-     */
3014
-    const MAYBE_SHOW_DATETIME_SELECTOR = 'maybe_datetime_selector';
3015
-
3016
-    /**
3017
-     * @var boolean $show_ticket_sale_columns
3018
-     */
3019
-    public $show_ticket_sale_columns;
3020
-
3021
-    /**
3022
-     * @var boolean $show_ticket_details
3023
-     */
3024
-    public $show_ticket_details;
3025
-
3026
-    /**
3027
-     * @var boolean $show_expired_tickets
3028
-     */
3029
-    public $show_expired_tickets;
3030
-
3031
-    /**
3032
-     * whether or not to display a dropdown box populated with event datetimes
3033
-     * that toggles which tickets are displayed for a ticket selector.
3034
-     * uses one of the *_DATETIME_SELECTOR constants defined above
3035
-     *
3036
-     * @var string $show_datetime_selector
3037
-     */
3038
-    private $show_datetime_selector = 'no_datetime_selector';
3039
-
3040
-    /**
3041
-     * the number of datetimes an event has to have before conditionally displaying a datetime selector
3042
-     *
3043
-     * @var int $datetime_selector_threshold
3044
-     */
3045
-    private $datetime_selector_threshold = 3;
3046
-
3047
-    /**
3048
-     * determines the maximum number of "checked" dates in the date and time filter
3049
-     *
3050
-     * @var int $datetime_selector_checked
3051
-     */
3052
-    private $datetime_selector_max_checked = 10;
3053
-
3054
-
3055
-    /**
3056
-     *    class constructor
3057
-     */
3058
-    public function __construct()
3059
-    {
3060
-        $this->show_ticket_sale_columns = true;
3061
-        $this->show_ticket_details = true;
3062
-        $this->show_expired_tickets = true;
3063
-        $this->show_datetime_selector = EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR;
3064
-        $this->datetime_selector_threshold = 3;
3065
-        $this->datetime_selector_max_checked = 10;
3066
-    }
3067
-
3068
-
3069
-    /**
3070
-     * returns true if a datetime selector should be displayed
3071
-     *
3072
-     * @param array $datetimes
3073
-     * @return bool
3074
-     */
3075
-    public function showDatetimeSelector(array $datetimes)
3076
-    {
3077
-        // if the settings are NOT: don't show OR below threshold, THEN active = true
3078
-        return ! (
3079
-            $this->getShowDatetimeSelector() === EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR
3080
-            || (
3081
-                $this->getShowDatetimeSelector() === EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR
3082
-                && count($datetimes) < $this->getDatetimeSelectorThreshold()
3083
-            )
3084
-        );
3085
-    }
3086
-
3087
-
3088
-    /**
3089
-     * @return string
3090
-     */
3091
-    public function getShowDatetimeSelector()
3092
-    {
3093
-        return $this->show_datetime_selector;
3094
-    }
3095
-
3096
-
3097
-    /**
3098
-     * @param bool $keys_only
3099
-     * @return array
3100
-     */
3101
-    public function getShowDatetimeSelectorOptions($keys_only = true)
3102
-    {
3103
-        return $keys_only
3104
-            ? array(
3105
-                EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR,
3106
-                EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR,
3107
-            )
3108
-            : array(
3109
-                EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR => esc_html__(
3110
-                    'Do not show date & time filter',
3111
-                    'event_espresso'
3112
-                ),
3113
-                EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR  => esc_html__(
3114
-                    'Maybe show date & time filter',
3115
-                    'event_espresso'
3116
-                ),
3117
-            );
3118
-    }
3119
-
3120
-
3121
-    /**
3122
-     * @param string $show_datetime_selector
3123
-     */
3124
-    public function setShowDatetimeSelector($show_datetime_selector)
3125
-    {
3126
-        $this->show_datetime_selector = in_array(
3127
-            $show_datetime_selector,
3128
-            $this->getShowDatetimeSelectorOptions(),
3129
-            true
3130
-        )
3131
-            ? $show_datetime_selector
3132
-            : EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR;
3133
-    }
3134
-
3135
-
3136
-    /**
3137
-     * @return int
3138
-     */
3139
-    public function getDatetimeSelectorThreshold()
3140
-    {
3141
-        return $this->datetime_selector_threshold;
3142
-    }
3143
-
3144
-
3145
-    /**
3146
-     * @param int $datetime_selector_threshold
3147
-     */
3148
-    public function setDatetimeSelectorThreshold($datetime_selector_threshold)
3149
-    {
3150
-        $datetime_selector_threshold = absint($datetime_selector_threshold);
3151
-        $this->datetime_selector_threshold = $datetime_selector_threshold ? $datetime_selector_threshold : 3;
3152
-    }
3153
-
3154
-
3155
-    /**
3156
-     * @return int
3157
-     */
3158
-    public function getDatetimeSelectorMaxChecked()
3159
-    {
3160
-        return $this->datetime_selector_max_checked;
3161
-    }
3162
-
3163
-
3164
-    /**
3165
-     * @param int $datetime_selector_max_checked
3166
-     */
3167
-    public function setDatetimeSelectorMaxChecked($datetime_selector_max_checked)
3168
-    {
3169
-        $this->datetime_selector_max_checked = absint($datetime_selector_max_checked);
3170
-    }
3005
+	/**
3006
+	 * constant to indicate that a datetime selector should NEVER be shown for ticket selectors
3007
+	 */
3008
+	const DO_NOT_SHOW_DATETIME_SELECTOR = 'no_datetime_selector';
3009
+
3010
+	/**
3011
+	 * constant to indicate that a datetime selector should only be shown for ticket selectors
3012
+	 * when the number of datetimes for the event matches the value set for $datetime_selector_threshold
3013
+	 */
3014
+	const MAYBE_SHOW_DATETIME_SELECTOR = 'maybe_datetime_selector';
3015
+
3016
+	/**
3017
+	 * @var boolean $show_ticket_sale_columns
3018
+	 */
3019
+	public $show_ticket_sale_columns;
3020
+
3021
+	/**
3022
+	 * @var boolean $show_ticket_details
3023
+	 */
3024
+	public $show_ticket_details;
3025
+
3026
+	/**
3027
+	 * @var boolean $show_expired_tickets
3028
+	 */
3029
+	public $show_expired_tickets;
3030
+
3031
+	/**
3032
+	 * whether or not to display a dropdown box populated with event datetimes
3033
+	 * that toggles which tickets are displayed for a ticket selector.
3034
+	 * uses one of the *_DATETIME_SELECTOR constants defined above
3035
+	 *
3036
+	 * @var string $show_datetime_selector
3037
+	 */
3038
+	private $show_datetime_selector = 'no_datetime_selector';
3039
+
3040
+	/**
3041
+	 * the number of datetimes an event has to have before conditionally displaying a datetime selector
3042
+	 *
3043
+	 * @var int $datetime_selector_threshold
3044
+	 */
3045
+	private $datetime_selector_threshold = 3;
3046
+
3047
+	/**
3048
+	 * determines the maximum number of "checked" dates in the date and time filter
3049
+	 *
3050
+	 * @var int $datetime_selector_checked
3051
+	 */
3052
+	private $datetime_selector_max_checked = 10;
3053
+
3054
+
3055
+	/**
3056
+	 *    class constructor
3057
+	 */
3058
+	public function __construct()
3059
+	{
3060
+		$this->show_ticket_sale_columns = true;
3061
+		$this->show_ticket_details = true;
3062
+		$this->show_expired_tickets = true;
3063
+		$this->show_datetime_selector = EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR;
3064
+		$this->datetime_selector_threshold = 3;
3065
+		$this->datetime_selector_max_checked = 10;
3066
+	}
3067
+
3068
+
3069
+	/**
3070
+	 * returns true if a datetime selector should be displayed
3071
+	 *
3072
+	 * @param array $datetimes
3073
+	 * @return bool
3074
+	 */
3075
+	public function showDatetimeSelector(array $datetimes)
3076
+	{
3077
+		// if the settings are NOT: don't show OR below threshold, THEN active = true
3078
+		return ! (
3079
+			$this->getShowDatetimeSelector() === EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR
3080
+			|| (
3081
+				$this->getShowDatetimeSelector() === EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR
3082
+				&& count($datetimes) < $this->getDatetimeSelectorThreshold()
3083
+			)
3084
+		);
3085
+	}
3086
+
3087
+
3088
+	/**
3089
+	 * @return string
3090
+	 */
3091
+	public function getShowDatetimeSelector()
3092
+	{
3093
+		return $this->show_datetime_selector;
3094
+	}
3095
+
3096
+
3097
+	/**
3098
+	 * @param bool $keys_only
3099
+	 * @return array
3100
+	 */
3101
+	public function getShowDatetimeSelectorOptions($keys_only = true)
3102
+	{
3103
+		return $keys_only
3104
+			? array(
3105
+				EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR,
3106
+				EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR,
3107
+			)
3108
+			: array(
3109
+				EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR => esc_html__(
3110
+					'Do not show date & time filter',
3111
+					'event_espresso'
3112
+				),
3113
+				EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR  => esc_html__(
3114
+					'Maybe show date & time filter',
3115
+					'event_espresso'
3116
+				),
3117
+			);
3118
+	}
3119
+
3120
+
3121
+	/**
3122
+	 * @param string $show_datetime_selector
3123
+	 */
3124
+	public function setShowDatetimeSelector($show_datetime_selector)
3125
+	{
3126
+		$this->show_datetime_selector = in_array(
3127
+			$show_datetime_selector,
3128
+			$this->getShowDatetimeSelectorOptions(),
3129
+			true
3130
+		)
3131
+			? $show_datetime_selector
3132
+			: EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR;
3133
+	}
3134
+
3135
+
3136
+	/**
3137
+	 * @return int
3138
+	 */
3139
+	public function getDatetimeSelectorThreshold()
3140
+	{
3141
+		return $this->datetime_selector_threshold;
3142
+	}
3143
+
3144
+
3145
+	/**
3146
+	 * @param int $datetime_selector_threshold
3147
+	 */
3148
+	public function setDatetimeSelectorThreshold($datetime_selector_threshold)
3149
+	{
3150
+		$datetime_selector_threshold = absint($datetime_selector_threshold);
3151
+		$this->datetime_selector_threshold = $datetime_selector_threshold ? $datetime_selector_threshold : 3;
3152
+	}
3153
+
3154
+
3155
+	/**
3156
+	 * @return int
3157
+	 */
3158
+	public function getDatetimeSelectorMaxChecked()
3159
+	{
3160
+		return $this->datetime_selector_max_checked;
3161
+	}
3162
+
3163
+
3164
+	/**
3165
+	 * @param int $datetime_selector_max_checked
3166
+	 */
3167
+	public function setDatetimeSelectorMaxChecked($datetime_selector_max_checked)
3168
+	{
3169
+		$this->datetime_selector_max_checked = absint($datetime_selector_max_checked);
3170
+	}
3171 3171
 }
3172 3172
 
3173 3173
 /**
@@ -3179,87 +3179,87 @@  discard block
 block discarded – undo
3179 3179
  */
3180 3180
 class EE_Environment_Config extends EE_Config_Base
3181 3181
 {
3182
-    /**
3183
-     * Hold any php environment variables that we want to track.
3184
-     *
3185
-     * @var stdClass;
3186
-     */
3187
-    public $php;
3188
-
3189
-
3190
-    /**
3191
-     *    constructor
3192
-     */
3193
-    public function __construct()
3194
-    {
3195
-        $this->php = new stdClass();
3196
-        $this->_set_php_values();
3197
-    }
3198
-
3199
-
3200
-    /**
3201
-     * This sets the php environment variables.
3202
-     *
3203
-     * @since 4.4.0
3204
-     * @return void
3205
-     */
3206
-    protected function _set_php_values()
3207
-    {
3208
-        $this->php->max_input_vars = ini_get('max_input_vars');
3209
-        $this->php->version = phpversion();
3210
-    }
3211
-
3212
-
3213
-    /**
3214
-     * helper method for determining whether input_count is
3215
-     * reaching the potential maximum the server can handle
3216
-     * according to max_input_vars
3217
-     *
3218
-     * @param int   $input_count the count of input vars.
3219
-     * @return array {
3220
-     *                           An array that represents whether available space and if no available space the error
3221
-     *                           message.
3222
-     * @type bool   $has_space   whether more inputs can be added.
3223
-     * @type string $msg         Any message to be displayed.
3224
-     *                           }
3225
-     */
3226
-    public function max_input_vars_limit_check($input_count = 0)
3227
-    {
3228
-        if (
3229
-            ! empty($this->php->max_input_vars)
3230
-            && ($input_count >= $this->php->max_input_vars)
3231
-        ) {
3232
-            // check the server setting because the config value could be stale
3233
-            $max_input_vars = ini_get('max_input_vars');
3234
-            if ($input_count >= $max_input_vars) {
3235
-                return sprintf(
3236
-                    esc_html__(
3237
-                        'The maximum number of inputs on this page has been exceeded. You cannot make edits to this page because of your server\'s PHP "max_input_vars" setting.%1$sThere are %2$d inputs and the maximum amount currently allowed by your server is %3$d.%1$sPlease contact your web host and ask them to raise the "max_input_vars" limit.',
3238
-                        'event_espresso'
3239
-                    ),
3240
-                    '<br>',
3241
-                    $input_count,
3242
-                    $max_input_vars
3243
-                );
3244
-            } else {
3245
-                return '';
3246
-            }
3247
-        } else {
3248
-            return '';
3249
-        }
3250
-    }
3251
-
3252
-
3253
-    /**
3254
-     * The purpose of this method is just to force rechecking php values so if they've changed, they get updated.
3255
-     *
3256
-     * @since 4.4.1
3257
-     * @return void
3258
-     */
3259
-    public function recheck_values()
3260
-    {
3261
-        $this->_set_php_values();
3262
-    }
3182
+	/**
3183
+	 * Hold any php environment variables that we want to track.
3184
+	 *
3185
+	 * @var stdClass;
3186
+	 */
3187
+	public $php;
3188
+
3189
+
3190
+	/**
3191
+	 *    constructor
3192
+	 */
3193
+	public function __construct()
3194
+	{
3195
+		$this->php = new stdClass();
3196
+		$this->_set_php_values();
3197
+	}
3198
+
3199
+
3200
+	/**
3201
+	 * This sets the php environment variables.
3202
+	 *
3203
+	 * @since 4.4.0
3204
+	 * @return void
3205
+	 */
3206
+	protected function _set_php_values()
3207
+	{
3208
+		$this->php->max_input_vars = ini_get('max_input_vars');
3209
+		$this->php->version = phpversion();
3210
+	}
3211
+
3212
+
3213
+	/**
3214
+	 * helper method for determining whether input_count is
3215
+	 * reaching the potential maximum the server can handle
3216
+	 * according to max_input_vars
3217
+	 *
3218
+	 * @param int   $input_count the count of input vars.
3219
+	 * @return array {
3220
+	 *                           An array that represents whether available space and if no available space the error
3221
+	 *                           message.
3222
+	 * @type bool   $has_space   whether more inputs can be added.
3223
+	 * @type string $msg         Any message to be displayed.
3224
+	 *                           }
3225
+	 */
3226
+	public function max_input_vars_limit_check($input_count = 0)
3227
+	{
3228
+		if (
3229
+			! empty($this->php->max_input_vars)
3230
+			&& ($input_count >= $this->php->max_input_vars)
3231
+		) {
3232
+			// check the server setting because the config value could be stale
3233
+			$max_input_vars = ini_get('max_input_vars');
3234
+			if ($input_count >= $max_input_vars) {
3235
+				return sprintf(
3236
+					esc_html__(
3237
+						'The maximum number of inputs on this page has been exceeded. You cannot make edits to this page because of your server\'s PHP "max_input_vars" setting.%1$sThere are %2$d inputs and the maximum amount currently allowed by your server is %3$d.%1$sPlease contact your web host and ask them to raise the "max_input_vars" limit.',
3238
+						'event_espresso'
3239
+					),
3240
+					'<br>',
3241
+					$input_count,
3242
+					$max_input_vars
3243
+				);
3244
+			} else {
3245
+				return '';
3246
+			}
3247
+		} else {
3248
+			return '';
3249
+		}
3250
+	}
3251
+
3252
+
3253
+	/**
3254
+	 * The purpose of this method is just to force rechecking php values so if they've changed, they get updated.
3255
+	 *
3256
+	 * @since 4.4.1
3257
+	 * @return void
3258
+	 */
3259
+	public function recheck_values()
3260
+	{
3261
+		$this->_set_php_values();
3262
+	}
3263 3263
 }
3264 3264
 
3265 3265
 /**
@@ -3271,21 +3271,21 @@  discard block
 block discarded – undo
3271 3271
  */
3272 3272
 class EE_Tax_Config extends EE_Config_Base
3273 3273
 {
3274
-    /*
3274
+	/*
3275 3275
      * flag to indicate whether or not to display ticket prices with the taxes included
3276 3276
      *
3277 3277
      * @var boolean $prices_displayed_including_taxes
3278 3278
      */
3279
-    public $prices_displayed_including_taxes;
3279
+	public $prices_displayed_including_taxes;
3280 3280
 
3281 3281
 
3282
-    /**
3283
-     *    class constructor
3284
-     */
3285
-    public function __construct()
3286
-    {
3287
-        $this->prices_displayed_including_taxes = true;
3288
-    }
3282
+	/**
3283
+	 *    class constructor
3284
+	 */
3285
+	public function __construct()
3286
+	{
3287
+		$this->prices_displayed_including_taxes = true;
3288
+	}
3289 3289
 }
3290 3290
 
3291 3291
 /**
@@ -3298,19 +3298,19 @@  discard block
 block discarded – undo
3298 3298
  */
3299 3299
 class EE_Messages_Config extends EE_Config_Base
3300 3300
 {
3301
-    /**
3302
-     * This is an integer representing the deletion threshold in months for when old messages will get deleted.
3303
-     * A value of 0 represents never deleting.  Default is 0.
3304
-     *
3305
-     * @var integer
3306
-     */
3307
-    public $delete_threshold;
3308
-
3309
-
3310
-    public function __construct()
3311
-    {
3312
-        $this->delete_threshold = 0;
3313
-    }
3301
+	/**
3302
+	 * This is an integer representing the deletion threshold in months for when old messages will get deleted.
3303
+	 * A value of 0 represents never deleting.  Default is 0.
3304
+	 *
3305
+	 * @var integer
3306
+	 */
3307
+	public $delete_threshold;
3308
+
3309
+
3310
+	public function __construct()
3311
+	{
3312
+		$this->delete_threshold = 0;
3313
+	}
3314 3314
 }
3315 3315
 
3316 3316
 /**
@@ -3320,31 +3320,31 @@  discard block
 block discarded – undo
3320 3320
  */
3321 3321
 class EE_Gateway_Config extends EE_Config_Base
3322 3322
 {
3323
-    /**
3324
-     * Array with keys that are payment gateways slugs, and values are arrays
3325
-     * with any config info the gateway wants to store
3326
-     *
3327
-     * @var array
3328
-     */
3329
-    public $payment_settings;
3330
-
3331
-    /**
3332
-     * Where keys are gateway slugs, and values are booleans indicating whether or not
3333
-     * the gateway is stored in the uploads directory
3334
-     *
3335
-     * @var array
3336
-     */
3337
-    public $active_gateways;
3338
-
3339
-
3340
-    /**
3341
-     *    class constructor
3342
-     *
3343
-     * @deprecated
3344
-     */
3345
-    public function __construct()
3346
-    {
3347
-        $this->payment_settings = array();
3348
-        $this->active_gateways = array('Invoice' => false);
3349
-    }
3323
+	/**
3324
+	 * Array with keys that are payment gateways slugs, and values are arrays
3325
+	 * with any config info the gateway wants to store
3326
+	 *
3327
+	 * @var array
3328
+	 */
3329
+	public $payment_settings;
3330
+
3331
+	/**
3332
+	 * Where keys are gateway slugs, and values are booleans indicating whether or not
3333
+	 * the gateway is stored in the uploads directory
3334
+	 *
3335
+	 * @var array
3336
+	 */
3337
+	public $active_gateways;
3338
+
3339
+
3340
+	/**
3341
+	 *    class constructor
3342
+	 *
3343
+	 * @deprecated
3344
+	 */
3345
+	public function __construct()
3346
+	{
3347
+		$this->payment_settings = array();
3348
+		$this->active_gateways = array('Invoice' => false);
3349
+	}
3350 3350
 }
Please login to merge, or discard this patch.
core/EE_Payment_Processor.core.php 1 patch
Indentation   +860 added lines, -860 removed lines patch added patch discarded remove patch
@@ -19,864 +19,864 @@
 block discarded – undo
19 19
  */
20 20
 class EE_Payment_Processor extends EE_Processor_Base implements ResettableInterface
21 21
 {
22
-    /**
23
-     * @var CurrencyFormatter
24
-     * @since $VID:$
25
-     */
26
-    protected $currency_formatter;
27
-
28
-    /**
29
-     * @var EE_Payment_Processor $_instance
30
-     */
31
-    private static $_instance;
32
-
33
-
34
-    /**
35
-     * @singleton method used to instantiate class object
36
-     * @return EE_Payment_Processor instance
37
-     */
38
-    public static function instance()
39
-    {
40
-        // check if class object is instantiated
41
-        if (! self::$_instance instanceof EE_Payment_Processor) {
42
-            self::$_instance = new self();
43
-        }
44
-        return self::$_instance;
45
-    }
46
-
47
-
48
-    /**
49
-     * @return EE_Payment_Processor
50
-     */
51
-    public static function reset()
52
-    {
53
-        self::$_instance = null;
54
-        return self::instance();
55
-    }
56
-
57
-
58
-    /**
59
-     *private constructor to prevent direct creation
60
-     */
61
-    private function __construct()
62
-    {
63
-        do_action('AHEE__EE_Payment_Processor__construct');
64
-        add_action('http_api_curl', [$this, '_curl_requests_to_paypal_use_tls'], 10, 3);
65
-        // in a better world this would have been injected upon construction
66
-        if (! $this->currency_formatter instanceof CurrencyFormatter) {
67
-            $this->currency_formatter = LoaderFactory::getLoader()->getShared(CurrencyFormatter::class);
68
-        }
69
-    }
70
-
71
-
72
-    /**
73
-     * Using the selected gateway, processes the payment for that transaction, and updates the transaction
74
-     * appropriately. Saves the payment that is generated
75
-     *
76
-     * @param EE_Payment_Method    $payment_method
77
-     * @param EE_Transaction       $transaction
78
-     * @param float                $amount       if only part of the transaction is to be paid for, how much.
79
-     *                                           Leave null if payment is for the full amount owing
80
-     * @param EE_Billing_Info_Form $billing_form (or probably null, if it's an offline or offsite payment method).
81
-     *                                           Receive_form_submission() should have
82
-     *                                           already been called on the billing form
83
-     *                                           (ie, its inputs should have their normalized values set).
84
-     * @param string               $return_url   string used mostly by offsite gateways to specify
85
-     *                                           where to go AFTER the offsite gateway
86
-     * @param string               $method       like 'CART', indicates who the client who called this was
87
-     * @param bool                 $by_admin     TRUE if payment is being attempted from the admin
88
-     * @param boolean              $update_txn   whether or not to call
89
-     *                                           EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
90
-     * @param string               $cancel_url   URL to return to if off-site payments are cancelled
91
-     * @return EE_Payment
92
-     * @throws EE_Error
93
-     * @throws InvalidArgumentException
94
-     * @throws ReflectionException
95
-     * @throws RuntimeException
96
-     * @throws InvalidDataTypeException
97
-     * @throws InvalidInterfaceException
98
-     */
99
-    public function process_payment(
100
-        EE_Payment_Method $payment_method,
101
-        EE_Transaction $transaction,
102
-        $amount = null,
103
-        $billing_form = null,
104
-        $return_url = null,
105
-        $method = 'CART',
106
-        $by_admin = false,
107
-        $update_txn = true,
108
-        $cancel_url = ''
109
-    ) {
110
-        $amount = (float) $amount;
111
-        if ($amount < 0) {
112
-            throw new EE_Error(
113
-                sprintf(
114
-                    esc_html__(
115
-                        'Attempting to make a payment for a negative amount of %1$d for transaction %2$d. That should be a refund',
116
-                        'event_espresso'
117
-                    ),
118
-                    $amount,
119
-                    $transaction->ID()
120
-                )
121
-            );
122
-        }
123
-        // verify payment method
124
-        $payment_method = EEM_Payment_Method::instance()->ensure_is_obj(
125
-            $payment_method,
126
-            true
127
-        );
128
-        // verify transaction
129
-        EEM_Transaction::instance()->ensure_is_obj($transaction);
130
-        $transaction->set_payment_method_ID($payment_method->ID());
131
-        $amount    = (float) $this->currency_formatter->formatForLocale(
132
-            $amount,
133
-            CurrencyFormatter::FORMAT_LOCALIZED_FLOAT
134
-        );
135
-        $remaining = (float) $transaction->prettyRemaining('localized_float');
136
-        // verify payment method type
137
-        if ($payment_method->type_obj() instanceof EE_PMT_Base) {
138
-            $payment = $payment_method->type_obj()->process_payment(
139
-                $transaction,
140
-                min($amount, $remaining), // make sure we don't overcharge
141
-                $billing_form,
142
-                $return_url,
143
-                add_query_arg(['ee_cancel_payment' => true], $cancel_url),
144
-                $method,
145
-                $by_admin
146
-            );
147
-            // check if payment method uses an off-site gateway
148
-            if ($payment_method->type_obj()->payment_occurs() !== EE_PMT_Base::offsite) {
149
-                // don't process payments for off-site gateways yet because no payment has occurred yet
150
-                $this->update_txn_based_on_payment($transaction, $payment, $update_txn);
151
-            }
152
-            return $payment;
153
-        }
154
-        EE_Error::add_error(
155
-            sprintf(
156
-                esc_html__(
157
-                    'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
158
-                    'event_espresso'
159
-                ),
160
-                '<br/>',
161
-                EE_Registry::instance()->CFG->organization->get_pretty('email')
162
-            ),
163
-            __FILE__,
164
-            __FUNCTION__,
165
-            __LINE__
166
-        );
167
-        return null;
168
-    }
169
-
170
-
171
-    /**
172
-     * @param EE_Transaction|int $transaction
173
-     * @param EE_Payment_Method  $payment_method
174
-     * @return string
175
-     * @throws EE_Error
176
-     * @throws InvalidArgumentException
177
-     * @throws InvalidDataTypeException
178
-     * @throws InvalidInterfaceException
179
-     * @throws ReflectionException
180
-     */
181
-    public function get_ipn_url_for_payment_method($transaction, $payment_method)
182
-    {
183
-        /** @type EE_Transaction $transaction */
184
-        $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
185
-        $primary_reg = $transaction->primary_registration();
186
-        if (! $primary_reg instanceof EE_Registration) {
187
-            throw new EE_Error(
188
-                sprintf(
189
-                    esc_html__(
190
-                        'Cannot get IPN URL for transaction with ID %d because it has no primary registration',
191
-                        'event_espresso'
192
-                    ),
193
-                    $transaction->ID()
194
-                )
195
-            );
196
-        }
197
-        $payment_method = EEM_Payment_Method::instance()->ensure_is_obj(
198
-            $payment_method,
199
-            true
200
-        );
201
-        return add_query_arg(
202
-            [
203
-                'e_reg_url_link'    => $primary_reg->reg_url_link(),
204
-                'ee_payment_method' => $payment_method->slug(),
205
-            ],
206
-            EE_Registry::instance()->CFG->core->txn_page_url()
207
-        );
208
-    }
209
-
210
-
211
-    /**
212
-     * Process the IPN. Firstly, we'll hope we put the standard args into the IPN URL so
213
-     * we can easily find what registration the IPN is for and what payment method.
214
-     * However, if not, we'll give all payment methods a chance to claim it and process it.
215
-     * If a payment is found for the IPN info, it is saved.
216
-     *
217
-     * @param array              $_req_data            form post data
218
-     * @param EE_Transaction|int $transaction          optional (or a transactions id)
219
-     * @param EE_Payment_Method  $payment_method       (or a slug or id of one)
220
-     * @param boolean            $update_txn           whether or not to call
221
-     *                                                 EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
222
-     * @param bool               $separate_IPN_request whether the IPN uses a separate request (true, like PayPal)
223
-     *                                                 or is processed manually (false, like Authorize.net)
224
-     * @return EE_Payment
225
-     * @throws EE_Error
226
-     * @throws Exception
227
-     * @throws RuntimeException
228
-     * @throws ReflectionException
229
-     * @throws InvalidArgumentException
230
-     * @throws InvalidInterfaceException
231
-     * @throws InvalidDataTypeException
232
-     */
233
-    public function process_ipn(
234
-        $_req_data,
235
-        $transaction = null,
236
-        $payment_method = null,
237
-        $update_txn = true,
238
-        $separate_IPN_request = true
239
-    ) {
240
-        EE_Registry::instance()->load_model('Change_Log');
241
-        $_req_data = $this->_remove_unusable_characters_from_array((array) $_req_data);
242
-        EE_Processor_Base::set_IPN($separate_IPN_request);
243
-        $obj_for_log = null;
244
-        if ($transaction instanceof EE_Transaction) {
245
-            $obj_for_log = $transaction;
246
-            if ($payment_method instanceof EE_Payment_Method) {
247
-                $obj_for_log = EEM_Payment::instance()->get_one(
248
-                    [
249
-                        ['TXN_ID' => $transaction->ID(), 'PMD_ID' => $payment_method->ID()],
250
-                        'order_by' => ['PAY_timestamp' => 'desc'],
251
-                    ]
252
-                );
253
-            }
254
-        } elseif ($payment_method instanceof EE_Payment) {
255
-            $obj_for_log = $payment_method;
256
-        }
257
-        $log = EEM_Change_Log::instance()->log(
258
-            EEM_Change_Log::type_gateway,
259
-            ['IPN data received' => $_req_data],
260
-            $obj_for_log
261
-        );
262
-        try {
263
-            /**
264
-             * @var EE_Payment $payment
265
-             */
266
-            $payment = null;
267
-            if ($transaction && $payment_method) {
268
-                /** @type EE_Transaction $transaction */
269
-                $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
270
-                /** @type EE_Payment_Method $payment_method */
271
-                $payment_method = EEM_Payment_Method::instance()->ensure_is_obj($payment_method);
272
-                if ($payment_method->type_obj() instanceof EE_PMT_Base) {
273
-                    try {
274
-                        $payment = $payment_method->type_obj()->handle_ipn($_req_data, $transaction);
275
-                        $log->set_object($payment);
276
-                    } catch (EventEspresso\core\exceptions\IpnException $e) {
277
-                        EEM_Change_Log::instance()->log(
278
-                            EEM_Change_Log::type_gateway,
279
-                            [
280
-                                'message'     => 'IPN Exception: ' . $e->getMessage(),
281
-                                'current_url' => EEH_URL::current_url(),
282
-                                'payment'     => $e->getPaymentProperties(),
283
-                                'IPN_data'    => $e->getIpnData(),
284
-                            ],
285
-                            $obj_for_log
286
-                        );
287
-                        return $e->getPayment();
288
-                    }
289
-                } else {
290
-                    // not a payment
291
-                    EE_Error::add_error(
292
-                        sprintf(
293
-                            esc_html__(
294
-                                'A valid payment method could not be determined due to a technical issue.%sPlease refresh your browser and try again or contact %s for assistance.',
295
-                                'event_espresso'
296
-                            ),
297
-                            '<br/>',
298
-                            EE_Registry::instance()->CFG->organization->get_pretty('email')
299
-                        ),
300
-                        __FILE__,
301
-                        __FUNCTION__,
302
-                        __LINE__
303
-                    );
304
-                }
305
-            } else {
306
-                // that's actually pretty ok. The IPN just wasn't able
307
-                // to identify which transaction or payment method this was for
308
-                // give all active payment methods a chance to claim it
309
-                $active_payment_methods = EEM_Payment_Method::instance()->get_all_active();
310
-                foreach ($active_payment_methods as $active_payment_method) {
311
-                    try {
312
-                        $payment        = $active_payment_method->type_obj()->handle_unclaimed_ipn($_req_data);
313
-                        $payment_method = $active_payment_method;
314
-                        EEM_Change_Log::instance()->log(
315
-                            EEM_Change_Log::type_gateway,
316
-                            ['IPN data' => $_req_data],
317
-                            $payment
318
-                        );
319
-                        break;
320
-                    } catch (EventEspresso\core\exceptions\IpnException $e) {
321
-                        EEM_Change_Log::instance()->log(
322
-                            EEM_Change_Log::type_gateway,
323
-                            [
324
-                                'message'     => 'IPN Exception: ' . $e->getMessage(),
325
-                                'current_url' => EEH_URL::current_url(),
326
-                                'payment'     => $e->getPaymentProperties(),
327
-                                'IPN_data'    => $e->getIpnData(),
328
-                            ],
329
-                            $obj_for_log
330
-                        );
331
-                        return $e->getPayment();
332
-                    } catch (EE_Error $e) {
333
-                        // that's fine- it apparently couldn't handle the IPN
334
-                    }
335
-                }
336
-            }
337
-            // EEM_Payment_Log::instance()->log("got to 7",$transaction,$payment_method);
338
-            if ($payment instanceof EE_Payment) {
339
-                $payment->save();
340
-                //  update the TXN
341
-                $this->update_txn_based_on_payment(
342
-                    $transaction,
343
-                    $payment,
344
-                    $update_txn,
345
-                    $separate_IPN_request
346
-                );
347
-            } else {
348
-                // we couldn't find the payment for this IPN... let's try and log at least SOMETHING
349
-                if ($payment_method) {
350
-                    EEM_Change_Log::instance()->log(
351
-                        EEM_Change_Log::type_gateway,
352
-                        ['IPN data' => $_req_data],
353
-                        $payment_method
354
-                    );
355
-                } elseif ($transaction) {
356
-                    EEM_Change_Log::instance()->log(
357
-                        EEM_Change_Log::type_gateway,
358
-                        ['IPN data' => $_req_data],
359
-                        $transaction
360
-                    );
361
-                }
362
-            }
363
-            return $payment;
364
-        } catch (EE_Error $e) {
365
-            do_action(
366
-                'AHEE__log',
367
-                __FILE__,
368
-                __FUNCTION__,
369
-                sprintf(
370
-                    esc_html__(
371
-                        'Error occurred while receiving IPN. Transaction: %1$s, req data: %2$s. The error was "%3$s"',
372
-                        'event_espresso'
373
-                    ),
374
-                    print_r($transaction, true),
375
-                    print_r($_req_data, true),
376
-                    $e->getMessage()
377
-                )
378
-            );
379
-            throw $e;
380
-        }
381
-    }
382
-
383
-
384
-    /**
385
-     * Removes any non-printable illegal characters from the input,
386
-     * which might cause a raucous when trying to insert into the database
387
-     *
388
-     * @param array $request_data
389
-     * @return array
390
-     */
391
-    protected function _remove_unusable_characters_from_array(array $request_data)
392
-    {
393
-        $return_data = [];
394
-        foreach ($request_data as $key => $value) {
395
-            $return_data[ $this->_remove_unusable_characters($key) ] = $this->_remove_unusable_characters(
396
-                $value
397
-            );
398
-        }
399
-        return $return_data;
400
-    }
401
-
402
-
403
-    /**
404
-     * Removes any non-printable illegal characters from the input,
405
-     * which might cause a raucous when trying to insert into the database
406
-     *
407
-     * @param string $request_data
408
-     * @return string
409
-     */
410
-    protected function _remove_unusable_characters($request_data)
411
-    {
412
-        return preg_replace('/[^[:print:]]/', '', $request_data);
413
-    }
414
-
415
-
416
-    /**
417
-     * Should be called just before displaying the payment attempt results to the user,
418
-     * when the payment attempt has finished. Some payment methods may have special
419
-     * logic to perform here. For example, if process_payment() happens on a special request
420
-     * and then the user is redirected to a page that displays the payment's status, this
421
-     * should be called while loading the page that displays the payment's status. If the user is
422
-     * sent to an offsite payment provider, this should be called upon returning from that offsite payment
423
-     * provider.
424
-     *
425
-     * @param EE_Transaction|int $transaction
426
-     * @param bool               $update_txn whether or not to call
427
-     *                                       EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
428
-     * @return EE_Payment
429
-     * @throws EE_Error
430
-     * @throws InvalidArgumentException
431
-     * @throws ReflectionException
432
-     * @throws RuntimeException
433
-     * @throws InvalidDataTypeException
434
-     * @throws InvalidInterfaceException
435
-     * @deprecated 4.6.24 method is no longer used. Instead it is up to client code, like SPCO,
436
-     *                                       to call handle_ipn() for offsite gateways that don't receive separate IPNs
437
-     */
438
-    public function finalize_payment_for($transaction, $update_txn = true)
439
-    {
440
-        /** @var $transaction EE_Transaction */
441
-        $transaction         = EEM_Transaction::instance()->ensure_is_obj($transaction);
442
-        $last_payment_method = $transaction->payment_method();
443
-        if ($last_payment_method instanceof EE_Payment_Method) {
444
-            $payment = $last_payment_method->type_obj()->finalize_payment_for($transaction);
445
-            $this->update_txn_based_on_payment($transaction, $payment, $update_txn);
446
-            return $payment;
447
-        }
448
-        return null;
449
-    }
450
-
451
-
452
-    /**
453
-     * Processes a direct refund request, saves the payment, and updates the transaction appropriately.
454
-     *
455
-     * @param EE_Payment_Method $payment_method
456
-     * @param EE_Payment        $payment_to_refund
457
-     * @param array             $refund_info
458
-     * @return EE_Payment
459
-     * @throws EE_Error
460
-     * @throws InvalidArgumentException
461
-     * @throws ReflectionException
462
-     * @throws RuntimeException
463
-     * @throws InvalidDataTypeException
464
-     * @throws InvalidInterfaceException
465
-     */
466
-    public function process_refund(
467
-        EE_Payment_Method $payment_method,
468
-        EE_Payment $payment_to_refund,
469
-        array $refund_info = []
470
-    ) {
471
-        if ($payment_method instanceof EE_Payment_Method && $payment_method->type_obj()->supports_sending_refunds()) {
472
-            $payment_method->type_obj()->process_refund($payment_to_refund, $refund_info);
473
-            $this->update_txn_based_on_payment($payment_to_refund->transaction(), $payment_to_refund);
474
-        }
475
-        return $payment_to_refund;
476
-    }
477
-
478
-
479
-    /**
480
-     * This should be called each time there may have been an update to a
481
-     * payment on a transaction (ie, we asked for a payment to process a
482
-     * payment for a transaction, or we told a payment method about an IPN, or
483
-     * we told a payment method to
484
-     * "finalize_payment_for" (a transaction), or we told a payment method to
485
-     * process a refund. This should handle firing the correct hooks to
486
-     * indicate
487
-     * what exactly happened and updating the transaction appropriately). This
488
-     * could be integrated directly into EE_Transaction upon save, but we want
489
-     * this logic to be separate from 'normal' plain-jane saving and updating
490
-     * of transactions and payments, and to be tied to payment processing.
491
-     * Note: this method DOES NOT save the payment passed into it. It is the responsibility
492
-     * of previous code to decide whether or not to save (because the payment passed into
493
-     * this method might be a temporary, never-to-be-saved payment from an offline gateway,
494
-     * in which case we only want that payment object for some temporary usage during this request,
495
-     * but we don't want it to be saved).
496
-     *
497
-     * @param EE_Transaction|int $transaction
498
-     * @param EE_Payment         $payment
499
-     * @param boolean            $update_txn
500
-     *                        whether or not to call
501
-     *                        EE_Transaction_Processor::
502
-     *                        update_transaction_and_registrations_after_checkout_or_payment()
503
-     *                        (you can save 1 DB query if you know you're going
504
-     *                        to save it later instead)
505
-     * @param bool               $IPN
506
-     *                        if processing IPNs or other similar payment
507
-     *                        related activities that occur in alternate
508
-     *                        requests than the main one that is processing the
509
-     *                        TXN, then set this to true to check whether the
510
-     *                        TXN is locked before updating
511
-     * @throws EE_Error
512
-     * @throws InvalidArgumentException
513
-     * @throws ReflectionException
514
-     * @throws RuntimeException
515
-     * @throws InvalidDataTypeException
516
-     * @throws InvalidInterfaceException
517
-     */
518
-    public function update_txn_based_on_payment($transaction, $payment, $update_txn = true, $IPN = false)
519
-    {
520
-        $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__not_successful';
521
-        /** @type EE_Transaction $transaction */
522
-        $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
523
-        // can we freely update the TXN at this moment?
524
-        if ($IPN && $transaction->is_locked()) {
525
-            // don't update the transaction at this exact moment
526
-            // because the TXN is active in another request
527
-            EE_Cron_Tasks::schedule_update_transaction_with_payment(
528
-                time(),
529
-                $transaction->ID(),
530
-                $payment->ID()
531
-            );
532
-        } else {
533
-            // verify payment and that it has been saved
534
-            if ($payment instanceof EE_Payment && $payment->ID()) {
535
-                if (
536
-                    $payment->payment_method() instanceof EE_Payment_Method
537
-                    && $payment->payment_method()->type_obj() instanceof EE_PMT_Base
538
-                ) {
539
-                    $payment->payment_method()->type_obj()->update_txn_based_on_payment($payment);
540
-                    // update TXN registrations with payment info
541
-                    $this->process_registration_payments($transaction, $payment);
542
-                }
543
-                $do_action = $payment->just_approved()
544
-                    ? 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__successful'
545
-                    : $do_action;
546
-            } else {
547
-                // send out notifications
548
-                add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
549
-                $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__no_payment_made';
550
-            }
551
-            if ($payment instanceof EE_Payment && $payment->status() !== EEM_Payment::status_id_failed) {
552
-                /** @type EE_Transaction_Payments $transaction_payments */
553
-                $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
554
-                // set new value for total paid
555
-                $transaction_payments->calculate_total_payments_and_update_status($transaction);
556
-                // call EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() ???
557
-                if ($update_txn) {
558
-                    $this->_post_payment_processing($transaction, $payment, $IPN);
559
-                }
560
-            }
561
-            // granular hook for others to use.
562
-            do_action($do_action, $transaction, $payment);
563
-            do_action('AHEE_log', __CLASS__, __FUNCTION__, $do_action, '$do_action');
564
-            // global hook for others to use.
565
-            do_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', $transaction, $payment);
566
-        }
567
-    }
568
-
569
-
570
-    /**
571
-     * update registrations REG_paid field after successful payment and link registrations with payment
572
-     *
573
-     * @param EE_Transaction    $transaction
574
-     * @param EE_Payment        $payment
575
-     * @param EE_Registration[] $registrations
576
-     * @throws EE_Error
577
-     * @throws InvalidArgumentException
578
-     * @throws RuntimeException
579
-     * @throws InvalidDataTypeException
580
-     * @throws InvalidInterfaceException
581
-     * @throws ReflectionException
582
-     */
583
-    public function process_registration_payments(
584
-        EE_Transaction $transaction,
585
-        EE_Payment $payment,
586
-        array $registrations = []
587
-    ) {
588
-        // only process if payment was successful
589
-        if ($payment->status() !== EEM_Payment::status_id_approved) {
590
-            return;
591
-        }
592
-        // EEM_Registration::instance()->show_next_x_db_queries();
593
-        if (empty($registrations)) {
594
-            // find registrations with monies owing that can receive a payment
595
-            $registrations = $transaction->registrations(
596
-                [
597
-                    [
598
-                        // only these reg statuses can receive payments
599
-                        'STS_ID'           => ['IN', EEM_Registration::reg_statuses_that_allow_payment()],
600
-                        'REG_final_price'  => ['!=', 0],
601
-                        'REG_final_price*' => ['!=', 'REG_paid', true],
602
-                    ],
603
-                ]
604
-            );
605
-        }
606
-        // still nothing ??!??
607
-        if (empty($registrations)) {
608
-            return;
609
-        }
610
-        // todo: break out the following logic into a separate strategy class
611
-        // todo: named something like "Sequential_Reg_Payment_Strategy"
612
-        // todo: which would apply payments using the capitalist "first come first paid" approach
613
-        // todo: then have another strategy class like "Distributed_Reg_Payment_Strategy"
614
-        // todo: which would be the socialist "everybody gets a piece of pie" approach,
615
-        // todo: which would be better for deposits, where you want a bit of the payment applied to each registration
616
-        $refund = $payment->is_a_refund();
617
-        // how much is available to apply to registrations?
618
-        $available_payment_amount = abs($payment->amount());
619
-        foreach ($registrations as $registration) {
620
-            if ($registration instanceof EE_Registration) {
621
-                // nothing left?
622
-                if ($available_payment_amount <= 0) {
623
-                    break;
624
-                }
625
-                if ($refund) {
626
-                    $available_payment_amount = $this->process_registration_refund(
627
-                        $registration,
628
-                        $payment,
629
-                        $available_payment_amount
630
-                    );
631
-                } else {
632
-                    $available_payment_amount = $this->process_registration_payment(
633
-                        $registration,
634
-                        $payment,
635
-                        $available_payment_amount
636
-                    );
637
-                }
638
-            }
639
-        }
640
-        if (
641
-            $available_payment_amount > 0
642
-            && apply_filters(
643
-                'FHEE__EE_Payment_Processor__process_registration_payments__display_notifications',
644
-                false
645
-            )
646
-        ) {
647
-            EE_Error::add_attention(
648
-                sprintf(
649
-                    esc_html__(
650
-                        'A remainder of %1$s exists after applying this payment to Registration(s) %2$s.%3$sPlease verify that the original payment amount of %4$s is correct. If so, you should edit this payment and select at least one additional registration in the "Registrations to Apply Payment to" section, so that the remainder of this payment can be applied to the additional registration(s).',
651
-                        'event_espresso'
652
-                    ),
653
-                    $this->currency_formatter->formatForLocale($available_payment_amount),
654
-                    implode(', ', array_keys($registrations)),
655
-                    '<br/>',
656
-                    $payment->prettyAmount()
657
-                ),
658
-                __FILE__,
659
-                __FUNCTION__,
660
-                __LINE__
661
-            );
662
-        }
663
-    }
664
-
665
-
666
-    /**
667
-     * update registration REG_paid field after successful payment and link registration with payment
668
-     *
669
-     * @param EE_Registration $registration
670
-     * @param EE_Payment      $payment
671
-     * @param float           $available_payment_amount
672
-     * @return float
673
-     * @throws EE_Error
674
-     * @throws InvalidArgumentException
675
-     * @throws RuntimeException
676
-     * @throws InvalidDataTypeException
677
-     * @throws InvalidInterfaceException
678
-     * @throws ReflectionException
679
-     */
680
-    public function process_registration_payment(
681
-        EE_Registration $registration,
682
-        EE_Payment $payment,
683
-        $available_payment_amount = 0.00
684
-    ) {
685
-        $owing = $registration->amountOwing();
686
-        if ($owing > 0) {
687
-            // don't allow payment amount to exceed the available payment amount, OR the amount owing
688
-            $payment_amount = min($available_payment_amount, $owing);
689
-            // update $available_payment_amount
690
-            $available_payment_amount -= $payment_amount;
691
-            // calculate and set new REG_paid
692
-            $registration->set_paid($registration->paid() + $payment_amount);
693
-            // now save it
694
-            $this->_apply_registration_payment($registration, $payment, $payment_amount);
695
-        }
696
-        return $available_payment_amount;
697
-    }
698
-
699
-
700
-    /**
701
-     * update registration REG_paid field after successful payment and link registration with payment
702
-     *
703
-     * @param EE_Registration $registration
704
-     * @param EE_Payment      $payment
705
-     * @param float           $payment_amount
706
-     * @return void
707
-     * @throws EE_Error
708
-     * @throws InvalidArgumentException
709
-     * @throws InvalidDataTypeException
710
-     * @throws InvalidInterfaceException
711
-     * @throws ReflectionException
712
-     */
713
-    protected function _apply_registration_payment(
714
-        EE_Registration $registration,
715
-        EE_Payment $payment,
716
-        $payment_amount = 0.00
717
-    ) {
718
-        // find any existing reg payment records for this registration and payment
719
-        $existing_reg_payment = EEM_Registration_Payment::instance()->get_one(
720
-            [['REG_ID' => $registration->ID(), 'PAY_ID' => $payment->ID()]]
721
-        );
722
-        // if existing registration payment exists
723
-        if ($existing_reg_payment instanceof EE_Registration_Payment) {
724
-            // then update that record
725
-            $existing_reg_payment->set_amount($payment_amount);
726
-            $existing_reg_payment->save();
727
-        } else {
728
-            // or add new relation between registration and payment and set amount
729
-            $registration->_add_relation_to(
730
-                $payment,
731
-                'Payment',
732
-                ['RPY_amount' => $payment_amount]
733
-            );
734
-            // make it stick
735
-            $registration->save();
736
-        }
737
-    }
738
-
739
-
740
-    /**
741
-     * update registration REG_paid field after refund and link registration with payment
742
-     *
743
-     * @param EE_Registration $registration
744
-     * @param EE_Payment      $payment
745
-     * @param float           $available_refund_amount - IMPORTANT !!! SEND AVAILABLE REFUND AMOUNT AS A POSITIVE NUMBER
746
-     * @return float
747
-     * @throws EE_Error
748
-     * @throws InvalidArgumentException
749
-     * @throws RuntimeException
750
-     * @throws InvalidDataTypeException
751
-     * @throws InvalidInterfaceException
752
-     * @throws ReflectionException
753
-     */
754
-    public function process_registration_refund(
755
-        EE_Registration $registration,
756
-        EE_Payment $payment,
757
-        $available_refund_amount = 0.00
758
-    ) {
759
-        // EEH_Debug_Tools::printr( $payment->amount(), '$payment->amount()', __FILE__, __LINE__ );
760
-        if ($registration->paid() > 0) {
761
-            // ensure $available_refund_amount is NOT negative
762
-            $available_refund_amount = (float) abs($available_refund_amount);
763
-            // don't allow refund amount to exceed the available payment amount, OR the amount paid
764
-            $refund_amount = min($available_refund_amount, (float) $registration->paid());
765
-            // update $available_payment_amount
766
-            $available_refund_amount -= $refund_amount;
767
-            // calculate and set new REG_paid
768
-            $registration->set_paid($registration->paid() - $refund_amount);
769
-            // convert payment amount back to a negative value for storage in the db
770
-            $refund_amount = (float) abs($refund_amount) * -1;
771
-            // now save it
772
-            $this->_apply_registration_payment($registration, $payment, $refund_amount);
773
-        }
774
-        return $available_refund_amount;
775
-    }
776
-
777
-
778
-    /**
779
-     * Process payments and transaction after payment process completed.
780
-     * ultimately this will send the TXN and payment details off so that notifications can be sent out.
781
-     * if this request happens to be processing an IPN,
782
-     * then we will also set the Payment Options Reg Step to completed,
783
-     * and attempt to completely finalize the TXN if all of the other Reg Steps are completed as well.
784
-     *
785
-     * @param EE_Transaction $transaction
786
-     * @param EE_Payment     $payment
787
-     * @param bool           $IPN
788
-     * @throws EE_Error
789
-     * @throws InvalidArgumentException
790
-     * @throws ReflectionException
791
-     * @throws RuntimeException
792
-     * @throws InvalidDataTypeException
793
-     * @throws InvalidInterfaceException
794
-     */
795
-    protected function _post_payment_processing(EE_Transaction $transaction, EE_Payment $payment, $IPN = false)
796
-    {
797
-        /** @type EE_Transaction_Processor $transaction_processor */
798
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
799
-        // is the Payment Options Reg Step completed ?
800
-        $payment_options_step_completed = $transaction->reg_step_completed('payment_options');
801
-        // if the Payment Options Reg Step is completed...
802
-        $revisit = $payment_options_step_completed === true;
803
-        // then this is kinda sorta a revisit with regards to payments at least
804
-        $transaction_processor->set_revisit($revisit);
805
-        // if this is an IPN, let's consider the Payment Options Reg Step completed if not already
806
-        if (
807
-            $IPN
808
-            && $payment_options_step_completed !== true
809
-            && ($payment->is_approved() || $payment->is_pending())
810
-        ) {
811
-            $payment_options_step_completed = $transaction->set_reg_step_completed(
812
-                'payment_options'
813
-            );
814
-        }
815
-        // maybe update status, but don't save transaction just yet
816
-        $transaction->update_status_based_on_total_paid(false);
817
-        // check if 'finalize_registration' step has been completed...
818
-        $finalized = $transaction->reg_step_completed('finalize_registration');
819
-        //  if this is an IPN and the final step has not been initiated
820
-        if ($IPN && $payment_options_step_completed && $finalized === false) {
821
-            // and if it hasn't already been set as being started...
822
-            $finalized = $transaction->set_reg_step_initiated('finalize_registration');
823
-        }
824
-        $transaction->save();
825
-        // because the above will return false if the final step was not fully completed, we need to check again...
826
-        if ($IPN && $finalized !== false) {
827
-            // and if we are all good to go, then send out notifications
828
-            add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
829
-            // ok, now process the transaction according to the payment
830
-            $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
831
-                $transaction,
832
-                $payment
833
-            );
834
-        }
835
-        // DEBUG LOG
836
-        $payment_method = $payment->payment_method();
837
-        if ($payment_method instanceof EE_Payment_Method) {
838
-            $payment_method_type_obj = $payment_method->type_obj();
839
-            if ($payment_method_type_obj instanceof EE_PMT_Base) {
840
-                $gateway = $payment_method_type_obj->get_gateway();
841
-                if ($gateway instanceof EE_Gateway) {
842
-                    $gateway->log(
843
-                        [
844
-                            'message'               => (string) esc_html__(
845
-                                'Post Payment Transaction Details',
846
-                                'event_espresso'
847
-                            ),
848
-                            'transaction'           => $transaction->model_field_array(),
849
-                            'finalized'             => $finalized,
850
-                            'IPN'                   => $IPN,
851
-                            'deliver_notifications' => has_filter(
852
-                                'FHEE__EED_Messages___maybe_registration__deliver_notifications'
853
-                            ),
854
-                        ],
855
-                        $payment
856
-                    );
857
-                }
858
-            }
859
-        }
860
-    }
861
-
862
-
863
-    /**
864
-     * Force posts to PayPal to use TLS v1.2. See:
865
-     * https://core.trac.wordpress.org/ticket/36320
866
-     * https://core.trac.wordpress.org/ticket/34924#comment:15
867
-     * https://www.paypal-knowledge.com/infocenter/index?page=content&widgetview=true&id=FAQ1914&viewlocale=en_US
868
-     * This will affect PayPal standard, pro, express, and Payflow.
869
-     *
870
-     * @param $handle
871
-     * @param $r
872
-     * @param $url
873
-     */
874
-    public static function _curl_requests_to_paypal_use_tls($handle, $r, $url)
875
-    {
876
-        if (strpos($url, 'https://') !== false && strpos($url, '.paypal.com') !== false) {
877
-            // Use the value of the constant CURL_SSLVERSION_TLSv1 = 1
878
-            // instead of the constant because it might not be defined
879
-            curl_setopt($handle, CURLOPT_SSLVERSION, 6);
880
-        }
881
-    }
22
+	/**
23
+	 * @var CurrencyFormatter
24
+	 * @since $VID:$
25
+	 */
26
+	protected $currency_formatter;
27
+
28
+	/**
29
+	 * @var EE_Payment_Processor $_instance
30
+	 */
31
+	private static $_instance;
32
+
33
+
34
+	/**
35
+	 * @singleton method used to instantiate class object
36
+	 * @return EE_Payment_Processor instance
37
+	 */
38
+	public static function instance()
39
+	{
40
+		// check if class object is instantiated
41
+		if (! self::$_instance instanceof EE_Payment_Processor) {
42
+			self::$_instance = new self();
43
+		}
44
+		return self::$_instance;
45
+	}
46
+
47
+
48
+	/**
49
+	 * @return EE_Payment_Processor
50
+	 */
51
+	public static function reset()
52
+	{
53
+		self::$_instance = null;
54
+		return self::instance();
55
+	}
56
+
57
+
58
+	/**
59
+	 *private constructor to prevent direct creation
60
+	 */
61
+	private function __construct()
62
+	{
63
+		do_action('AHEE__EE_Payment_Processor__construct');
64
+		add_action('http_api_curl', [$this, '_curl_requests_to_paypal_use_tls'], 10, 3);
65
+		// in a better world this would have been injected upon construction
66
+		if (! $this->currency_formatter instanceof CurrencyFormatter) {
67
+			$this->currency_formatter = LoaderFactory::getLoader()->getShared(CurrencyFormatter::class);
68
+		}
69
+	}
70
+
71
+
72
+	/**
73
+	 * Using the selected gateway, processes the payment for that transaction, and updates the transaction
74
+	 * appropriately. Saves the payment that is generated
75
+	 *
76
+	 * @param EE_Payment_Method    $payment_method
77
+	 * @param EE_Transaction       $transaction
78
+	 * @param float                $amount       if only part of the transaction is to be paid for, how much.
79
+	 *                                           Leave null if payment is for the full amount owing
80
+	 * @param EE_Billing_Info_Form $billing_form (or probably null, if it's an offline or offsite payment method).
81
+	 *                                           Receive_form_submission() should have
82
+	 *                                           already been called on the billing form
83
+	 *                                           (ie, its inputs should have their normalized values set).
84
+	 * @param string               $return_url   string used mostly by offsite gateways to specify
85
+	 *                                           where to go AFTER the offsite gateway
86
+	 * @param string               $method       like 'CART', indicates who the client who called this was
87
+	 * @param bool                 $by_admin     TRUE if payment is being attempted from the admin
88
+	 * @param boolean              $update_txn   whether or not to call
89
+	 *                                           EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
90
+	 * @param string               $cancel_url   URL to return to if off-site payments are cancelled
91
+	 * @return EE_Payment
92
+	 * @throws EE_Error
93
+	 * @throws InvalidArgumentException
94
+	 * @throws ReflectionException
95
+	 * @throws RuntimeException
96
+	 * @throws InvalidDataTypeException
97
+	 * @throws InvalidInterfaceException
98
+	 */
99
+	public function process_payment(
100
+		EE_Payment_Method $payment_method,
101
+		EE_Transaction $transaction,
102
+		$amount = null,
103
+		$billing_form = null,
104
+		$return_url = null,
105
+		$method = 'CART',
106
+		$by_admin = false,
107
+		$update_txn = true,
108
+		$cancel_url = ''
109
+	) {
110
+		$amount = (float) $amount;
111
+		if ($amount < 0) {
112
+			throw new EE_Error(
113
+				sprintf(
114
+					esc_html__(
115
+						'Attempting to make a payment for a negative amount of %1$d for transaction %2$d. That should be a refund',
116
+						'event_espresso'
117
+					),
118
+					$amount,
119
+					$transaction->ID()
120
+				)
121
+			);
122
+		}
123
+		// verify payment method
124
+		$payment_method = EEM_Payment_Method::instance()->ensure_is_obj(
125
+			$payment_method,
126
+			true
127
+		);
128
+		// verify transaction
129
+		EEM_Transaction::instance()->ensure_is_obj($transaction);
130
+		$transaction->set_payment_method_ID($payment_method->ID());
131
+		$amount    = (float) $this->currency_formatter->formatForLocale(
132
+			$amount,
133
+			CurrencyFormatter::FORMAT_LOCALIZED_FLOAT
134
+		);
135
+		$remaining = (float) $transaction->prettyRemaining('localized_float');
136
+		// verify payment method type
137
+		if ($payment_method->type_obj() instanceof EE_PMT_Base) {
138
+			$payment = $payment_method->type_obj()->process_payment(
139
+				$transaction,
140
+				min($amount, $remaining), // make sure we don't overcharge
141
+				$billing_form,
142
+				$return_url,
143
+				add_query_arg(['ee_cancel_payment' => true], $cancel_url),
144
+				$method,
145
+				$by_admin
146
+			);
147
+			// check if payment method uses an off-site gateway
148
+			if ($payment_method->type_obj()->payment_occurs() !== EE_PMT_Base::offsite) {
149
+				// don't process payments for off-site gateways yet because no payment has occurred yet
150
+				$this->update_txn_based_on_payment($transaction, $payment, $update_txn);
151
+			}
152
+			return $payment;
153
+		}
154
+		EE_Error::add_error(
155
+			sprintf(
156
+				esc_html__(
157
+					'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
158
+					'event_espresso'
159
+				),
160
+				'<br/>',
161
+				EE_Registry::instance()->CFG->organization->get_pretty('email')
162
+			),
163
+			__FILE__,
164
+			__FUNCTION__,
165
+			__LINE__
166
+		);
167
+		return null;
168
+	}
169
+
170
+
171
+	/**
172
+	 * @param EE_Transaction|int $transaction
173
+	 * @param EE_Payment_Method  $payment_method
174
+	 * @return string
175
+	 * @throws EE_Error
176
+	 * @throws InvalidArgumentException
177
+	 * @throws InvalidDataTypeException
178
+	 * @throws InvalidInterfaceException
179
+	 * @throws ReflectionException
180
+	 */
181
+	public function get_ipn_url_for_payment_method($transaction, $payment_method)
182
+	{
183
+		/** @type EE_Transaction $transaction */
184
+		$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
185
+		$primary_reg = $transaction->primary_registration();
186
+		if (! $primary_reg instanceof EE_Registration) {
187
+			throw new EE_Error(
188
+				sprintf(
189
+					esc_html__(
190
+						'Cannot get IPN URL for transaction with ID %d because it has no primary registration',
191
+						'event_espresso'
192
+					),
193
+					$transaction->ID()
194
+				)
195
+			);
196
+		}
197
+		$payment_method = EEM_Payment_Method::instance()->ensure_is_obj(
198
+			$payment_method,
199
+			true
200
+		);
201
+		return add_query_arg(
202
+			[
203
+				'e_reg_url_link'    => $primary_reg->reg_url_link(),
204
+				'ee_payment_method' => $payment_method->slug(),
205
+			],
206
+			EE_Registry::instance()->CFG->core->txn_page_url()
207
+		);
208
+	}
209
+
210
+
211
+	/**
212
+	 * Process the IPN. Firstly, we'll hope we put the standard args into the IPN URL so
213
+	 * we can easily find what registration the IPN is for and what payment method.
214
+	 * However, if not, we'll give all payment methods a chance to claim it and process it.
215
+	 * If a payment is found for the IPN info, it is saved.
216
+	 *
217
+	 * @param array              $_req_data            form post data
218
+	 * @param EE_Transaction|int $transaction          optional (or a transactions id)
219
+	 * @param EE_Payment_Method  $payment_method       (or a slug or id of one)
220
+	 * @param boolean            $update_txn           whether or not to call
221
+	 *                                                 EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
222
+	 * @param bool               $separate_IPN_request whether the IPN uses a separate request (true, like PayPal)
223
+	 *                                                 or is processed manually (false, like Authorize.net)
224
+	 * @return EE_Payment
225
+	 * @throws EE_Error
226
+	 * @throws Exception
227
+	 * @throws RuntimeException
228
+	 * @throws ReflectionException
229
+	 * @throws InvalidArgumentException
230
+	 * @throws InvalidInterfaceException
231
+	 * @throws InvalidDataTypeException
232
+	 */
233
+	public function process_ipn(
234
+		$_req_data,
235
+		$transaction = null,
236
+		$payment_method = null,
237
+		$update_txn = true,
238
+		$separate_IPN_request = true
239
+	) {
240
+		EE_Registry::instance()->load_model('Change_Log');
241
+		$_req_data = $this->_remove_unusable_characters_from_array((array) $_req_data);
242
+		EE_Processor_Base::set_IPN($separate_IPN_request);
243
+		$obj_for_log = null;
244
+		if ($transaction instanceof EE_Transaction) {
245
+			$obj_for_log = $transaction;
246
+			if ($payment_method instanceof EE_Payment_Method) {
247
+				$obj_for_log = EEM_Payment::instance()->get_one(
248
+					[
249
+						['TXN_ID' => $transaction->ID(), 'PMD_ID' => $payment_method->ID()],
250
+						'order_by' => ['PAY_timestamp' => 'desc'],
251
+					]
252
+				);
253
+			}
254
+		} elseif ($payment_method instanceof EE_Payment) {
255
+			$obj_for_log = $payment_method;
256
+		}
257
+		$log = EEM_Change_Log::instance()->log(
258
+			EEM_Change_Log::type_gateway,
259
+			['IPN data received' => $_req_data],
260
+			$obj_for_log
261
+		);
262
+		try {
263
+			/**
264
+			 * @var EE_Payment $payment
265
+			 */
266
+			$payment = null;
267
+			if ($transaction && $payment_method) {
268
+				/** @type EE_Transaction $transaction */
269
+				$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
270
+				/** @type EE_Payment_Method $payment_method */
271
+				$payment_method = EEM_Payment_Method::instance()->ensure_is_obj($payment_method);
272
+				if ($payment_method->type_obj() instanceof EE_PMT_Base) {
273
+					try {
274
+						$payment = $payment_method->type_obj()->handle_ipn($_req_data, $transaction);
275
+						$log->set_object($payment);
276
+					} catch (EventEspresso\core\exceptions\IpnException $e) {
277
+						EEM_Change_Log::instance()->log(
278
+							EEM_Change_Log::type_gateway,
279
+							[
280
+								'message'     => 'IPN Exception: ' . $e->getMessage(),
281
+								'current_url' => EEH_URL::current_url(),
282
+								'payment'     => $e->getPaymentProperties(),
283
+								'IPN_data'    => $e->getIpnData(),
284
+							],
285
+							$obj_for_log
286
+						);
287
+						return $e->getPayment();
288
+					}
289
+				} else {
290
+					// not a payment
291
+					EE_Error::add_error(
292
+						sprintf(
293
+							esc_html__(
294
+								'A valid payment method could not be determined due to a technical issue.%sPlease refresh your browser and try again or contact %s for assistance.',
295
+								'event_espresso'
296
+							),
297
+							'<br/>',
298
+							EE_Registry::instance()->CFG->organization->get_pretty('email')
299
+						),
300
+						__FILE__,
301
+						__FUNCTION__,
302
+						__LINE__
303
+					);
304
+				}
305
+			} else {
306
+				// that's actually pretty ok. The IPN just wasn't able
307
+				// to identify which transaction or payment method this was for
308
+				// give all active payment methods a chance to claim it
309
+				$active_payment_methods = EEM_Payment_Method::instance()->get_all_active();
310
+				foreach ($active_payment_methods as $active_payment_method) {
311
+					try {
312
+						$payment        = $active_payment_method->type_obj()->handle_unclaimed_ipn($_req_data);
313
+						$payment_method = $active_payment_method;
314
+						EEM_Change_Log::instance()->log(
315
+							EEM_Change_Log::type_gateway,
316
+							['IPN data' => $_req_data],
317
+							$payment
318
+						);
319
+						break;
320
+					} catch (EventEspresso\core\exceptions\IpnException $e) {
321
+						EEM_Change_Log::instance()->log(
322
+							EEM_Change_Log::type_gateway,
323
+							[
324
+								'message'     => 'IPN Exception: ' . $e->getMessage(),
325
+								'current_url' => EEH_URL::current_url(),
326
+								'payment'     => $e->getPaymentProperties(),
327
+								'IPN_data'    => $e->getIpnData(),
328
+							],
329
+							$obj_for_log
330
+						);
331
+						return $e->getPayment();
332
+					} catch (EE_Error $e) {
333
+						// that's fine- it apparently couldn't handle the IPN
334
+					}
335
+				}
336
+			}
337
+			// EEM_Payment_Log::instance()->log("got to 7",$transaction,$payment_method);
338
+			if ($payment instanceof EE_Payment) {
339
+				$payment->save();
340
+				//  update the TXN
341
+				$this->update_txn_based_on_payment(
342
+					$transaction,
343
+					$payment,
344
+					$update_txn,
345
+					$separate_IPN_request
346
+				);
347
+			} else {
348
+				// we couldn't find the payment for this IPN... let's try and log at least SOMETHING
349
+				if ($payment_method) {
350
+					EEM_Change_Log::instance()->log(
351
+						EEM_Change_Log::type_gateway,
352
+						['IPN data' => $_req_data],
353
+						$payment_method
354
+					);
355
+				} elseif ($transaction) {
356
+					EEM_Change_Log::instance()->log(
357
+						EEM_Change_Log::type_gateway,
358
+						['IPN data' => $_req_data],
359
+						$transaction
360
+					);
361
+				}
362
+			}
363
+			return $payment;
364
+		} catch (EE_Error $e) {
365
+			do_action(
366
+				'AHEE__log',
367
+				__FILE__,
368
+				__FUNCTION__,
369
+				sprintf(
370
+					esc_html__(
371
+						'Error occurred while receiving IPN. Transaction: %1$s, req data: %2$s. The error was "%3$s"',
372
+						'event_espresso'
373
+					),
374
+					print_r($transaction, true),
375
+					print_r($_req_data, true),
376
+					$e->getMessage()
377
+				)
378
+			);
379
+			throw $e;
380
+		}
381
+	}
382
+
383
+
384
+	/**
385
+	 * Removes any non-printable illegal characters from the input,
386
+	 * which might cause a raucous when trying to insert into the database
387
+	 *
388
+	 * @param array $request_data
389
+	 * @return array
390
+	 */
391
+	protected function _remove_unusable_characters_from_array(array $request_data)
392
+	{
393
+		$return_data = [];
394
+		foreach ($request_data as $key => $value) {
395
+			$return_data[ $this->_remove_unusable_characters($key) ] = $this->_remove_unusable_characters(
396
+				$value
397
+			);
398
+		}
399
+		return $return_data;
400
+	}
401
+
402
+
403
+	/**
404
+	 * Removes any non-printable illegal characters from the input,
405
+	 * which might cause a raucous when trying to insert into the database
406
+	 *
407
+	 * @param string $request_data
408
+	 * @return string
409
+	 */
410
+	protected function _remove_unusable_characters($request_data)
411
+	{
412
+		return preg_replace('/[^[:print:]]/', '', $request_data);
413
+	}
414
+
415
+
416
+	/**
417
+	 * Should be called just before displaying the payment attempt results to the user,
418
+	 * when the payment attempt has finished. Some payment methods may have special
419
+	 * logic to perform here. For example, if process_payment() happens on a special request
420
+	 * and then the user is redirected to a page that displays the payment's status, this
421
+	 * should be called while loading the page that displays the payment's status. If the user is
422
+	 * sent to an offsite payment provider, this should be called upon returning from that offsite payment
423
+	 * provider.
424
+	 *
425
+	 * @param EE_Transaction|int $transaction
426
+	 * @param bool               $update_txn whether or not to call
427
+	 *                                       EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
428
+	 * @return EE_Payment
429
+	 * @throws EE_Error
430
+	 * @throws InvalidArgumentException
431
+	 * @throws ReflectionException
432
+	 * @throws RuntimeException
433
+	 * @throws InvalidDataTypeException
434
+	 * @throws InvalidInterfaceException
435
+	 * @deprecated 4.6.24 method is no longer used. Instead it is up to client code, like SPCO,
436
+	 *                                       to call handle_ipn() for offsite gateways that don't receive separate IPNs
437
+	 */
438
+	public function finalize_payment_for($transaction, $update_txn = true)
439
+	{
440
+		/** @var $transaction EE_Transaction */
441
+		$transaction         = EEM_Transaction::instance()->ensure_is_obj($transaction);
442
+		$last_payment_method = $transaction->payment_method();
443
+		if ($last_payment_method instanceof EE_Payment_Method) {
444
+			$payment = $last_payment_method->type_obj()->finalize_payment_for($transaction);
445
+			$this->update_txn_based_on_payment($transaction, $payment, $update_txn);
446
+			return $payment;
447
+		}
448
+		return null;
449
+	}
450
+
451
+
452
+	/**
453
+	 * Processes a direct refund request, saves the payment, and updates the transaction appropriately.
454
+	 *
455
+	 * @param EE_Payment_Method $payment_method
456
+	 * @param EE_Payment        $payment_to_refund
457
+	 * @param array             $refund_info
458
+	 * @return EE_Payment
459
+	 * @throws EE_Error
460
+	 * @throws InvalidArgumentException
461
+	 * @throws ReflectionException
462
+	 * @throws RuntimeException
463
+	 * @throws InvalidDataTypeException
464
+	 * @throws InvalidInterfaceException
465
+	 */
466
+	public function process_refund(
467
+		EE_Payment_Method $payment_method,
468
+		EE_Payment $payment_to_refund,
469
+		array $refund_info = []
470
+	) {
471
+		if ($payment_method instanceof EE_Payment_Method && $payment_method->type_obj()->supports_sending_refunds()) {
472
+			$payment_method->type_obj()->process_refund($payment_to_refund, $refund_info);
473
+			$this->update_txn_based_on_payment($payment_to_refund->transaction(), $payment_to_refund);
474
+		}
475
+		return $payment_to_refund;
476
+	}
477
+
478
+
479
+	/**
480
+	 * This should be called each time there may have been an update to a
481
+	 * payment on a transaction (ie, we asked for a payment to process a
482
+	 * payment for a transaction, or we told a payment method about an IPN, or
483
+	 * we told a payment method to
484
+	 * "finalize_payment_for" (a transaction), or we told a payment method to
485
+	 * process a refund. This should handle firing the correct hooks to
486
+	 * indicate
487
+	 * what exactly happened and updating the transaction appropriately). This
488
+	 * could be integrated directly into EE_Transaction upon save, but we want
489
+	 * this logic to be separate from 'normal' plain-jane saving and updating
490
+	 * of transactions and payments, and to be tied to payment processing.
491
+	 * Note: this method DOES NOT save the payment passed into it. It is the responsibility
492
+	 * of previous code to decide whether or not to save (because the payment passed into
493
+	 * this method might be a temporary, never-to-be-saved payment from an offline gateway,
494
+	 * in which case we only want that payment object for some temporary usage during this request,
495
+	 * but we don't want it to be saved).
496
+	 *
497
+	 * @param EE_Transaction|int $transaction
498
+	 * @param EE_Payment         $payment
499
+	 * @param boolean            $update_txn
500
+	 *                        whether or not to call
501
+	 *                        EE_Transaction_Processor::
502
+	 *                        update_transaction_and_registrations_after_checkout_or_payment()
503
+	 *                        (you can save 1 DB query if you know you're going
504
+	 *                        to save it later instead)
505
+	 * @param bool               $IPN
506
+	 *                        if processing IPNs or other similar payment
507
+	 *                        related activities that occur in alternate
508
+	 *                        requests than the main one that is processing the
509
+	 *                        TXN, then set this to true to check whether the
510
+	 *                        TXN is locked before updating
511
+	 * @throws EE_Error
512
+	 * @throws InvalidArgumentException
513
+	 * @throws ReflectionException
514
+	 * @throws RuntimeException
515
+	 * @throws InvalidDataTypeException
516
+	 * @throws InvalidInterfaceException
517
+	 */
518
+	public function update_txn_based_on_payment($transaction, $payment, $update_txn = true, $IPN = false)
519
+	{
520
+		$do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__not_successful';
521
+		/** @type EE_Transaction $transaction */
522
+		$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
523
+		// can we freely update the TXN at this moment?
524
+		if ($IPN && $transaction->is_locked()) {
525
+			// don't update the transaction at this exact moment
526
+			// because the TXN is active in another request
527
+			EE_Cron_Tasks::schedule_update_transaction_with_payment(
528
+				time(),
529
+				$transaction->ID(),
530
+				$payment->ID()
531
+			);
532
+		} else {
533
+			// verify payment and that it has been saved
534
+			if ($payment instanceof EE_Payment && $payment->ID()) {
535
+				if (
536
+					$payment->payment_method() instanceof EE_Payment_Method
537
+					&& $payment->payment_method()->type_obj() instanceof EE_PMT_Base
538
+				) {
539
+					$payment->payment_method()->type_obj()->update_txn_based_on_payment($payment);
540
+					// update TXN registrations with payment info
541
+					$this->process_registration_payments($transaction, $payment);
542
+				}
543
+				$do_action = $payment->just_approved()
544
+					? 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__successful'
545
+					: $do_action;
546
+			} else {
547
+				// send out notifications
548
+				add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
549
+				$do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__no_payment_made';
550
+			}
551
+			if ($payment instanceof EE_Payment && $payment->status() !== EEM_Payment::status_id_failed) {
552
+				/** @type EE_Transaction_Payments $transaction_payments */
553
+				$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
554
+				// set new value for total paid
555
+				$transaction_payments->calculate_total_payments_and_update_status($transaction);
556
+				// call EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() ???
557
+				if ($update_txn) {
558
+					$this->_post_payment_processing($transaction, $payment, $IPN);
559
+				}
560
+			}
561
+			// granular hook for others to use.
562
+			do_action($do_action, $transaction, $payment);
563
+			do_action('AHEE_log', __CLASS__, __FUNCTION__, $do_action, '$do_action');
564
+			// global hook for others to use.
565
+			do_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', $transaction, $payment);
566
+		}
567
+	}
568
+
569
+
570
+	/**
571
+	 * update registrations REG_paid field after successful payment and link registrations with payment
572
+	 *
573
+	 * @param EE_Transaction    $transaction
574
+	 * @param EE_Payment        $payment
575
+	 * @param EE_Registration[] $registrations
576
+	 * @throws EE_Error
577
+	 * @throws InvalidArgumentException
578
+	 * @throws RuntimeException
579
+	 * @throws InvalidDataTypeException
580
+	 * @throws InvalidInterfaceException
581
+	 * @throws ReflectionException
582
+	 */
583
+	public function process_registration_payments(
584
+		EE_Transaction $transaction,
585
+		EE_Payment $payment,
586
+		array $registrations = []
587
+	) {
588
+		// only process if payment was successful
589
+		if ($payment->status() !== EEM_Payment::status_id_approved) {
590
+			return;
591
+		}
592
+		// EEM_Registration::instance()->show_next_x_db_queries();
593
+		if (empty($registrations)) {
594
+			// find registrations with monies owing that can receive a payment
595
+			$registrations = $transaction->registrations(
596
+				[
597
+					[
598
+						// only these reg statuses can receive payments
599
+						'STS_ID'           => ['IN', EEM_Registration::reg_statuses_that_allow_payment()],
600
+						'REG_final_price'  => ['!=', 0],
601
+						'REG_final_price*' => ['!=', 'REG_paid', true],
602
+					],
603
+				]
604
+			);
605
+		}
606
+		// still nothing ??!??
607
+		if (empty($registrations)) {
608
+			return;
609
+		}
610
+		// todo: break out the following logic into a separate strategy class
611
+		// todo: named something like "Sequential_Reg_Payment_Strategy"
612
+		// todo: which would apply payments using the capitalist "first come first paid" approach
613
+		// todo: then have another strategy class like "Distributed_Reg_Payment_Strategy"
614
+		// todo: which would be the socialist "everybody gets a piece of pie" approach,
615
+		// todo: which would be better for deposits, where you want a bit of the payment applied to each registration
616
+		$refund = $payment->is_a_refund();
617
+		// how much is available to apply to registrations?
618
+		$available_payment_amount = abs($payment->amount());
619
+		foreach ($registrations as $registration) {
620
+			if ($registration instanceof EE_Registration) {
621
+				// nothing left?
622
+				if ($available_payment_amount <= 0) {
623
+					break;
624
+				}
625
+				if ($refund) {
626
+					$available_payment_amount = $this->process_registration_refund(
627
+						$registration,
628
+						$payment,
629
+						$available_payment_amount
630
+					);
631
+				} else {
632
+					$available_payment_amount = $this->process_registration_payment(
633
+						$registration,
634
+						$payment,
635
+						$available_payment_amount
636
+					);
637
+				}
638
+			}
639
+		}
640
+		if (
641
+			$available_payment_amount > 0
642
+			&& apply_filters(
643
+				'FHEE__EE_Payment_Processor__process_registration_payments__display_notifications',
644
+				false
645
+			)
646
+		) {
647
+			EE_Error::add_attention(
648
+				sprintf(
649
+					esc_html__(
650
+						'A remainder of %1$s exists after applying this payment to Registration(s) %2$s.%3$sPlease verify that the original payment amount of %4$s is correct. If so, you should edit this payment and select at least one additional registration in the "Registrations to Apply Payment to" section, so that the remainder of this payment can be applied to the additional registration(s).',
651
+						'event_espresso'
652
+					),
653
+					$this->currency_formatter->formatForLocale($available_payment_amount),
654
+					implode(', ', array_keys($registrations)),
655
+					'<br/>',
656
+					$payment->prettyAmount()
657
+				),
658
+				__FILE__,
659
+				__FUNCTION__,
660
+				__LINE__
661
+			);
662
+		}
663
+	}
664
+
665
+
666
+	/**
667
+	 * update registration REG_paid field after successful payment and link registration with payment
668
+	 *
669
+	 * @param EE_Registration $registration
670
+	 * @param EE_Payment      $payment
671
+	 * @param float           $available_payment_amount
672
+	 * @return float
673
+	 * @throws EE_Error
674
+	 * @throws InvalidArgumentException
675
+	 * @throws RuntimeException
676
+	 * @throws InvalidDataTypeException
677
+	 * @throws InvalidInterfaceException
678
+	 * @throws ReflectionException
679
+	 */
680
+	public function process_registration_payment(
681
+		EE_Registration $registration,
682
+		EE_Payment $payment,
683
+		$available_payment_amount = 0.00
684
+	) {
685
+		$owing = $registration->amountOwing();
686
+		if ($owing > 0) {
687
+			// don't allow payment amount to exceed the available payment amount, OR the amount owing
688
+			$payment_amount = min($available_payment_amount, $owing);
689
+			// update $available_payment_amount
690
+			$available_payment_amount -= $payment_amount;
691
+			// calculate and set new REG_paid
692
+			$registration->set_paid($registration->paid() + $payment_amount);
693
+			// now save it
694
+			$this->_apply_registration_payment($registration, $payment, $payment_amount);
695
+		}
696
+		return $available_payment_amount;
697
+	}
698
+
699
+
700
+	/**
701
+	 * update registration REG_paid field after successful payment and link registration with payment
702
+	 *
703
+	 * @param EE_Registration $registration
704
+	 * @param EE_Payment      $payment
705
+	 * @param float           $payment_amount
706
+	 * @return void
707
+	 * @throws EE_Error
708
+	 * @throws InvalidArgumentException
709
+	 * @throws InvalidDataTypeException
710
+	 * @throws InvalidInterfaceException
711
+	 * @throws ReflectionException
712
+	 */
713
+	protected function _apply_registration_payment(
714
+		EE_Registration $registration,
715
+		EE_Payment $payment,
716
+		$payment_amount = 0.00
717
+	) {
718
+		// find any existing reg payment records for this registration and payment
719
+		$existing_reg_payment = EEM_Registration_Payment::instance()->get_one(
720
+			[['REG_ID' => $registration->ID(), 'PAY_ID' => $payment->ID()]]
721
+		);
722
+		// if existing registration payment exists
723
+		if ($existing_reg_payment instanceof EE_Registration_Payment) {
724
+			// then update that record
725
+			$existing_reg_payment->set_amount($payment_amount);
726
+			$existing_reg_payment->save();
727
+		} else {
728
+			// or add new relation between registration and payment and set amount
729
+			$registration->_add_relation_to(
730
+				$payment,
731
+				'Payment',
732
+				['RPY_amount' => $payment_amount]
733
+			);
734
+			// make it stick
735
+			$registration->save();
736
+		}
737
+	}
738
+
739
+
740
+	/**
741
+	 * update registration REG_paid field after refund and link registration with payment
742
+	 *
743
+	 * @param EE_Registration $registration
744
+	 * @param EE_Payment      $payment
745
+	 * @param float           $available_refund_amount - IMPORTANT !!! SEND AVAILABLE REFUND AMOUNT AS A POSITIVE NUMBER
746
+	 * @return float
747
+	 * @throws EE_Error
748
+	 * @throws InvalidArgumentException
749
+	 * @throws RuntimeException
750
+	 * @throws InvalidDataTypeException
751
+	 * @throws InvalidInterfaceException
752
+	 * @throws ReflectionException
753
+	 */
754
+	public function process_registration_refund(
755
+		EE_Registration $registration,
756
+		EE_Payment $payment,
757
+		$available_refund_amount = 0.00
758
+	) {
759
+		// EEH_Debug_Tools::printr( $payment->amount(), '$payment->amount()', __FILE__, __LINE__ );
760
+		if ($registration->paid() > 0) {
761
+			// ensure $available_refund_amount is NOT negative
762
+			$available_refund_amount = (float) abs($available_refund_amount);
763
+			// don't allow refund amount to exceed the available payment amount, OR the amount paid
764
+			$refund_amount = min($available_refund_amount, (float) $registration->paid());
765
+			// update $available_payment_amount
766
+			$available_refund_amount -= $refund_amount;
767
+			// calculate and set new REG_paid
768
+			$registration->set_paid($registration->paid() - $refund_amount);
769
+			// convert payment amount back to a negative value for storage in the db
770
+			$refund_amount = (float) abs($refund_amount) * -1;
771
+			// now save it
772
+			$this->_apply_registration_payment($registration, $payment, $refund_amount);
773
+		}
774
+		return $available_refund_amount;
775
+	}
776
+
777
+
778
+	/**
779
+	 * Process payments and transaction after payment process completed.
780
+	 * ultimately this will send the TXN and payment details off so that notifications can be sent out.
781
+	 * if this request happens to be processing an IPN,
782
+	 * then we will also set the Payment Options Reg Step to completed,
783
+	 * and attempt to completely finalize the TXN if all of the other Reg Steps are completed as well.
784
+	 *
785
+	 * @param EE_Transaction $transaction
786
+	 * @param EE_Payment     $payment
787
+	 * @param bool           $IPN
788
+	 * @throws EE_Error
789
+	 * @throws InvalidArgumentException
790
+	 * @throws ReflectionException
791
+	 * @throws RuntimeException
792
+	 * @throws InvalidDataTypeException
793
+	 * @throws InvalidInterfaceException
794
+	 */
795
+	protected function _post_payment_processing(EE_Transaction $transaction, EE_Payment $payment, $IPN = false)
796
+	{
797
+		/** @type EE_Transaction_Processor $transaction_processor */
798
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
799
+		// is the Payment Options Reg Step completed ?
800
+		$payment_options_step_completed = $transaction->reg_step_completed('payment_options');
801
+		// if the Payment Options Reg Step is completed...
802
+		$revisit = $payment_options_step_completed === true;
803
+		// then this is kinda sorta a revisit with regards to payments at least
804
+		$transaction_processor->set_revisit($revisit);
805
+		// if this is an IPN, let's consider the Payment Options Reg Step completed if not already
806
+		if (
807
+			$IPN
808
+			&& $payment_options_step_completed !== true
809
+			&& ($payment->is_approved() || $payment->is_pending())
810
+		) {
811
+			$payment_options_step_completed = $transaction->set_reg_step_completed(
812
+				'payment_options'
813
+			);
814
+		}
815
+		// maybe update status, but don't save transaction just yet
816
+		$transaction->update_status_based_on_total_paid(false);
817
+		// check if 'finalize_registration' step has been completed...
818
+		$finalized = $transaction->reg_step_completed('finalize_registration');
819
+		//  if this is an IPN and the final step has not been initiated
820
+		if ($IPN && $payment_options_step_completed && $finalized === false) {
821
+			// and if it hasn't already been set as being started...
822
+			$finalized = $transaction->set_reg_step_initiated('finalize_registration');
823
+		}
824
+		$transaction->save();
825
+		// because the above will return false if the final step was not fully completed, we need to check again...
826
+		if ($IPN && $finalized !== false) {
827
+			// and if we are all good to go, then send out notifications
828
+			add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
829
+			// ok, now process the transaction according to the payment
830
+			$transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
831
+				$transaction,
832
+				$payment
833
+			);
834
+		}
835
+		// DEBUG LOG
836
+		$payment_method = $payment->payment_method();
837
+		if ($payment_method instanceof EE_Payment_Method) {
838
+			$payment_method_type_obj = $payment_method->type_obj();
839
+			if ($payment_method_type_obj instanceof EE_PMT_Base) {
840
+				$gateway = $payment_method_type_obj->get_gateway();
841
+				if ($gateway instanceof EE_Gateway) {
842
+					$gateway->log(
843
+						[
844
+							'message'               => (string) esc_html__(
845
+								'Post Payment Transaction Details',
846
+								'event_espresso'
847
+							),
848
+							'transaction'           => $transaction->model_field_array(),
849
+							'finalized'             => $finalized,
850
+							'IPN'                   => $IPN,
851
+							'deliver_notifications' => has_filter(
852
+								'FHEE__EED_Messages___maybe_registration__deliver_notifications'
853
+							),
854
+						],
855
+						$payment
856
+					);
857
+				}
858
+			}
859
+		}
860
+	}
861
+
862
+
863
+	/**
864
+	 * Force posts to PayPal to use TLS v1.2. See:
865
+	 * https://core.trac.wordpress.org/ticket/36320
866
+	 * https://core.trac.wordpress.org/ticket/34924#comment:15
867
+	 * https://www.paypal-knowledge.com/infocenter/index?page=content&widgetview=true&id=FAQ1914&viewlocale=en_US
868
+	 * This will affect PayPal standard, pro, express, and Payflow.
869
+	 *
870
+	 * @param $handle
871
+	 * @param $r
872
+	 * @param $url
873
+	 */
874
+	public static function _curl_requests_to_paypal_use_tls($handle, $r, $url)
875
+	{
876
+		if (strpos($url, 'https://') !== false && strpos($url, '.paypal.com') !== false) {
877
+			// Use the value of the constant CURL_SSLVERSION_TLSv1 = 1
878
+			// instead of the constant because it might not be defined
879
+			curl_setopt($handle, CURLOPT_SSLVERSION, 6);
880
+		}
881
+	}
882 882
 }
Please login to merge, or discard this patch.