Completed
Branch FET-10766-extract-activation-d... (6ba6fc)
by
unknown
84:12 queued 72:44
created

EE_Registry   D

Complexity

Total Complexity 180

Size/Duplication

Total Lines 1501
Duplicated Lines 3.46 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
dl 52
loc 1501
rs 4.4102
c 0
b 0
f 0
wmc 180
lcom 1
cbo 9

52 Methods

Rating   Name   Duplication   Size   Complexity  
A localize_i18n_js_strings() 0 10 3
A add_module() 0 12 3
A get_module() 0 4 2
A load_core() 0 16 1
A load_service() 0 11 1
A load_dms() 0 5 1
A load_class() 0 10 1
A load_helper() 0 7 1
A load_lib() 0 12 1
A load_model() 0 9 1
A load_model_class() 0 11 1
A is_model_name() 0 4 2
A load_file() 0 5 1
A load_addon() 0 5 1
A init() 0 8 3
A instance() 0 8 2
A __construct() 0 10 1
B initialize() 0 30 1
C create() 7 43 12
D loadOrVerifyClassExists() 0 25 9
C _load() 7 57 15
D _get_cached_class() 3 25 9
C clear_cached_class() 4 26 8
B _resolve_path() 0 19 6
B _require_file() 22 36 4
D _create_object() 0 67 15
A _array_is_numerically_and_sequentially_indexed() 0 4 2
A get_ReflectionClass() 9 10 3
C _resolve_dependencies() 0 60 13
D _resolve_dependency() 0 42 10
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 14 6
B reset() 0 23 4
B _reset_and_unset_object() 0 20 5
A __destruct() 0 3 1
A __call() 0 3 1
A __get() 0 3 1
A __set() 0 3 1
A __isset() 0 3 1
A __unset() 0 3 1
A __sleep() 0 4 1
A __wakeup() 0 3 1
A __toString() 0 4 1
A __invoke() 0 3 1
A __set_state() 0 4 1
A __clone() 0 3 1
A __callStatic() 0 3 1
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
7
defined('EVENT_ESPRESSO_VERSION') || exit;
8
9
10
11
/**
12
 * EE_Registry Class
13
 * Centralized Application Data Storage and Management
14
 *
15
 * @package                   Event Espresso
16
 * @subpackage                core
17
 * @author                    Brent Christensen
18
 */
