Completed
Branch BUG-10878-event-spaces-remaini... (62f9c8)
by
unknown
151:41 queued 139:39
created

EE_Registry   F

Complexity

Total Complexity 156

Size/Duplication

Total Lines 1465
Duplicated Lines 2.53 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
dl 37
loc 1465
rs 3.9999
c 0
b 0
f 0
wmc 156
lcom 1
cbo 11

38 Methods

Rating   Name   Duplication   Size   Complexity  
A instance() 0 8 2
A __construct() 0 10 1
B initialize() 0 30 1
A init() 0 8 3
A localize_i18n_js_strings() 0 10 3
A add_module() 0 12 3
A get_module() 0 6 2
B load_core() 0 25 1
A load_service() 0 20 1
A load_dms() 0 13 1
A load_class() 0 21 1
A load_helper() 0 16 1
A load_lib() 0 21 1
A load_model() 0 20 1
A load_model_class() 0 20 1
A is_model_name() 0 4 1
A load_file() 0 14 1
A load_addon() 0 14 1
C create() 7 46 12
C _load() 7 59 15
C _get_cached_class() 0 25 8
C clear_cached_class() 0 26 7
B _resolve_path() 0 25 6
B _require_file() 14 39 4
D _create_object() 0 72 15
A _array_is_numerically_and_sequentially_indexed() 0 6 2
A get_ReflectionClass() 9 10 3
C _resolve_dependencies() 0 62 13
D _resolve_dependency() 0 42 9
C _set_cached_class() 0 24 7
A factory() 0 11 3
A get_addon_by_name() 0 9 3
A get_addons_by_name() 0 8 2
B reset_model() 0 19 6
B reset() 0 22 4
C _reset_and_unset_object() 0 27 7
A cpt_models() 0 10 3
A CFG() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EE_Registry often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EE_Registry, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
use EventEspresso\core\interfaces\InterminableInterface;
4
use EventEspresso\core\interfaces\ResettableInterface;
5
use EventEspresso\core\services\assets\Registry;
6
use EventEspresso\core\services\commands\CommandBusInterface;
7
8
defined('EVENT_ESPRESSO_VERSION') || exit;
9
10
11
12
/**
13
 * EE_Registry Class
14
 * Centralized Application Data Storage and Management
15
 *
16
 * @package                   Event Espresso
17
 * @subpackage                core
18
 * @author                    Brent Christensen
19
 */