19
class EE_Registry implements ResettableInterface
20
{
21
22
    /**
23
     *    EE_Registry Object
24
     *
25
     * @var EE_Registry $_instance
26
     * @access    private
27
     */
28
    private static $_instance = null;
29
30
    /**
31
     * @var EE_Dependency_Map $_dependency_map
32
     * @access    protected
33
     */
34
    protected $_dependency_map = null;
35
36
    /**
37
     * @var array $_class_abbreviations
38
     * @access    protected
39
     */
40
    protected $_class_abbreviations = array();
41
42
    /**
43
     * @access public
44
     * @var \EventEspresso\core\services\commands\CommandBusInterface $BUS
45
     */
46
    public $BUS;
47
48
    /**
49
     *    EE_Cart Object
50
     *
51
     * @access    public
52
     * @var    EE_Cart $CART
53
     */
54
    public $CART = null;
55
56
    /**
57
     *    EE_Config Object
58
     *
59
     * @access    public
60
     * @var    EE_Config $CFG
61
     */
62
    public $CFG = null;
63
64
    /**
65
     * EE_Network_Config Object
66
     *
67
     * @access public
68
     * @var EE_Network_Config $NET_CFG
69
     */
70
    public $NET_CFG = null;
71
72
    /**
73
     *    StdClass object for storing library classes in
74
     *
75
     * @public LIB
76
     * @var StdClass $LIB
77
     */
78
    public $LIB = null;
79
80
    /**
81
     *    EE_Request_Handler Object
82
     *
83
     * @access    public
84
     * @var    EE_Request_Handler $REQ
85
     */
86
    public $REQ = null;
87
88
    /**
89
     *    EE_Session Object
90
     *
91
     * @access    public
92
     * @var    EE_Session $SSN
93
     */
94
    public $SSN = null;
95
96
    /**
97
     * holds the ee capabilities object.
98
     *
99
     * @since 4.5.0
100
     * @var EE_Capabilities
101
     */
102
    public $CAP = null;
103
104
    /**
105
     * holds the EE_Message_Resource_Manager object.
106
     *
107
     * @since 4.9.0
108
     * @var EE_Message_Resource_Manager
109
     */
110
    public $MRM = null;
111
112
113
    /**
114
     * Holds the Assets Registry instance
115
     * @var Registry
116
     */
117
    public $AssetsRegistry = null;
118
119
    /**
120
     * StdClass object for holding addons which have registered themselves to work with EE core
121
     *
122
     * @var StdClass
123
     */
124
    public $addons = null;
125
126
    /**
127
     *    $models
128
     * @access    public
129
     * @var    EEM_Base[] $models keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
130
     */
131
    public $models = array();
132
133
    /**
134
     *    $modules
135
     * @access    public
136
     * @var    EED_Module[] $modules
137
     */
138
    public $modules = null;
139
140
    /**
141
     *    $shortcodes
142
     * @access    public
143
     * @var    EES_Shortcode[] $shortcodes
144
     */
145
    public $shortcodes = null;
146
147
    /**
148
     *    $widgets
149
     * @access    public
150
     * @var    WP_Widget[] $widgets
151
     */
152
    public $widgets = null;
153
154
    /**
155
     * $non_abstract_db_models
156
     * @access public
157
     * @var array this is an array of all implemented model names (i.e. not the parent abstract models, or models
158
     * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
159
     * Keys are model "short names" (eg "Event") as used in model relations, and values are
160
     * classnames (eg "EEM_Event")
161
     */
162
    public $non_abstract_db_models = array();
163
164
165
    /**
166
     *    $i18n_js_strings - internationalization for JS strings
167
     *    usage:   EE_Registry::i18n_js_strings['string_key'] = __( 'string to translate.', 'event_espresso' );
168
     *    in js file:  var translatedString = eei18n.string_key;
169
     *
170
     * @access    public
171
     * @var    array
172
     */
173
    public static $i18n_js_strings = array();
174
175
176
    /**
177
     *    $main_file - path to espresso.php
178
     *
179
     * @access    public
180
     * @var    array
181
     */
182
    public $main_file;
183
184
    /**
185
     * array of ReflectionClass objects where the key is the class name
186
     *
187
     * @access    public
188
     * @var ReflectionClass[]
189
     */
190
    public $_reflectors;
191
192
    /**
193
     * boolean flag to indicate whether or not to load/save dependencies from/to the cache
194
     *
195
     * @access    protected
196
     * @var boolean $_cache_on
197
     */
198
    protected $_cache_on = true;
199
200
201
202
    /**
203
     * @singleton method used to instantiate class object
204
     * @access    public
205
     * @param  \EE_Dependency_Map $dependency_map
206
     * @return \EE_Registry instance
207
     */
208
    public static function instance(\EE_Dependency_Map $dependency_map = null)
209
    {
210
        // check if class object is instantiated
211
        if ( ! self::$_instance instanceof EE_Registry) {
212
            self::$_instance = new EE_Registry($dependency_map);
0 ignored issues
show
Bug introduced by
It seems like $dependency_map defined by parameter $dependency_map on line 208 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...
213
        }
214
        return self::$_instance;
215
    }
216
217
218
219
    /**
220
     *protected constructor to prevent direct creation
221
     *
222
     * @Constructor
223
     * @access protected
224
     * @param  \EE_Dependency_Map $dependency_map
225
     */
226
    protected function __construct(\EE_Dependency_Map $dependency_map)
227
    {
228
        $this->_dependency_map = $dependency_map;
229
        $this->LIB = new stdClass();
230
        $this->addons = new stdClass();
231
        $this->modules = new stdClass();
232
        $this->shortcodes = new stdClass();
233
        $this->widgets = new stdClass();
234
        add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
235
    }
236
237
238
239
    /**
240
     * initialize
241
     */
242
    public function initialize()
243
    {
244
        $this->_class_abbreviations = apply_filters(
245
            'FHEE__EE_Registry____construct___class_abbreviations',
246
            array(
247
                'EE_Config'                                       => 'CFG',
248
                'EE_Session'                                      => 'SSN',
249
                'EE_Capabilities'                                 => 'CAP',
250
                'EE_Cart'                                         => 'CART',
251
                'EE_Network_Config'                               => 'NET_CFG',
252
                'EE_Request_Handler'                              => 'REQ',
253
                'EE_Message_Resource_Manager'                     => 'MRM',
254
                'EventEspresso\core\services\commands\CommandBus' => 'BUS',
255
                'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
256
            )
257
        );
258
        $this->load_core('Base', array(), true);
259
        // add our request and response objects to the cache
260
        $request_loader = $this->_dependency_map->class_loader('EE_Request');
261
        $this->_set_cached_class(
262
            $request_loader(),
263
            'EE_Request'
264
        );
265
        $response_loader = $this->_dependency_map->class_loader('EE_Response');
266
        $this->_set_cached_class(
267
            $response_loader(),
268
            'EE_Response'
269
        );
270
        add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
271
    }
272
273
274
275
    /**
276
     *    init
277
     *
278
     * @access    public
279
     * @return    void
280
     */
281
    public function init()
282
    {
283
        // Get current page protocol
284
        $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
285
        // Output admin-ajax.php URL with same protocol as current page
286
        self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
287
        self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
288
    }
289
290
291
292
    /**
293
     * localize_i18n_js_strings
294
     *
295
     * @return string
296
     */
297
    public static function localize_i18n_js_strings()
298
    {
299
        $i18n_js_strings = (array)EE_Registry::$i18n_js_strings;
300
        foreach ($i18n_js_strings as $key => $value) {
301
            if (is_scalar($value)) {
302
                $i18n_js_strings[$key] = html_entity_decode((string)$value, ENT_QUOTES, 'UTF-8');
303
            }
304
        }
305
        return "/* <![CDATA[ */ var eei18n = " . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
306
    }
307
308
309
310
    /**
311
     * @param mixed string | EED_Module $module
312
     */
313
    public function add_module($module)
314
    {
315
        if ($module instanceof EED_Module) {
316
            $module_class = get_class($module);
317
            $this->modules->{$module_class} = $module;
318
        } else {
319
            if ( ! class_exists('EE_Module_Request_Router')) {
320
                $this->load_core('Module_Request_Router');
321
            }
322
            $this->modules->{$module} = EE_Module_Request_Router::module_factory($module);
323
        }
324
    }
325
326
327
328
    /**
329
     * @param string $module_name
330
     * @return mixed EED_Module | NULL
331
     */
332
    public function get_module($module_name = '')
333
    {
334
        return isset($this->modules->{$module_name}) ? $this->modules->{$module_name} : null;
335
    }
336
337
338
339
    /**
340
     *    loads core classes - must be singletons
341
     *
342
     * @access    public
343
     * @param string $class_name - simple class name ie: session
344
     * @param mixed  $arguments
345
     * @param bool   $load_only
346
     * @return mixed
347
     */
348
    public function load_core($class_name, $arguments = array(), $load_only = false)
349
    {
350
        $core_paths = apply_filters(
351
            'FHEE__EE_Registry__load_core__core_paths',
352
            array(
353
                EE_CORE,
354
                EE_ADMIN,
355
                EE_CPTS,
356
                EE_CORE . 'data_migration_scripts' . DS,
357
                EE_CORE . 'request_stack' . DS,
358
                EE_CORE . 'middleware' . DS,
359
            )
360
        );
361
        // retrieve instantiated class
362
        return $this->_load($core_paths, 'EE_', $class_name, 'core', $arguments, false, true, $load_only);
363
    }
364
365
366
367
    /**
368
     *    loads service classes
369
     *
370
     * @access    public
371
     * @param string $class_name - simple class name ie: session
372
     * @param mixed  $arguments
373
     * @param bool   $load_only
374
     * @return mixed
375
     */
376
    public function load_service($class_name, $arguments = array(), $load_only = false)
377
    {
378
        $service_paths = apply_filters(
379
            'FHEE__EE_Registry__load_service__service_paths',
380
            array(
381
                EE_CORE . 'services' . DS,
382
            )
383
        );
384
        // retrieve instantiated class
385
        return $this->_load($service_paths, 'EE_', $class_name, 'class', $arguments, false, true, $load_only);
386
    }
387
388
389
390
    /**
391
     *    loads data_migration_scripts
392
     *
393
     * @access    public
394
     * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
395
     * @param mixed  $arguments
396
     * @return EE_Data_Migration_Script_Base|mixed
397
     */
398
    public function load_dms($class_name, $arguments = array())
399
    {
400
        // retrieve instantiated class
401
        return $this->_load(EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(), 'EE_DMS_', $class_name, 'dms', $arguments, false, false, false);
402
    }
403
404
405
406
    /**
407
     *    loads object creating classes - must be singletons
408
     *
409
     * @param string $class_name - simple class name ie: attendee
410
     * @param mixed  $arguments  - an array of arguments to pass to the class
411
     * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to instantiate
412
     * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then set this to FALSE (ie. when instantiating model objects from client in a loop)
413
     * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate (default)
414
     * @return EE_Base_Class | bool
415
     */
416
    public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
417
    {
418
        $paths = apply_filters('FHEE__EE_Registry__load_class__paths', array(
419
            EE_CORE,
420
            EE_CLASSES,
421
            EE_BUSINESS,
422
        ));
423
        // retrieve instantiated class
424
        return $this->_load($paths, 'EE_', $class_name, 'class', $arguments, $from_db, $cache, $load_only);
425
    }
426
427
428
429
    /**
430
     *    loads helper classes - must be singletons
431
     *
432
     * @param string $class_name - simple class name ie: price
433
     * @param mixed  $arguments
434
     * @param bool   $load_only
435
     * @return EEH_Base | bool
436
     */
437
    public function load_helper($class_name, $arguments = array(), $load_only = true)
438
    {
439
        // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
440
        $helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
441
        // retrieve instantiated class
442
        return $this->_load($helper_paths, 'EEH_', $class_name, 'helper', $arguments, false, true, $load_only);
443
    }
444
445
446
447
    /**
448
     *    loads core classes - must be singletons
449
     *
450
     * @access    public
451
     * @param string $class_name - simple class name ie: session
452
     * @param mixed  $arguments
453
     * @param bool   $load_only
454
     * @param bool   $cache      whether to cache the object or not.
455
     * @return mixed
456
     */
457
    public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
458
    {
459
        $paths = array(
460
            EE_LIBRARIES,
461
            EE_LIBRARIES . 'messages' . DS,
462
            EE_LIBRARIES . 'shortcodes' . DS,
463
            EE_LIBRARIES . 'qtips' . DS,
464
            EE_LIBRARIES . 'payment_methods' . DS,
465
        );
466
        // retrieve instantiated class
467
        return $this->_load($paths, 'EE_', $class_name, 'lib', $arguments, false, $cache, $load_only);
468
    }
469
470
471
472
    /**
473
     *    loads model classes - must be singletons
474
     *
475
     * @param string $class_name - simple class name ie: price
476
     * @param mixed  $arguments
477
     * @param bool   $load_only
478
     * @return EEM_Base | bool
479
     */
480
    public function load_model($class_name, $arguments = array(), $load_only = false)
481
    {
482
        $paths = apply_filters('FHEE__EE_Registry__load_model__paths', array(
483
            EE_MODELS,
484
            EE_CORE,
485
        ));
486
        // retrieve instantiated class
487
        return $this->_load($paths, 'EEM_', $class_name, 'model', $arguments, false, true, $load_only);
488
    }
489
490
491
492
    /**
493
     *    loads model classes - must be singletons
494
     *
495
     * @param string $class_name - simple class name ie: price
496
     * @param mixed  $arguments
497
     * @param bool   $load_only
498
     * @return mixed | bool
499
     */
500
    public function load_model_class($class_name, $arguments = array(), $load_only = true)
501
    {
502
        $paths = array(
503
            EE_MODELS . 'fields' . DS,
504
            EE_MODELS . 'helpers' . DS,
505
            EE_MODELS . 'relations' . DS,
506
            EE_MODELS . 'strategies' . DS,
507
        );
508
        // retrieve instantiated class
509
        return $this->_load($paths, 'EE_', $class_name, '', $arguments, false, true, $load_only);
510
    }
511
512
513
514
    /**
515
     * Determines if $model_name is the name of an actual EE model.
516
     *
517
     * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
518
     * @return boolean
519
     */
520
    public function is_model_name($model_name)
521
    {
522
        return isset($this->models[$model_name]) ? true : false;
523
    }
524
525
526
527
    /**
528
     *    generic class loader
529
     *
530
     * @param string $path_to_file - directory path to file location, not including filename
531
     * @param string $file_name    - file name  ie:  my_file.php, including extension
532
     * @param string $type         - file type - core? class? helper? model?
533
     * @param mixed  $arguments
534
     * @param bool   $load_only
535
     * @return mixed
536
     */
537
    public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
538
    {
539
        // retrieve instantiated class
540
        return $this->_load($path_to_file, '', $file_name, $type, $arguments, false, true, $load_only);
541
    }
542
543
544
545
    /**
546
     *    load_addon
547
     *
548
     * @param string $path_to_file - directory path to file location, not including filename
549
     * @param string $class_name   - full class name  ie:  My_Class
550
     * @param string $type         - file type - core? class? helper? model?
551
     * @param mixed  $arguments
552
     * @param bool   $load_only
553
     * @return EE_Addon
554
     */
555
    public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
556
    {
557
        // retrieve instantiated class
558
        return $this->_load($path_to_file, 'addon', $class_name, $type, $arguments, false, true, $load_only);
559
    }
560
561
562
563
    /**
564
     * instantiates, caches, and automatically resolves dependencies
565
     * for classes that use a Fully Qualified Class Name.
566
     * if the class is not capable of being loaded using PSR-4 autoloading,
567
     * then you need to use one of the existing load_*() methods
568
     * which can resolve the classname and filepath from the passed arguments
569
     *
570
     * @param bool|string $class_name   Fully Qualified Class Name
571
     * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
572
     * @param bool        $cache        whether to cache the instantiated object for reuse
573
     * @param bool        $from_db      some classes are instantiated from the db
574
     *                                  and thus call a different method to instantiate
575
     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
576
     * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
577
     * @return mixed null = failure to load or instantiate class object.
578
     *                                  object = class loaded and instantiated successfully.
579
     *                                  bool = fail or success when $load_only is true
580
     * @throws EE_Error
581
     */
582
    public function create(
583
        $class_name = false,
584
        $arguments = array(),
585
        $cache = false,
586
        $from_db = false,
587
        $load_only = false,
588
        $addon = false
589
    ) {
590
        $class_name = ltrim($class_name, '\\');
591
        $class_name = $this->_dependency_map->get_alias($class_name);
592
        $class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
593
        // if a non-FQCN was passed, then verifyClassExists() might return an object
594
        // or it could return null if the class just could not be found anywhere
595
        if ($class_exists instanceof $class_name || $class_exists === null){
596
            // either way, return the results
597
            return $class_exists;
598
        }
599
        $class_name = $class_exists;
600
        // if we're only loading the class and it already exists, then let's just return true immediately
601
        if ($load_only) {
602
            return true;
603
        }
604
        $addon = $addon ? 'addon' : '';
605
        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
606
        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
607
        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
608 View Code Duplication
        if ($this->_cache_on && $cache && ! $load_only) {
609
            // return object if it's already cached
610
            $cached_class = $this->_get_cached_class($class_name, $addon);
611
            if ($cached_class !== null) {
612
                return $cached_class;
613
            }
614
        }
615
        // instantiate the requested object
616
        $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $class_obj is correct as $this->_create_object($c...ents, $addon, $from_db) (which targets EE_Registry::_create_object()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
617
        // if caching is turned on OR this class is cached in a class property
618
        if (($this->_cache_on && $cache) || isset($this->_class_abbreviations[ $class_name ])) {
619
            // save it for later... kinda like gum  { : $
620
            $this->_set_cached_class($class_obj, $class_name, $addon, $from_db);
621
        }
622
        $this->_cache_on = true;
623
        return $class_obj;
624
    }
625
626
627
628
    /**
629
     * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
630
     *
631
     * @param string $class_name
632
     * @param array  $arguments
633
     * @param int    $attempt
634
     * @return mixed
635
     */
636
    private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1) {
637
        if (is_object($class_name) || class_exists($class_name)) {
638
            return $class_name;
639
        }
640
        switch ($attempt) {
641
            case 1:
642
                // if it's a FQCN then maybe the class is registered with a preceding \
643
                $class_name = strpos($class_name, '\\') !== false
644
                    ? '\\' . ltrim($class_name, '\\')
645
                    : $class_name;
646
                break;
647
            case 2:
648
                //
649
                $loader = $this->_dependency_map->class_loader($class_name);
650
                if ($loader && method_exists($this, $loader)) {
651
                    return $this->{$loader}($class_name, $arguments);
652
                }
653
                break;
654
            case 3:
655
            default;
656
                return null;
657
        }
658
        $attempt++;
659
        return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
660
    }
661
662
663
664
    /**
665
     * instantiates, caches, and injects dependencies for classes
666
     *
667
     * @param array       $file_paths   an array of paths to folders to look in
668
     * @param string      $class_prefix EE  or EEM or... ???
669
     * @param bool|string $class_name   $class name
670
     * @param string      $type         file type - core? class? helper? model?
671
     * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
672
     * @param bool        $from_db      some classes are instantiated from the db
673
     *                                  and thus call a different method to instantiate
674
     * @param bool        $cache        whether to cache the instantiated object for reuse
675
     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
676
     * @return bool|null|object null = failure to load or instantiate class object.
677
     *                                  object = class loaded and instantiated successfully.
678
     *                                  bool = fail or success when $load_only is true
679
     * @throws EE_Error
680
     */
681
    protected function _load(
682
        $file_paths = array(),
683
        $class_prefix = 'EE_',
684
        $class_name = false,
685
        $type = 'class',
686
        $arguments = array(),
687
        $from_db = false,
688
        $cache = true,
689
        $load_only = false
690
    ) {
691
        $class_name = ltrim($class_name, '\\');
692
        // strip php file extension
693
        $class_name = str_replace('.php', '', trim($class_name));
694
        // does the class have a prefix ?
695
        if ( ! empty($class_prefix) && $class_prefix != 'addon') {
696
            // make sure $class_prefix is uppercase
697
            $class_prefix = strtoupper(trim($class_prefix));
698
            // add class prefix ONCE!!!
699
            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
700
        }
701
        $class_name = $this->_dependency_map->get_alias($class_name);
702
        $class_exists = class_exists($class_name);
703
        // if we're only loading the class and it already exists, then let's just return true immediately
704
        if ($load_only && $class_exists) {
705
            return true;
706
        }
707
        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
708
        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
709
        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
710 View Code Duplication
        if ($this->_cache_on && $cache && ! $load_only) {
711
            // return object if it's already cached
712
            $cached_class = $this->_get_cached_class($class_name, $class_prefix);
713
            if ($cached_class !== null) {
714
                return $cached_class;
715
            }
716
        }
717
        // if the class doesn't already exist.. then we need to try and find the file and load it
718
        if ( ! $class_exists) {
719
            // get full path to file
720
            $path = $this->_resolve_path($class_name, $type, $file_paths);
721
            // load the file
722
            $loaded = $this->_require_file($path, $class_name, $type, $file_paths);
723
            // if loading failed, or we are only loading a file but NOT instantiating an object
724
            if ( ! $loaded || $load_only) {
725
                // return boolean if only loading, or null if an object was expected
726
                return $load_only ? $loaded : null;
727
            }
728
        }
729
        // instantiate the requested object
730
        $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $class_obj is correct as $this->_create_object($c...ments, $type, $from_db) (which targets EE_Registry::_create_object()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
731
        if ($this->_cache_on && $cache) {
732
            // save it for later... kinda like gum  { : $
733
            $this->_set_cached_class($class_obj, $class_name, $class_prefix, $from_db);
734
        }
735
        $this->_cache_on = true;
736
        return $class_obj;
737
    }
738
739
740
741
742
    /**
743
     * _get_cached_class
744
     * attempts to find a cached version of the requested class
745
     * by looking in the following places:
746
     *        $this->{$class_abbreviation}            ie:    $this->CART
747
     *        $this->{$class_name}                        ie:    $this->Some_Class
748
     *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
749
     *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
750
     *
751
     * @access protected
752
     * @param string $class_name
753
     * @param string $class_prefix
754
     * @return mixed
755
     */
756
    protected function _get_cached_class($class_name, $class_prefix = '')
757
    {
758
        if ($class_name === 'EE_Registry') {
759
            return $this;
760
        }
761
        // have to specify something, but not anything that will conflict
762
        $class_abbreviation = isset($this->_class_abbreviations[ $class_name ])
763
            ? $this->_class_abbreviations[ $class_name ]
764
            : 'FANCY_BATMAN_PANTS';
765
        $class_name = str_replace('\\', '_', $class_name);
766
        // check if class has already been loaded, and return it if it has been
767 View Code Duplication
        if (isset($this->{$class_abbreviation}) && ! is_null($this->{$class_abbreviation})) {
768
            return $this->{$class_abbreviation};
769
        }
770
        if (isset ($this->{$class_name})) {
771
            return $this->{$class_name};
772
        }
773
        if (isset ($this->LIB->{$class_name})) {
774
            return $this->LIB->{$class_name};
775
        }
776
        if ($class_prefix === 'addon' && isset ($this->addons->{$class_name})) {
777
            return $this->addons->{$class_name};
778
        }
779
        return null;
780
    }
781
782
783
784
    /**
785
     * removes a cached version of the requested class
786
     *
787
     * @param string $class_name
788
     * @param boolean $addon
789
     * @return boolean
790
     */
791
    public function clear_cached_class($class_name, $addon = false)
792
    {
793
        // have to specify something, but not anything that will conflict
794
        $class_abbreviation = isset($this->_class_abbreviations[ $class_name ])
795
            ? $this->_class_abbreviations[ $class_name ]
796
            : 'FANCY_BATMAN_PANTS';
797
        $class_name = str_replace('\\', '_', $class_name);
798
        // check if class has already been loaded, and return it if it has been
799 View Code Duplication
        if (isset($this->{$class_abbreviation}) && ! is_null($this->{$class_abbreviation})) {
800
            $this->{$class_abbreviation} = null;
801
            return true;
802
        }
803
        if (isset($this->{$class_name})) {
804
            $this->{$class_name} = null;
805
            return true;
806
        }
807
        if (isset($this->LIB->{$class_name})) {
808
            unset($this->LIB->{$class_name});
809
            return true;
810
        }
811
        if ($addon && isset($this->addons->{$class_name})) {
812
            unset($this->addons->{$class_name});
813
            return true;
814
        }
815
        return false;
816
    }
817
818
819
    /**
820
     * _resolve_path
821
     * attempts to find a full valid filepath for the requested class.
822
     * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
823
     * then returns that path if the target file has been found and is readable
824
     *
825
     * @access protected
826
     * @param string $class_name
827
     * @param string $type
828
     * @param array  $file_paths
829
     * @return string | bool
830
     */
831
    protected function _resolve_path($class_name, $type = '', $file_paths = array())
832
    {
833
        // make sure $file_paths is an array
834
        $file_paths = is_array($file_paths) ? $file_paths : array($file_paths);
835
        // cycle thru paths
836
        foreach ($file_paths as $key => $file_path) {
837
            // convert all separators to proper DS, if no filepath, then use EE_CLASSES
838
            $file_path = $file_path ? str_replace(array('/', '\\'), DS, $file_path) : EE_CLASSES;
839
            // prep file type
840
            $type = ! empty($type) ? trim($type, '.') . '.' : '';
841
            // build full file path
842
            $file_paths[$key] = rtrim($file_path, DS) . DS . $class_name . '.' . $type . 'php';
843
            //does the file exist and can be read ?
844
            if (is_readable($file_paths[$key])) {
845
                return $file_paths[$key];
846
            }
847
        }
848
        return false;
849
    }
850
851
852
853
    /**
854
     * _require_file
855
     * basically just performs a require_once()
856
     * but with some error handling
857
     *
858
     * @access protected
859
     * @param  string $path
860
     * @param  string $class_name
861
     * @param  string $type
862
     * @param  array  $file_paths
863
     * @return boolean
864
     * @throws \EE_Error
865
     */
866
    protected function _require_file($path, $class_name, $type = '', $file_paths = array())
867
    {
868
        // don't give up! you gotta...
869
        try {
870
            //does the file exist and can it be read ?
871 View Code Duplication
            if ( ! $path) {
872
                // so sorry, can't find the file
873
                throw new EE_Error (
874
                    sprintf(
875
                        __('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', 'event_espresso'),
876
                        trim($type, '.'),
877
                        $class_name,
878
                        '<br />' . implode(',<br />', $file_paths)
879
                    )
880
                );
881
            }
882
            // get the file
883
            require_once($path);
884
            // if the class isn't already declared somewhere
885 View Code Duplication
            if (class_exists($class_name, false) === false) {
886
                // so sorry, not a class
887
                throw new EE_Error(
888
                    sprintf(
889
                        __('The %s file %s does not appear to contain the %s Class.', 'event_espresso'),
890
                        $type,
891
                        $path,
892
                        $class_name
893
                    )
894
                );
895
            }
896
        } catch (EE_Error $e) {
897
            $e->get_error();
898
            return false;
899
        }
900
        return true;
901
    }
902
903
904
905
    /**
906
     * _create_object
907
     * Attempts to instantiate the requested class via any of the
908
     * commonly used instantiation methods employed throughout EE.
909
     * The priority for instantiation is as follows:
910
     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
911
     *        - model objects via their 'new_instance_from_db' method
912
     *        - model objects via their 'new_instance' method
913
     *        - "singleton" classes" via their 'instance' method
914
     *    - standard instantiable classes via their __constructor
915
     * Prior to instantiation, if the classname exists in the dependency_map,
916
     * then the constructor for the requested class will be examined to determine
917
     * if any dependencies exist, and if they can be injected.
918
     * If so, then those classes will be added to the array of arguments passed to the constructor
919
     *
920
     * @access protected
921
     * @param string $class_name
922
     * @param array  $arguments
923
     * @param string $type
924
     * @param bool   $from_db
925
     * @return null | object
926
     * @throws \EE_Error
927
     */
928
    protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
929
    {
930
        $class_obj = null;
931
        $instantiation_mode = '0) none';
932
        // don't give up! you gotta...
933
        try {
934
            // create reflection
935
            $reflector = $this->get_ReflectionClass($class_name);
936
            // make sure arguments are an array
937
            $arguments = is_array($arguments) ? $arguments : array($arguments);
938
            // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
939
            // else wrap it in an additional array so that it doesn't get split into multiple parameters
940
            $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
941
                ? $arguments
942
                : array($arguments);
943
            // attempt to inject dependencies ?
944
            if ($this->_dependency_map->has($class_name)) {
945
                $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
946
            }
947
            // instantiate the class if possible
948
            if ($reflector->isAbstract()) {
949
                // nothing to instantiate, loading file was enough
950
                // does not throw an exception so $instantiation_mode is unused
951
                // $instantiation_mode = "1) no constructor abstract class";
952
                $class_obj = true;
953
            } else if ($reflector->getConstructor() === null && $reflector->isInstantiable() && empty($arguments)) {
954
                // no constructor = static methods only... nothing to instantiate, loading file was enough
955
                $instantiation_mode = "2) no constructor but instantiable";
956
                $class_obj = $reflector->newInstance();
957
            } else if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
958
                $instantiation_mode = "3) new_instance_from_db()";
959
                $class_obj = call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
960
            } else if (method_exists($class_name, 'new_instance')) {
961
                $instantiation_mode = "4) new_instance()";
962
                $class_obj = call_user_func_array(array($class_name, 'new_instance'), $arguments);
963
            } else if (method_exists($class_name, 'instance')) {
964
                $instantiation_mode = "5) instance()";
965
                $class_obj = call_user_func_array(array($class_name, 'instance'), $arguments);
966
            } else if ($reflector->isInstantiable()) {
967
                $instantiation_mode = "6) constructor";
968
                $class_obj = $reflector->newInstanceArgs($arguments);
969
            } else {
970
                // heh ? something's not right !
971
                throw new EE_Error(
972
                    sprintf(
973
                        __('The %s file %s could not be instantiated.', 'event_espresso'),
974
                        $type,
975
                        $class_name
976
                    )
977
                );
978
            }
979
        } catch (Exception $e) {
980
            if ( ! $e instanceof EE_Error) {
981
                $e = new EE_Error(
982
                    sprintf(
983
                        __('The following error occurred while attempting to instantiate "%1$s": %2$s %3$s %2$s instantiation mode : %4$s', 'event_espresso'),
984
                        $class_name,
985
                        '<br />',
986
                        $e->getMessage(),
987
                        $instantiation_mode
988
                    )
989
                );
990
            }
991
            $e->get_error();
992
        }
993
        return $class_obj;
994
    }
995
996
997
998
    /**
999
     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1000
     * @param array $array
1001
     * @return bool
1002
     */
1003
    protected function _array_is_numerically_and_sequentially_indexed(array $array)
1004
    {
1005
        return ! empty($array) ? array_keys($array) === range(0, count($array) - 1) : true;
1006
    }
1007
1008
1009
1010
    /**
1011
     * getReflectionClass
1012
     * checks if a ReflectionClass object has already been generated for a class
1013
     * and returns that instead of creating a new one
1014
     *
1015
     * @access public
1016
     * @param string $class_name
1017
     * @return ReflectionClass
1018
     */
1019 View Code Duplication
    public function get_ReflectionClass($class_name)
1020
    {
1021
        if (
1022
            ! isset($this->_reflectors[$class_name])
1023
            || ! $this->_reflectors[$class_name] instanceof ReflectionClass
1024
        ) {
1025
            $this->_reflectors[$class_name] = new ReflectionClass($class_name);
1026
        }
1027
        return $this->_reflectors[$class_name];
1028
    }
1029
1030
1031
1032
    /**
1033
     * _resolve_dependencies
1034
     * examines the constructor for the requested class to determine
1035
     * if any dependencies exist, and if they can be injected.
1036
     * If so, then those classes will be added to the array of arguments passed to the constructor
1037
     * PLZ NOTE: this is achieved by type hinting the constructor params
1038
     * For example:
1039
     *        if attempting to load a class "Foo" with the following constructor:
1040
     *        __construct( Bar $bar_class, Fighter $grohl_class )
1041
     *        then $bar_class and $grohl_class will be added to the $arguments array,
1042
     *        but only IF they are NOT already present in the incoming arguments array,
1043
     *        and the correct classes can be loaded
1044
     *
1045
     * @access protected
1046
     * @param ReflectionClass $reflector
1047
     * @param string          $class_name
1048
     * @param array           $arguments
1049
     * @return array
1050
     * @throws \ReflectionException
1051
     */
1052
    protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, $arguments = array())
1053
    {
1054
        // let's examine the constructor
1055
        $constructor = $reflector->getConstructor();
1056
        // whu? huh? nothing?
1057
        if ( ! $constructor) {
1058
            return $arguments;
1059
        }
1060
        // get constructor parameters
1061
        $params = $constructor->getParameters();
1062
        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1063
        $argument_keys = array_keys($arguments);
1064
        // now loop thru all of the constructors expected parameters
1065
        foreach ($params as $index => $param) {
1066
            // is this a dependency for a specific class ?
1067
            $param_class = $param->getClass() ? $param->getClass()->name : null;
1068
            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1069
            $param_class = $this->_dependency_map->has_alias($param_class, $class_name)
1070
                ? $this->_dependency_map->get_alias($param_class, $class_name)
1071
                : $param_class;
1072
            if (
1073
                // param is not even a class
1074
                empty($param_class)
1075
                // and something already exists in the incoming arguments for this param
1076
                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1077
            ) {
1078
                // so let's skip this argument and move on to the next
1079
                continue;
1080
            }
1081
            if (
1082
                // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1083
                ! empty($param_class)
1084
                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1085
                && $arguments[$argument_keys[$index]] instanceof $param_class
1086
            ) {
1087
                // skip this argument and move on to the next
1088
                continue;
1089
            }
1090
            if (
1091
                // parameter is type hinted as a class, and should be injected
1092
                ! empty($param_class)
1093
                && $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1094
            ) {
1095
                $arguments = $this->_resolve_dependency($class_name, $param_class, $arguments, $index);
1096
            } else {
1097
                try {
1098
                    $arguments[$index] = $param->getDefaultValue();
1099
                } catch (ReflectionException $e) {
1100
                    throw new ReflectionException(
1101
                        sprintf(
1102
                            __('%1$s for parameter "$%2$s"', 'event_espresso'),
1103
                            $e->getMessage(),
1104
                            $param->getName()
1105
                        )
1106
                    );
1107
                }
1108
            }
1109
        }
1110
        return $arguments;
1111
    }