20
class EE_Registry implements ResettableInterface
21
{
22
23
    /**
24
     * @var EE_Registry $_instance
25
     */
26
    private static $_instance;
27
28
    /**
29
     * @var EE_Dependency_Map $_dependency_map
30
     */
31
    protected $_dependency_map;
32
33
    /**
34
     * @var array $_class_abbreviations
35
     */
36
    protected $_class_abbreviations = array();
37
38
    /**
39
     * @var CommandBusInterface $BUS
40
     */
41
    public $BUS;
42
43
    /**
44
     * @var EE_Cart $CART
45
     */
46
    public $CART;
47
48
    /**
49
     * @var EE_Config $CFG
50
     */
51
    public $CFG;
52
53
    /**
54
     * @var EE_Network_Config $NET_CFG
55
     */
56
    public $NET_CFG;
57
58
    /**
59
     * StdClass object for storing library classes in
60
     *
61
     * @var StdClass $LIB
62
     */
63
    public $LIB;
64
65
    /**
66
     * @var EE_Request_Handler $REQ
67
     */
68
    public $REQ;
69
70
    /**
71
     * @var EE_Session $SSN
72
     */
73
    public $SSN;
74
75
    /**
76
     * @since 4.5.0
77
     * @var EE_Capabilities $CAP
78
     */
79
    public $CAP;
80
81
    /**
82
     * @since 4.9.0
83
     * @var EE_Message_Resource_Manager $MRM
84
     */
85
    public $MRM;
86
87
88
    /**
89
     * @var Registry $AssetsRegistry
90
     */
91
    public $AssetsRegistry;
92
93
    /**
94
     * StdClass object for holding addons which have registered themselves to work with EE core
95
     *
96
     * @var EE_Addon[] $addons
97
     */
98
    public $addons;
99
100
    /**
101
     * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
102
     *
103
     * @var EEM_Base[] $models
104
     */
105
    public $models = array();
106
107
    /**
108
     * @var EED_Module[] $modules
109
     */
110
    public $modules;
111
112
    /**
113
     * @var EES_Shortcode[] $shortcodes
114
     */
115
    public $shortcodes;
116
117
    /**
118
     * @var WP_Widget[] $widgets
119
     */
120
    public $widgets;
121
122
    /**
123
     * this is an array of all implemented model names (i.e. not the parent abstract models, or models
124
     * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
125
     * Keys are model "short names" (eg "Event") as used in model relations, and values are
126
     * classnames (eg "EEM_Event")
127
     *
128
     * @var array $non_abstract_db_models
129
     */
130
    public $non_abstract_db_models = array();
131
132
133
    /**
134
     * internationalization for JS strings
135
     *    usage:   EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' );
136
     *    in js file:  var translatedString = eei18n.string_key;
137
     *
138
     * @var array $i18n_js_strings
139
     */
140
    public static $i18n_js_strings = array();
141
142
143
    /**
144
     * $main_file - path to espresso.php
145
     *
146
     * @var array $main_file
147
     */
148
    public $main_file;
149
150
    /**
151
     * array of ReflectionClass objects where the key is the class name
152
     *
153
     * @var ReflectionClass[] $_reflectors
154
     */
155
    public $_reflectors;
156
157
    /**
158
     * boolean flag to indicate whether or not to load/save dependencies from/to the cache
159
     *
160
     * @var boolean $_cache_on
161
     */
162
    protected $_cache_on = true;
163
164
165
166
    /**
167
     * @singleton method used to instantiate class object
168
     * @param  EE_Dependency_Map $dependency_map
169
     * @return EE_Registry instance
170
     */
171
    public static function instance(EE_Dependency_Map $dependency_map = null)
172
    {
173
        // check if class object is instantiated
174
        if (! self::$_instance instanceof EE_Registry) {
175
            self::$_instance = new self($dependency_map);
0 ignored issues
show
Bug introduced by
It seems like $dependency_map defined by parameter $dependency_map on line 171 can be null; however, EE_Registry::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
176
        }
177
        return self::$_instance;
178
    }
179
180
181
182
    /**
183
     * protected constructor to prevent direct creation
184
     *
185
     * @Constructor
186
     * @param  EE_Dependency_Map $dependency_map
187
     */
188
    protected function __construct(EE_Dependency_Map $dependency_map)
189
    {
190
        $this->_dependency_map = $dependency_map;
191
        $this->LIB = new stdClass();
192
        $this->addons = new stdClass();
193
        $this->modules = new stdClass();
194
        $this->shortcodes = new stdClass();
195
        $this->widgets = new stdClass();
196
        add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
197
    }
198
199
200
201
    /**
202
     * initialize
203
     *
204
     * @throws EE_Error
205
     * @throws ReflectionException
206
     */
207
    public function initialize()
208
    {
209
        $this->_class_abbreviations = apply_filters(
210
            'FHEE__EE_Registry____construct___class_abbreviations',
211
            array(
212
                'EE_Config'                                       => 'CFG',
213
                'EE_Session'                                      => 'SSN',
214
                'EE_Capabilities'                                 => 'CAP',
215
                'EE_Cart'                                         => 'CART',
216
                'EE_Network_Config'                               => 'NET_CFG',
217
                'EE_Request_Handler'                              => 'REQ',
218
                'EE_Message_Resource_Manager'                     => 'MRM',
219
                'EventEspresso\core\services\commands\CommandBus' => 'BUS',
220
                'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
221
            )
222
        );
223
        $this->load_core('Base', array(), true);
224
        // add our request and response objects to the cache
225
        $request_loader = $this->_dependency_map->class_loader('EE_Request');
226
        $this->_set_cached_class(
227
            $request_loader(),
228
            'EE_Request'
229
        );
230
        $response_loader = $this->_dependency_map->class_loader('EE_Response');
231
        $this->_set_cached_class(
232
            $response_loader(),
233
            'EE_Response'
234
        );
235
        add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
236
    }
237
238
239
240
    /**
241
     * @return void
242
     */
243
    public function init()
244
    {
245
        // Get current page protocol
246
        $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
247
        // Output admin-ajax.php URL with same protocol as current page
248
        self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
249
        self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
250
    }
251
252
253
254
    /**
255
     * localize_i18n_js_strings
256
     *
257
     * @return string
258
     */
259
    public static function localize_i18n_js_strings()
260
    {
261
        $i18n_js_strings = (array)self::$i18n_js_strings;
262
        foreach ($i18n_js_strings as $key => $value) {
263
            if (is_scalar($value)) {
264
                $i18n_js_strings[$key] = html_entity_decode((string)$value, ENT_QUOTES, 'UTF-8');
265
            }
266
        }
267
        return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
268
    }
269
270
271
272
    /**
273
     * @param $module
274
     * @throws EE_Error
275
     * @throws ReflectionException
276
     */
277
    public function add_module($module)
278
    {
279
        if ($module instanceof EED_Module) {
280
            $module_class = get_class($module);
281
            $this->modules->{$module_class} = $module;
282
        } else {
283
            if (! class_exists('EE_Module_Request_Router')) {
284
                $this->load_core('Module_Request_Router');
285
            }
286
            EE_Module_Request_Router::module_factory($module);
287
        }
288
    }
289
290
291
292
    /**
293
     * @param string $module_name
294
     * @return mixed EED_Module | NULL
295
     */
296
    public function get_module($module_name = '')
297
    {
298
        return isset($this->modules->{$module_name})
299
            ? $this->modules->{$module_name}
300
            : null;
301
    }
302
303
304
305
    /**
306
     * loads core classes - must be singletons
307
     *
308
     * @param string $class_name - simple class name ie: session
309
     * @param mixed  $arguments
310
     * @param bool   $load_only
311
     * @return mixed
312
     * @throws EE_Error
313
     * @throws ReflectionException
314
     */
315
    public function load_core($class_name, $arguments = array(), $load_only = false)
316
    {
317
        $core_paths = apply_filters(
318
            'FHEE__EE_Registry__load_core__core_paths',
319
            array(
320
                EE_CORE,
321
                EE_ADMIN,
322
                EE_CPTS,
323
                EE_CORE . 'data_migration_scripts' . DS,
324
                EE_CORE . 'request_stack' . DS,
325
                EE_CORE . 'middleware' . DS,
326
            )
327
        );
328
        // retrieve instantiated class
329
        return $this->_load(
330
            $core_paths,
331
            'EE_',
332
            $class_name,
333
            'core',
334
            $arguments,
335
            false,
336
            true,
337
            $load_only
338
        );
339
    }
340
341
342
343
    /**
344
     * loads service classes
345
     *
346
     * @param string $class_name - simple class name ie: session
347
     * @param mixed  $arguments
348
     * @param bool   $load_only
349
     * @return mixed
350
     * @throws EE_Error
351
     * @throws ReflectionException
352
     */
353
    public function load_service($class_name, $arguments = array(), $load_only = false)
354
    {
355
        $service_paths = apply_filters(
356
            'FHEE__EE_Registry__load_service__service_paths',
357
            array(
358
                EE_CORE . 'services' . DS,
359
            )
360
        );
361
        // retrieve instantiated class
362
        return $this->_load(
363
            $service_paths,
364
            'EE_',
365
            $class_name,
366
            'class',
367
            $arguments,
368
            false,
369
            true,
370
            $load_only
371
        );
372
    }
373
374
375
376
    /**
377
     * loads data_migration_scripts
378
     *
379
     * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
380
     * @param mixed  $arguments
381
     * @return EE_Data_Migration_Script_Base|mixed
382
     * @throws EE_Error
383
     * @throws ReflectionException
384
     */
385
    public function load_dms($class_name, $arguments = array())
386
    {
387
        // retrieve instantiated class
388
        return $this->_load(
389
            EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
390
            'EE_DMS_',
391
            $class_name,
392
            'dms',
393
            $arguments,
394
            false,
395
            false
396
        );
397
    }
398
399
400
401
    /**
402
     * loads object creating classes - must be singletons
403
     *
404
     * @param string $class_name - simple class name ie: attendee
405
     * @param mixed  $arguments  - an array of arguments to pass to the class
406
     * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
407
     *                           instantiate
408
     * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
409
     *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
410
     * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
411
     *                           (default)
412
     * @return EE_Base_Class | bool
413
     * @throws EE_Error
414
     * @throws ReflectionException
415
     */
416
    public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
417
    {
418
        $paths = apply_filters(
419
            'FHEE__EE_Registry__load_class__paths', array(
420
            EE_CORE,
421
            EE_CLASSES,
422
            EE_BUSINESS,
423
        )
424
        );
425
        // retrieve instantiated class
426
        return $this->_load(
427
            $paths,
428
            'EE_',
429
            $class_name,
430
            'class',
431
            $arguments,
432
            $from_db,
433
            $cache,
434
            $load_only
435
        );
436
    }
437
438
439
440
    /**
441
     * loads helper classes - must be singletons
442
     *
443
     * @param string $class_name - simple class name ie: price
444
     * @param mixed  $arguments
445
     * @param bool   $load_only
446
     * @return EEH_Base | bool
447
     * @throws EE_Error
448
     * @throws ReflectionException
449
     */
450
    public function load_helper($class_name, $arguments = array(), $load_only = true)
451
    {
452
        // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
453
        $helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
454
        // retrieve instantiated class
455
        return $this->_load(
456
            $helper_paths,
457
            'EEH_',
458
            $class_name,
459
            'helper',
460
            $arguments,
461
            false,
462
            true,
463
            $load_only
464
        );
465
    }
466
467
468
469
    /**
470
     * loads core classes - must be singletons
471
     *
472
     * @param string $class_name - simple class name ie: session
473
     * @param mixed  $arguments
474
     * @param bool   $load_only
475
     * @param bool   $cache      whether to cache the object or not.
476
     * @return mixed
477
     * @throws EE_Error
478
     * @throws ReflectionException
479
     */
480
    public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
481
    {
482
        $paths = array(
483
            EE_LIBRARIES,
484
            EE_LIBRARIES . 'messages' . DS,
485
            EE_LIBRARIES . 'shortcodes' . DS,
486
            EE_LIBRARIES . 'qtips' . DS,
487
            EE_LIBRARIES . 'payment_methods' . DS,
488
        );
489
        // retrieve instantiated class
490
        return $this->_load(
491
            $paths,
492
            'EE_',
493
            $class_name,
494
            'lib',
495
            $arguments,
496
            false,
497
            $cache,
498
            $load_only
499
        );
500
    }
501
502
503
504
    /**
505
     * loads model classes - must be singletons
506
     *
507
     * @param string $class_name - simple class name ie: price
508
     * @param mixed  $arguments
509
     * @param bool   $load_only
510
     * @return EEM_Base | bool
511
     * @throws EE_Error
512
     * @throws ReflectionException
513
     */
514
    public function load_model($class_name, $arguments = array(), $load_only = false)
515
    {
516
        $paths = apply_filters(
517
            'FHEE__EE_Registry__load_model__paths', array(
518
            EE_MODELS,
519
            EE_CORE,
520
        )
521
        );
522
        // retrieve instantiated class
523
        return $this->_load(
524
            $paths,
525
            'EEM_',
526
            $class_name,
527
            'model',
528
            $arguments,
529
            false,
530
            true,
531
            $load_only
532
        );
533
    }
534
535
536
537
    /**
538
     * loads model classes - must be singletons
539
     *
540
     * @param string $class_name - simple class name ie: price
541
     * @param mixed  $arguments
542
     * @param bool   $load_only
543
     * @return mixed | bool
544
     * @throws EE_Error
545
     * @throws ReflectionException
546
     */
547
    public function load_model_class($class_name, $arguments = array(), $load_only = true)
548
    {
549
        $paths = array(
550
            EE_MODELS . 'fields' . DS,
551
            EE_MODELS . 'helpers' . DS,
552
            EE_MODELS . 'relations' . DS,
553
            EE_MODELS . 'strategies' . DS,
554
        );
555
        // retrieve instantiated class
556
        return $this->_load(
557
            $paths,
558
            'EE_',
559
            $class_name,
560
            '',
561
            $arguments,
562
            false,
563
            true,
564
            $load_only
565
        );
566
    }
567
568
569
570
    /**
571
     * Determines if $model_name is the name of an actual EE model.
572
     *
573
     * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
574
     * @return boolean
575
     */
576
    public function is_model_name($model_name)
577
    {
578
        return isset($this->models[$model_name]);
579
    }
580
581
582
583
    /**
584
     * generic class loader
585
     *
586
     * @param string $path_to_file - directory path to file location, not including filename
587
     * @param string $file_name    - file name  ie:  my_file.php, including extension
588
     * @param string $type         - file type - core? class? helper? model?
589
     * @param mixed  $arguments
590
     * @param bool   $load_only
591
     * @return mixed
592
     * @throws EE_Error
593
     * @throws ReflectionException
594
     */
595
    public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
596
    {
597
        // retrieve instantiated class
598
        return $this->_load(
599
            $path_to_file,
600
            '',
601
            $file_name,
602
            $type,
603
            $arguments,
604
            false,
605
            true,
606
            $load_only
607
        );
608
    }
609
610
611
612
    /**
613
     * @param string $path_to_file - directory path to file location, not including filename
614
     * @param string $class_name   - full class name  ie:  My_Class
615
     * @param string $type         - file type - core? class? helper? model?
616
     * @param mixed  $arguments
617
     * @param bool   $load_only
618
     * @return bool|EE_Addon|object
619
     * @throws EE_Error
620
     * @throws ReflectionException
621
     */
622
    public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
623
    {
624
        // retrieve instantiated class
625
        return $this->_load(
626
            $path_to_file,
627
            'addon',
628
            $class_name,
629
            $type,
630
            $arguments,
631
            false,
632
            true,
633
            $load_only
634
        );
635
    }
636
637
638
639
    /**
640
     * instantiates, caches, and automatically resolves dependencies
641
     * for classes that use a Fully Qualified Class Name.
642
     * if the class is not capable of being loaded using PSR-4 autoloading,
643
     * then you need to use one of the existing load_*() methods
644
     * which can resolve the classname and filepath from the passed arguments
645
     *
646
     * @param bool|string $class_name   Fully Qualified Class Name
647
     * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
648
     * @param bool        $cache        whether to cache the instantiated object for reuse
649
     * @param bool        $from_db      some classes are instantiated from the db
650
     *                                  and thus call a different method to instantiate
651
     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
652
     * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
653
     * @return bool|null|object null = failure to load or instantiate class object.
654
     *                                  object = class loaded and instantiated successfully.
655
     *                                  bool = fail or success when $load_only is true
656
     * @throws EE_Error
657
     * @throws ReflectionException
658
     */
659
    public function create(
660
        $class_name = false,
661
        $arguments = array(),
662
        $cache = false,
663
        $from_db = false,
664
        $load_only = false,
665
        $addon = false
666
    ) {
667
        $class_name = ltrim($class_name, '\\');
668
        $class_name = $this->_dependency_map->get_alias($class_name);
669
        if (! class_exists($class_name)) {
670
            // maybe the class is registered with a preceding \
671
            $class_name = strpos($class_name, '\\') !== 0
672
                ? '\\' . $class_name
673
                : $class_name;
674
            // still doesn't exist ?
675
            if (! class_exists($class_name)) {
676
                return null;
677
            }
678
        }
679
        // if we're only loading the class and it already exists, then let's just return true immediately
680
        if ($load_only) {
681
            return true;
682
        }
683
        $addon = $addon
684
            ? 'addon'
685
            : '';
686
        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
687
        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
688
        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
689 View Code Duplication
        if ($this->_cache_on && $cache && ! $load_only) {
690
            // return object if it's already cached
691
            $cached_class = $this->_get_cached_class($class_name, $addon);
692
            if ($cached_class !== null) {
693
                return $cached_class;
694
            }
695
        }
696
        // instantiate the requested object
697
        $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
698
        if ($this->_cache_on && $cache) {
699
            // save it for later... kinda like gum  { : $
700
            $this->_set_cached_class($class_obj, $class_name, $addon, $from_db);
701
        }
702
        $this->_cache_on = true;
703
        return $class_obj;
704
    }
705
706
707
708
    /**
709
     * instantiates, caches, and injects dependencies for classes
710
     *
711
     * @param array       $file_paths   an array of paths to folders to look in
712
     * @param string      $class_prefix EE  or EEM or... ???
713
     * @param bool|string $class_name   $class name
714
     * @param string      $type         file type - core? class? helper? model?
715
     * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
716
     * @param bool        $from_db      some classes are instantiated from the db
717
     *                                  and thus call a different method to instantiate
718
     * @param bool        $cache        whether to cache the instantiated object for reuse
719
     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
720
     * @return bool|null|object null = failure to load or instantiate class object.
721
     *                                  object = class loaded and instantiated successfully.
722
     *                                  bool = fail or success when $load_only is true
723
     * @throws EE_Error
724
     * @throws ReflectionException
725
     */
726
    protected function _load(
727
        $file_paths = array(),
728
        $class_prefix = 'EE_',
729
        $class_name = false,
730
        $type = 'class',
731
        $arguments = array(),
732
        $from_db = false,
733
        $cache = true,
734
        $load_only = false
735
    ) {
736
        $class_name = ltrim($class_name, '\\');
737
        // strip php file extension
738
        $class_name = str_replace('.php', '', trim($class_name));
739
        // does the class have a prefix ?
740
        if (! empty($class_prefix) && $class_prefix !== 'addon') {
741
            // make sure $class_prefix is uppercase
742
            $class_prefix = strtoupper(trim($class_prefix));
743
            // add class prefix ONCE!!!
744
            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
745
        }
746
        $class_name = $this->_dependency_map->get_alias($class_name);
747
        $class_exists = class_exists($class_name);
748
        // if we're only loading the class and it already exists, then let's just return true immediately
749
        if ($load_only && $class_exists) {
750
            return true;
751
        }
752
        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
753
        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
754
        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
755 View Code Duplication
        if ($this->_cache_on && $cache && ! $load_only) {
756
            // return object if it's already cached
757
            $cached_class = $this->_get_cached_class($class_name, $class_prefix);
758
            if ($cached_class !== null) {
759
                return $cached_class;
760
            }
761
        }
762
        // if the class doesn't already exist.. then we need to try and find the file and load it
763
        if (! $class_exists) {
764
            // get full path to file
765
            $path = $this->_resolve_path($class_name, $type, $file_paths);
766
            // load the file
767
            $loaded = $this->_require_file($path, $class_name, $type, $file_paths);
768
            // if loading failed, or we are only loading a file but NOT instantiating an object
769
            if (! $loaded || $load_only) {
770
                // return boolean if only loading, or null if an object was expected
771
                return $load_only
772
                    ? $loaded
773
                    : null;
774
            }
775
        }
776
        // instantiate the requested object
777
        $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
778
        if ($this->_cache_on && $cache) {
779
            // save it for later... kinda like gum  { : $
780
            $this->_set_cached_class($class_obj, $class_name, $class_prefix, $from_db);
781
        }
782
        $this->_cache_on = true;
783
        return $class_obj;
784
    }
785
786
787
788
    /**
789
     * attempts to find a cached version of the requested class
790
     * by looking in the following places:
791
     *        $this->{$class_abbreviation}            ie:    $this->CART
792
     *        $this->{$class_name}                        ie:    $this->Some_Class
793
     *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
794
     *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
795
     *
796
     * @param string $class_name
797
     * @param string $class_prefix
798
     * @return mixed
799
     */
800
    protected function _get_cached_class($class_name, $class_prefix = '')
801
    {
802
        if ($class_name === 'EE_Registry') {
803
            return $this;
804
        }
805
        // have to specify something, but not anything that will conflict
806
        $class_abbreviation = isset($this->_class_abbreviations[$class_name])
807
            ? $this->_class_abbreviations[$class_name]
808
            : 'FANCY_BATMAN_PANTS';
809
        $class_name = str_replace('\\', '_', $class_name);
810
        // check if class has already been loaded, and return it if it has been
811
        if (isset($this->{$class_abbreviation})) {
812
            return $this->{$class_abbreviation};
813
        }
814
        if (isset ($this->{$class_name})) {
815
            return $this->{$class_name};
816
        }
817
        if (isset ($this->LIB->{$class_name})) {
818
            return $this->LIB->{$class_name};
819
        }
820
        if ($class_prefix === 'addon' && isset ($this->addons->{$class_name})) {
821
            return $this->addons->{$class_name};
822
        }
823
        return null;
824
    }
825
826
827
828
    /**
829
     * removes a cached version of the requested class
830
     *
831
     * @param string  $class_name
832
     * @param boolean $addon
833
     * @return boolean
834
     */
835
    public function clear_cached_class($class_name, $addon = false)
836
    {
837
        // have to specify something, but not anything that will conflict
838
        $class_abbreviation = isset($this->_class_abbreviations[$class_name])
839
            ? $this->_class_abbreviations[$class_name]
840
            : 'FANCY_BATMAN_PANTS';
841
        $class_name = str_replace('\\', '_', $class_name);
842
        // check if class has already been loaded, and return it if it has been
843
        if (isset($this->{$class_abbreviation})) {
844
            $this->{$class_abbreviation} = null;
845
            return true;
846
        }
847
        if (isset($this->{$class_name})) {
848
            $this->{$class_name} = null;
849
            return true;
850
        }
851
        if (isset($this->LIB->{$class_name})) {
852
            unset($this->LIB->{$class_name});
853
            return true;
854
        }
855
        if ($addon && isset($this->addons->{$class_name})) {
856
            unset($this->addons->{$class_name});
857
            return true;
858
        }
859
        return false;
860
    }
861
862
863
864
    /**
865
     * attempts to find a full valid filepath for the requested class.
866
     * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
867
     * then returns that path if the target file has been found and is readable
868
     *
869
     * @param string $class_name
870
     * @param string $type
871
     * @param array  $file_paths
872
     * @return string | bool
873
     */
874
    protected function _resolve_path($class_name, $type = '', $file_paths = array())
875
    {
876
        // make sure $file_paths is an array
877
        $file_paths = is_array($file_paths)
878
            ? $file_paths
879
            : array($file_paths);
880
        // cycle thru paths
881
        foreach ($file_paths as $key => $file_path) {
882
            // convert all separators to proper DS, if no filepath, then use EE_CLASSES
883
            $file_path = $file_path
884
                ? str_replace(array('/', '\\'), DS, $file_path)
885
                : EE_CLASSES;
886
            // prep file type
887
            $type = ! empty($type)
888
                ? trim($type, '.') . '.'
889
                : '';
890
            // build full file path
891
            $file_paths[$key] = rtrim($file_path, DS) . DS . $class_name . '.' . $type . 'php';
892
            //does the file exist and can be read ?
893
            if (is_readable($file_paths[$key])) {
894
                return $file_paths[$key];
895
            }
896
        }
897
        return false;
898
    }
899
900
901
902
    /**
903
     * basically just performs a require_once()
904
     * but with some error handling
905
     *
906
     * @param  string $path
907
     * @param  string $class_name
908
     * @param  string $type
909
     * @param  array  $file_paths
910
     * @return bool
911
     * @throws EE_Error
912
     * @throws ReflectionException
913
     */
914
    protected function _require_file($path, $class_name, $type = '', $file_paths = array())
915
    {
916
        // don't give up! you gotta...
917
        try {
918
            //does the file exist and can it be read ?
919 View Code Duplication
            if (! $path) {
920
                // so sorry, can't find the file
921
                throw new EE_Error (
922
                    sprintf(
923
                        esc_html__(
924
                            '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',
925
                            'event_espresso'
926
                        ),
927
                        trim($type, '.'),
928
                        $class_name,
929
                        '<br />' . implode(',<br />', $file_paths)
930
                    )
931
                );
932
            }
933
            // get the file
934
            require_once($path);
935
            // if the class isn't already declared somewhere
936
            if (class_exists($class_name, false) === false) {
937
                // so sorry, not a class
938
                throw new EE_Error(
939
                    sprintf(
940
                        esc_html__('The %s file %s does not appear to contain the %s Class.', 'event_espresso'),
941
                        $type,
942
                        $path,
943
                        $class_name
944
                    )
945
                );
946
            }
947
        } catch (EE_Error $e) {
948
            $e->get_error();
949
            return false;
950
        }
951
        return true;
952
    }
953
954
955
956
    /**
957
     * _create_object
958
     * Attempts to instantiate the requested class via any of the
959
     * commonly used instantiation methods employed throughout EE.
960
     * The priority for instantiation is as follows:
961
     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
962
     *        - model objects via their 'new_instance_from_db' method
963
     *        - model objects via their 'new_instance' method
964
     *        - "singleton" classes" via their 'instance' method
965
     *    - standard instantiable classes via their __constructor
966
     * Prior to instantiation, if the classname exists in the dependency_map,
967
     * then the constructor for the requested class will be examined to determine
968
     * if any dependencies exist, and if they can be injected.
969
     * If so, then those classes will be added to the array of arguments passed to the constructor
970
     *
971
     * @param string $class_name
972
     * @param array  $arguments
973
     * @param string $type
974
     * @param bool   $from_db
975
     * @return null|object
976
     * @throws EE_Error
977
     * @throws ReflectionException
978
     */
979
    protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
980
    {
981
        $class_obj = null;
982
        $instantiation_mode = '0) none';
983
        // don't give up! you gotta...
984
        try {
985
            // create reflection
986
            $reflector = $this->get_ReflectionClass($class_name);
987
            // make sure arguments are an array
988
            $arguments = is_array($arguments)
989
                ? $arguments
990
                : array($arguments);
991
            // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
992
            // else wrap it in an additional array so that it doesn't get split into multiple parameters
993
            $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
994
                ? $arguments
995
                : array($arguments);
996
            // attempt to inject dependencies ?
997
            if ($this->_dependency_map->has($class_name)) {
998
                $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
999
            }
1000
            // instantiate the class if possible
1001
            if ($reflector->isAbstract()) {
1002
                // nothing to instantiate, loading file was enough
1003
                // does not throw an exception so $instantiation_mode is unused
1004
                // $instantiation_mode = "1) no constructor abstract class";
1005
                $class_obj = true;
1006
            } else if (empty($arguments) && $reflector->getConstructor() === null && $reflector->isInstantiable()) {
1007
                // no constructor = static methods only... nothing to instantiate, loading file was enough
1008
                $instantiation_mode = '2) no constructor but instantiable';
1009
                $class_obj = $reflector->newInstance();
1010
            } else if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1011
                $instantiation_mode = '3) new_instance_from_db()';
1012
                $class_obj = call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1013
            } else if (method_exists($class_name, 'new_instance')) {
1014
                $instantiation_mode = '4) new_instance()';
1015
                $class_obj = call_user_func_array(array($class_name, 'new_instance'), $arguments);
1016
            } else if (method_exists($class_name, 'instance')) {
1017
                $instantiation_mode = '5) instance()';
1018
                $class_obj = call_user_func_array(array($class_name, 'instance'), $arguments);
1019
            } else if ($reflector->isInstantiable()) {
1020
                $instantiation_mode = '6) constructor';
1021
                $class_obj = $reflector->newInstanceArgs($arguments);
1022
            } else {
1023
                // heh ? something's not right !
1024
                throw new EE_Error(
1025
                    sprintf(
1026
                        esc_html__('The %s file %s could not be instantiated.', 'event_espresso'),
1027
                        $type,
1028
                        $class_name
1029
                    )
1030
                );
1031
            }
1032
        } catch (Exception $e) {
1033
            if (! $e instanceof EE_Error) {
1034
                $e = new EE_Error(
1035
                    sprintf(
1036
                        esc_html__(
1037
                            'The following error occurred while attempting to instantiate "%1$s": %2$s %3$s %2$s instantiation mode : %4$s',
1038
                            'event_espresso'
1039
                        ),
1040
                        $class_name,
1041
                        '<br />',
1042
                        $e->getMessage(),
1043
                        $instantiation_mode
1044
                    )
1045
                );
1046
            }
1047
            $e->get_error();
1048
        }
1049
        return $class_obj;
1050
    }