1112
1113
1114
1115
    /**
1116
     * @access protected
1117
     * @param string $class_name
1118
     * @param string $param_class
1119
     * @param array  $arguments
1120
     * @param mixed  $index
1121
     * @return array
1122
     */
1123
    protected function _resolve_dependency($class_name, $param_class, $arguments, $index)
1124
    {
1125
        $dependency = null;
1126
        // should dependency be loaded from cache ?
1127
        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency($class_name, $param_class)
1128
                    !== EE_Dependency_Map::load_new_object
1129
            ? true
1130
            : false;
1131
        // we might have a dependency...
1132
        // let's MAYBE try and find it in our cache if that's what's been requested
1133
        $cached_class = $cache_on ? $this->_get_cached_class($param_class) : null;
1134
        // and grab it if it exists
1135
        if ($cached_class instanceof $param_class) {
1136
            $dependency = $cached_class;
1137
        } else if ($param_class !== $class_name) {
1138
            // obtain the loader method from the dependency map
1139
            $loader = $this->_dependency_map->class_loader($param_class);
1140
            // is loader a custom closure ?
1141
            if ($loader instanceof Closure) {
1142
                $dependency = $loader();
1143
            } else {
1144
                // set the cache on property for the recursive loading call
1145
                $this->_cache_on = $cache_on;
1146
                // if not, then let's try and load it via the registry
1147
                if ($loader && method_exists($this, $loader)) {
1148
                    $dependency = $this->{$loader}($param_class);
1149
                } else {
1150
                    $dependency = $this->create($param_class, array(), $cache_on);
1151
                }
1152
            }
1153
        }
1154
        // did we successfully find the correct dependency ?
1155
        if ($dependency instanceof $param_class) {
1156
            // then let's inject it into the incoming array of arguments at the correct location
1157
            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...
1158
                $arguments[$argument_keys[$index]] = $dependency;
1159
            } else {
1160
                $arguments[$index] = $dependency;
1161
            }
1162
        }
1163
        return $arguments;
1164
    }
1165
1166
1167
1168
    /**
1169
     * _set_cached_class
1170
     * attempts to cache the instantiated class locally
1171
     * in one of the following places, in the following order:
1172
     *        $this->{class_abbreviation}   ie:    $this->CART
1173
     *        $this->{$class_name}          ie:    $this->Some_Class
1174
     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1175
     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1176
     *
1177
     * @access protected
1178
     * @param object $class_obj
1179
     * @param string $class_name
1180
     * @param string $class_prefix
1181
     * @param bool   $from_db
1182
     * @return void
1183
     */
1184
    protected function _set_cached_class($class_obj, $class_name, $class_prefix = '', $from_db = false)
1185
    {
1186
        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1187
            return;
1188
        }
1189
        // return newly instantiated class
1190
        if (isset($this->_class_abbreviations[$class_name])) {
1191
            $class_abbreviation = $this->_class_abbreviations[$class_name];
1192
            $this->{$class_abbreviation} = $class_obj;
1193
            return;
1194
        }
1195
        $class_name = str_replace('\\', '_', $class_name);
1196
        if (property_exists($this, $class_name)) {
1197
            $this->{$class_name} = $class_obj;
1198
            return;
1199
        }
1200
        if ($class_prefix === 'addon') {
1201
            $this->addons->{$class_name} = $class_obj;
1202
            return;
1203
        }