1051
1052
1053
1054
    /**
1055
     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1056
     * @param array $array
1057
     * @return bool
1058
     */
1059
    protected function _array_is_numerically_and_sequentially_indexed(array $array)
1060
    {
1061
        return ! empty($array)
1062
            ? array_keys($array) === range(0, count($array) - 1)
1063
            : true;
1064
    }
1065
1066
1067
1068
    /**
1069
     * getReflectionClass
1070
     * checks if a ReflectionClass object has already been generated for a class
1071
     * and returns that instead of creating a new one
1072
     *
1073
     * @param string $class_name
1074
     * @return ReflectionClass
1075
     * @throws ReflectionException
1076
     */
1077 View Code Duplication
    public function get_ReflectionClass($class_name)
1078
    {
1079
        if (
1080
            ! isset($this->_reflectors[$class_name])
1081
            || ! $this->_reflectors[$class_name] instanceof ReflectionClass
1082
        ) {
1083
            $this->_reflectors[$class_name] = new ReflectionClass($class_name);
1084
        }
1085
        return $this->_reflectors[$class_name];
1086
    }
1087
1088
1089
1090
    /**
1091
     * _resolve_dependencies
1092
     * examines the constructor for the requested class to determine
1093
     * if any dependencies exist, and if they can be injected.
1094
     * If so, then those classes will be added to the array of arguments passed to the constructor
1095
     * PLZ NOTE: this is achieved by type hinting the constructor params
1096
     * For example:
1097
     *        if attempting to load a class "Foo" with the following constructor:
1098
     *        __construct( Bar $bar_class, Fighter $grohl_class )
1099
     *        then $bar_class and $grohl_class will be added to the $arguments array,
1100
     *        but only IF they are NOT already present in the incoming arguments array,
1101
     *        and the correct classes can be loaded
1102
     *
1103
     * @param ReflectionClass $reflector
1104
     * @param string          $class_name
1105
     * @param array           $arguments
1106
     * @return array
1107
     * @throws EE_Error
1108
     * @throws ReflectionException
1109
     */