1204
        if ( ! $from_db) {
1205
            $this->LIB->{$class_name} = $class_obj;
1206
        }
1207
    }
1208
1209
1210
1211
    /**
1212
     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1213
     *
1214
     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1215
     *                          in the EE_Dependency_Map::$_class_loaders array,
1216
     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1217
     * @param array  $arguments
1218
     * @return object
1219
     */
1220
    public static function factory($classname, $arguments = array())
1221
    {
1222
        $loader = self::instance()->_dependency_map->class_loader($classname);
1223
        if ($loader instanceof Closure) {
1224
            return $loader($arguments);
1225
        }
1226
        if (method_exists(EE_Registry::instance(), $loader)) {
1227
            return EE_Registry::instance()->{$loader}($classname, $arguments);
1228
        }
1229
        return null;
1230
    }
1231
1232
1233
1234
    /**
1235
     * Gets the addon by its name/slug (not classname. For that, just
1236
     * use the classname as the property name on EE_Config::instance()->addons)
1237
     *
1238
     * @param string $name
1239
     * @return EE_Addon
1240
     */
1241
    public function get_addon_by_name($name)
1242
    {
1243
        foreach ($this->addons as $addon) {
1244
            if ($addon->name() == $name) {
1245
                return $addon;
1246
            }
1247
        }
1248
        return null;
1249
    }