1110
    protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, $arguments = array())
1111
    {
1112
        // let's examine the constructor
1113
        $constructor = $reflector->getConstructor();
1114
        // whu? huh? nothing?
1115
        if (! $constructor) {
1116
            return $arguments;
1117
        }
1118
        // get constructor parameters
1119
        $params = $constructor->getParameters();
1120
        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1121
        $argument_keys = array_keys($arguments);
1122
        // now loop thru all of the constructors expected parameters
1123
        foreach ($params as $index => $param) {
1124
            // is this a dependency for a specific class ?
1125
            $param_class = $param->getClass()
1126
                ? $param->getClass()->name
1127
                : null;
1128
            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1129
            $param_class = $this->_dependency_map->has_alias($param_class, $class_name)
1130
                ? $this->_dependency_map->get_alias($param_class, $class_name)
1131
                : $param_class;
1132
            if (
1133
                // param is not even a class
1134
                empty($param_class)
1135
                // and something already exists in the incoming arguments for this param
1136
                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1137
            ) {
1138
                // so let's skip this argument and move on to the next
1139
                continue;
1140
            }
1141
            if (
1142
                // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1143
                ! empty($param_class)
1144
                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1145
                && $arguments[$argument_keys[$index]] instanceof $param_class
1146
            ) {
1147
                // skip this argument and move on to the next
1148
                continue;
1149
            }
1150
            if (
1151
                // parameter is type hinted as a class, and should be injected
1152
                ! empty($param_class)
1153
                && $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1154
            ) {
1155
                $arguments = $this->_resolve_dependency($class_name, $param_class, $arguments, $index);
1156
            } else {
1157
                try {
1158
                    $arguments[$index] = $param->getDefaultValue();
1159
                } catch (ReflectionException $e) {
1160
                    throw new ReflectionException(
1161
                        sprintf(
1162
                            esc_html__('%1$s for parameter "$%2$s"', 'event_espresso'),
1163
                            $e->getMessage(),
1164
                            $param->getName()
1165
                        )
1166
                    );
1167
                }
1168
            }
1169
        }
1170
        return $arguments;
1171
    }