1250
1251
1252
1253
    /**
1254
     * Gets an array of all the registered addons, where the keys are their names. (ie, what each returns for their name() function) They're already available on EE_Config::instance()->addons as properties, where each property's name is
1255
     * the addon's classname. So if you just want to get the addon by classname, use EE_Config::instance()->addons->{classname}
1256
     *
1257
     * @return EE_Addon[] where the KEYS are the addon's name()
1258
     */
1259
    public function get_addons_by_name()
1260
    {
1261
        $addons = array();
1262
        foreach ($this->addons as $addon) {
1263
            $addons[$addon->name()] = $addon;
1264
        }
1265
        return $addons;
1266
    }
1267
1268
1269
1270
    /**
1271
     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1272
     * a stale copy of it around
1273
     *
1274
     * @param string $model_name
1275
     * @return \EEM_Base
1276
     * @throws \EE_Error
1277
     */
1278
    public function reset_model($model_name)
1279
    {
1280
        $model_class_name = strpos($model_name, 'EEM_') !== 0 ? "EEM_{$model_name}" : $model_name;
1281
        if ( ! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1282
            return null;
1283
        }
1284
        //get that model reset it and make sure we nuke the old reference to it
1285
        if ($this->LIB->{$model_class_name} instanceof $model_class_name && is_callable(array($model_class_name, 'reset'))) {
1286
            $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1287
        } else {
1288
            throw new EE_Error(sprintf(__('Model %s does not have a method "reset"', 'event_espresso'), $model_name));
1289
        }
1290
        return $this->LIB->{$model_class_name};
1291
    }