1172
1173
1174
1175
    /**
1176
     * @param string $class_name
1177
     * @param string $param_class
1178
     * @param array  $arguments
1179
     * @param mixed  $index
1180
     * @return array
1181
     * @throws EE_Error
1182
     * @throws ReflectionException
1183
     */
1184
    protected function _resolve_dependency($class_name, $param_class, $arguments, $index)
1185
    {
1186
        $dependency = null;
1187
        // should dependency be loaded from cache ?
1188
        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency($class_name, $param_class)
1189
                    !== EE_Dependency_Map::load_new_object;
1190
        // we might have a dependency...
1191
        // let's MAYBE try and find it in our cache if that's what's been requested
1192
        $cached_class = $cache_on
1193
            ? $this->_get_cached_class($param_class)
1194
            : null;
1195
        // and grab it if it exists
1196
        if ($cached_class instanceof $param_class) {
1197
            $dependency = $cached_class;
1198
        } else if ($param_class !== $class_name) {
1199
            // obtain the loader method from the dependency map
1200
            $loader = $this->_dependency_map->class_loader($param_class);
1201
            // is loader a custom closure ?
1202
            if ($loader instanceof Closure) {
1203
                $dependency = $loader();
1204
            } else {
1205
                // set the cache on property for the recursive loading call
1206
                $this->_cache_on = $cache_on;
1207
                // if not, then let's try and load it via the registry
1208
                if ($loader && method_exists($this, $loader)) {
1209
                    $dependency = $this->{$loader}($param_class);
1210
                } else {
1211
                    $dependency = $this->create($param_class, array(), $cache_on);
1212
                }
1213
            }
1214
        }
1215
        // did we successfully find the correct dependency ?
1216
        if ($dependency instanceof $param_class) {
1217
            // then let's inject it into the incoming array of arguments at the correct location
1218
            if (isset($argument_keys[$index])) {
0 ignored issues
show
Bug introduced by
The variable $argument_keys seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
1219
                $arguments[$argument_keys[$index]] = $dependency;
1220
            } else {
1221
                $arguments[$index] = $dependency;
1222
            }
1223
        }
1224
        return $arguments;
1225
    }
1226
1227
1228
1229
    /**
1230
     * _set_cached_class
1231
     * attempts to cache the instantiated class locally
1232
     * in one of the following places, in the following order:
1233
     *        $this->{class_abbreviation}   ie:    $this->CART
1234
     *        $this->{$class_name}          ie:    $this->Some_Class
1235
     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1236
     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1237
     *
1238
     * @param object $class_obj
1239
     * @param string $class_name
1240
     * @param string $class_prefix
1241
     * @param bool   $from_db
1242
     * @return void
1243
     */
1244
    protected function _set_cached_class($class_obj, $class_name, $class_prefix = '', $from_db = false)
1245
    {
1246
        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1247
            return;
1248
        }
1249
        // return newly instantiated class
1250
        if (isset($this->_class_abbreviations[$class_name])) {
1251
            $class_abbreviation = $this->_class_abbreviations[$class_name];
1252
            $this->{$class_abbreviation} = $class_obj;
1253
            return;
1254
        }
1255
        $class_name = str_replace('\\', '_', $class_name);
1256
        if (property_exists($this, $class_name)) {
1257
            $this->{$class_name} = $class_obj;
1258
            return;
1259
        }
1260
        if ($class_prefix === 'addon') {
1261
            $this->addons->{$class_name} = $class_obj;
1262
            return;
1263
        }