1292
1293
1294
1295
    /**
1296
     * Resets the registry.
1297
     * The criteria for what gets reset is based on what can be shared between sites on the same request when switch_to_blog
1298
     * is used in a multisite install.  Here is a list of things that are NOT reset.
1299
     * - $_dependency_map
1300
     * - $_class_abbreviations
1301
     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1302
     * - $REQ:  Still on the same request so no need to change.
1303
     * - $CAP: There is no site specific state in the EE_Capability class.
1304
     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only one Session
1305
     *         can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1306
     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1307
     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1308
     *             switch or on the restore.
1309
     * - $modules
1310
     * - $shortcodes
1311
     * - $widgets
1312
     *
1313
     * @param boolean $hard             whether to reset data in the database too, or just refresh
1314
     *                                  the Registry to its state at the beginning of the request
1315
     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1316
     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not sure if you CAN
1317
     *                                  currently reinstantiate the singletons at the moment)
1318
     * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so client
1319
     *                                  code instead can just change the model context to a different blog id if necessary
1320
     * @return EE_Registry
1321
     */
1322
    public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1323
    {
1324
        $instance = self::instance();
1325
        $instance->_cache_on = true;
1326
        // reset some "special" classes
1327
        EEH_Activation::reset();
1328
        $instance->CFG = $instance->CFG->reset($hard, $reinstantiate);
1329
        $instance->CART = null;
1330
        $instance->MRM = null;
1331
        $instance->AssetsRegistry = null;
1332
        $instance->AssetsRegistry = $instance->create('EventEspresso\core\services\assets\Registry');
1333
        //messages reset
1334
        EED_Messages::reset();
1335
        //handle of objects cached on LIB
1336
        foreach (array('LIB', 'modules', 'shortcodes') as $cache) {
1337
            foreach ($instance->{$cache} as $class_name => $class) {
1338
                if (EE_Registry::_reset_and_unset_object($class, $reset_models)) {
1339
                    unset($instance->{$cache}->{$class_name});
1340
                }
1341
            }
1342
        }
1343
        return $instance;
1344
    }
1345
1346
1347
1348
    /**
1349
     * if passed object implements ResettableInterface, then call it's reset() method
1350
     * if passed object implements InterminableInterface, then return false,
1351
     * to indicate that it should NOT be cleared from the Registry cache
1352
     *
1353
     * @param      $object
1354
     * @param bool $reset_models
1355
     * @return bool returns true if cached object should be unset
1356
     */
1357
    private static function _reset_and_unset_object($object, $reset_models)
1358
    {
1359
        static $count = 0;
1360
        $count++;
1361
        if ($object instanceof ResettableInterface) {
1362
            if ($object instanceof EEM_Base) {
1363
                if ($reset_models) {
1364
                    $object->reset();
1365
                    return true;
1366
                }
1367
                return false;
1368
            }
1369
            $object->reset();
1370
            return true;
1371
        }
1372
        if ( ! $object instanceof InterminableInterface) {
1373
            return true;
1374
        }
1375
        return false;
1376
    }
1377
1378
1379
1380
    /**
1381
     * @override magic methods
1382
     * @return void
1383
     */
1384
    public final function __destruct()
1385
    {
1386
    }
1387
1388
1389
1390
    /**
1391
     * @param $a
1392
     * @param $b
1393
     */
1394
    public final function __call($a, $b)
1395
    {
1396
    }
1397
1398
1399
1400
    /**
1401
     * @param $a
1402
     */
1403
    public final function __get($a)
1404
    {
1405
    }
1406
1407
1408
1409
    /**
1410
     * @param $a
1411
     * @param $b
1412
     */
1413
    public final function __set($a, $b)
1414
    {
1415
    }
1416
1417
1418
1419
    /**
1420
     * @param $a
1421
     */
1422
    public final function __isset($a)
1423
    {
1424
    }
1425
1426
1427
1428
    /**
1429
     * @param $a
1430
     */
1431
    public final function __unset($a)
1432
    {
1433
    }
1434
1435
1436
1437
    /**
1438
     * @return array
1439
     */
1440
    public final function __sleep()
1441
    {
1442
        return array();
1443
    }
1444
1445
1446
1447
    public final function __wakeup()
1448
    {
1449
    }
1450
1451
1452
1453
    /**
1454
     * @return string
1455
     */
1456
    public final function __toString()
1457
    {
1458
        return '';
1459
    }
1460
1461
1462
1463
    public final function __invoke()
1464
    {
1465
    }
1466
1467
1468
1469
    public final static function __set_state($array = array())
1470
    {
1471
        return EE_Registry::instance();
1472
    }
1473
1474
1475
1476
    public final function __clone()
1477
    {
1478
    }
1479
1480
1481
1482
    /**
1483
     * @param $a
1484
     * @param $b
1485
     */
1486
    public final static function __callStatic($a, $b)
1487
    {
1488
    }
1489
1490
1491
1492
    /**
1493
     * Gets all the custom post type models defined
1494
     *
1495
     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1496
     */
1497
    public function cpt_models()
1498
    {
1499
        $cpt_models = array();
1500
        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1501
            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1502
                $cpt_models[$short_name] = $classname;
1503
            }
1504
        }
1505
        return $cpt_models;
1506
    }
1507
1508
1509
1510
    /**
1511
     * @return \EE_Config
1512
     */
1513
    public static function CFG()
1514
    {
1515
        return self::instance()->CFG;
1516
    }
1517
1518
1519
}
1520
// End of file EE_Registry.core.php
1521
// Location: ./core/EE_Registry.core.php
1522