1264
        if (! $from_db) {
1265
            $this->LIB->{$class_name} = $class_obj;
1266
        }
1267
    }
1268
1269
1270
1271
    /**
1272
     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1273
     *
1274
     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1275
     *                          in the EE_Dependency_Map::$_class_loaders array,
1276
     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1277
     * @param array  $arguments
1278
     * @return object
1279
     */
1280
    public static function factory($classname, $arguments = array())
1281
    {
1282
        $loader = self::instance()->_dependency_map->class_loader($classname);
1283
        if ($loader instanceof Closure) {
1284
            return $loader($arguments);
1285
        }
1286
        if (method_exists(self::instance(), $loader)) {
1287
            return self::instance()->{$loader}($classname, $arguments);
1288
        }
1289
        return null;
1290
    }
1291
1292
1293
1294
    /**
1295
     * Gets the addon by its name/slug (not classname. For that, just
1296
     * use the classname as the property name on EE_Config::instance()->addons)
1297
     *
1298
     * @param string $name
1299
     * @return EE_Addon
1300
     */
1301
    public function get_addon_by_name($name)
1302
    {
1303
        foreach ($this->addons as $addon) {
1304
            if ($addon->name() === $name) {
1305
                return $addon;
1306
            }
1307
        }
1308
        return null;
1309
    }
1310
1311
1312
1313
    /**
1314
     * Gets an array of all the registered addons, where the keys are their names. (ie, what each returns for their
1315
     * name() function) They're already available on EE_Config::instance()->addons as properties, where each property's
1316
     * name is the addon's classname. So if you just want to get the addon by classname, use
1317
     * EE_Config::instance()->addons->{classname}
1318
     *
1319
     * @return EE_Addon[] where the KEYS are the addon's name()
1320
     */
1321
    public function get_addons_by_name()
1322
    {
1323
        $addons = array();
1324
        foreach ($this->addons as $addon) {
1325
            $addons[$addon->name()] = $addon;
1326
        }
1327
        return $addons;
1328
    }
1329
1330
1331
1332
    /**
1333
     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1334
     * a stale copy of it around
1335
     *
1336
     * @param string $model_name
1337
     * @return \EEM_Base
1338
     * @throws \EE_Error
1339
     */
1340
    public function reset_model($model_name)
1341
    {
1342
        $model_class_name = strpos($model_name, 'EEM_') !== 0
1343
            ? "EEM_{$model_name}"
1344
            : $model_name;
1345
        if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1346
            return null;
1347
        }
1348
        //get that model reset it and make sure we nuke the old reference to it
1349
        if ($this->LIB->{$model_class_name} instanceof $model_class_name
1350
            && is_callable(
1351
                array($model_class_name, 'reset')
1352
            )) {
1353
            $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1354
        } else {
1355
            throw new EE_Error(sprintf(esc_html__('Model %s does not have a method "reset"', 'event_espresso'), $model_name));
1356
        }
1357
        return $this->LIB->{$model_class_name};
1358
    }
1359
1360
1361
1362
    /**
1363
     * Resets the registry.
1364
     * The criteria for what gets reset is based on what can be shared between sites on the same request when
1365
     * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1366
     * - $_dependency_map
1367
     * - $_class_abbreviations
1368
     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1369
     * - $REQ:  Still on the same request so no need to change.
1370
     * - $CAP: There is no site specific state in the EE_Capability class.
1371
     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1372
     * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1373
     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1374
     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1375
     *             switch or on the restore.
1376
     * - $modules
1377
     * - $shortcodes
1378
     * - $widgets
1379
     *
1380
     * @param boolean $hard             whether to reset data in the database too, or just refresh
1381
     *                                  the Registry to its state at the beginning of the request
1382
     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1383
     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1384
     *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1385
     * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1386
     *                                  client
1387
     *                                  code instead can just change the model context to a different blog id if
1388
     *                                  necessary
1389
     * @return EE_Registry
1390
     * @throws EE_Error
1391
     * @throws ReflectionException
1392
     */
1393
    public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1394
    {
1395
        $instance = self::instance();
1396
        $instance->_cache_on = true;
1397
        // reset some "special" classes
1398
        EEH_Activation::reset();
1399
        $instance->CFG = EE_Config::reset($hard, $reinstantiate);
1400
        $instance->CART = null;
1401
        $instance->MRM = null;
1402
        $instance->AssetsRegistry = $instance->create('EventEspresso\core\services\assets\Registry');
1403
        //messages reset
1404
        EED_Messages::reset();
1405
        //handle of objects cached on LIB
1406
        foreach (array('LIB', 'modules') as $cache) {
1407
            foreach ($instance->{$cache} as $class_name => $class) {
1408
                if (self::_reset_and_unset_object($class, $reset_models)) {
1409
                    unset($instance->{$cache}->{$class_name});
1410
                }
1411
            }
1412
        }
1413
        return $instance;
1414
    }
1415
1416
1417
1418
    /**
1419
     * if passed object implements ResettableInterface, then call it's reset() method
1420
     * if passed object implements InterminableInterface, then return false,
1421
     * to indicate that it should NOT be cleared from the Registry cache
1422
     *
1423
     * @param      $object
1424
     * @param bool $reset_models
1425
     * @return bool returns true if cached object should be unset
1426
     */
1427
    private static function _reset_and_unset_object($object, $reset_models)
1428
    {
1429
        if (! is_object($object)) {
1430
            // don't unset anything that's not an object
1431
            return false;
1432
        }
1433
        if ($object instanceof EED_Module) {
1434
            $object::reset();
1435
            // don't unset modules
1436
            return false;
1437
        }
1438
        if ($object instanceof ResettableInterface) {
1439
            if ($object instanceof EEM_Base) {
1440
                if ($reset_models) {
1441
                    $object->reset();
1442
                    return true;
1443
                }
1444
                return false;
1445
            }
1446
            $object->reset();
1447
            return true;
1448
        }
1449
        if (! $object instanceof InterminableInterface) {
1450
            return true;
1451
        }
1452
        return false;
1453
    }
1454
1455
1456
1457
    /**
1458
     * Gets all the custom post type models defined
1459
     *
1460
     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1461
     */
1462
    public function cpt_models()
1463
    {
1464
        $cpt_models = array();
1465
        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1466
            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1467
                $cpt_models[$short_name] = $classname;
1468
            }
1469
        }
1470
        return $cpt_models;
1471
    }
1472
1473
1474
1475
    /**
1476
     * @return \EE_Config
1477
     */
1478
    public static function CFG()
1479
    {
1480
        return self::instance()->CFG;
1481
    }
1482
1483
1484
}
1485
// End of file EE_Registry.core.php
1486
// Location: ./core/EE_Registry.core.php
1487