Completed
Branch BUG-11137-domain-base (06ea45)
by
unknown
44:54 queued 34:30
created

EE_Registry::_load()   C

Complexity

Conditions 15
Paths 28

Size

Total Lines 59
Code Lines 34

Duplication

Lines 7
Ratio 11.86 %

Importance

Changes 0
Metric Value
cc 15
eloc 34
c 0
b 0
f 0
nc 28
nop 8
dl 7
loc 59
rs 6.3845

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
use EventEspresso\core\exceptions\InvalidDataTypeException;
3
use EventEspresso\core\exceptions\InvalidInterfaceException;
4
use EventEspresso\core\interfaces\InterminableInterface;
5
use EventEspresso\core\interfaces\ResettableInterface;
6
use EventEspresso\core\services\assets\Registry;
7
use EventEspresso\core\services\commands\CommandBusInterface;
8
use EventEspresso\core\services\loaders\LoaderFactory;
9
10
defined('EVENT_ESPRESSO_VERSION') || exit;
11
12
13
14
/**
15
 * EE_Registry Class
16
 * Centralized Application Data Storage and Management
17
 *
18
 * @package                   Event Espresso
19
 * @subpackage                core
20
 * @author                    Brent Christensen
21
 */
22
class EE_Registry implements ResettableInterface
23
{
24
25
    /**
26
     * @var EE_Registry $_instance
27
     */
28
    private static $_instance;
29
30
    /**
31
     * @var EE_Dependency_Map $_dependency_map
32
     */
33
    protected $_dependency_map;
34
35
    /**
36
     * @var array $_class_abbreviations
37
     */
38
    protected $_class_abbreviations = array();
39
40
    /**
41
     * @var CommandBusInterface $BUS
42
     */
43
    public $BUS;
44
45
    /**
46
     * @var EE_Cart $CART
47
     */
48
    public $CART;
49
50
    /**
51
     * @var EE_Config $CFG
52
     */
53
    public $CFG;
54
55
    /**
56
     * @var EE_Network_Config $NET_CFG
57
     */
58
    public $NET_CFG;
59
60
    /**
61
     * StdClass object for storing library classes in
62
     *
63
     * @var StdClass $LIB
64
     */
65
    public $LIB;
66
67
    /**
68
     * @var EE_Request_Handler $REQ
69
     */
70
    public $REQ;
71
72
    /**
73
     * @var EE_Session $SSN
74
     */
75
    public $SSN;
76
77
    /**
78
     * @since 4.5.0
79
     * @var EE_Capabilities $CAP
80
     */
81
    public $CAP;
82
83
    /**
84
     * @since 4.9.0
85
     * @var EE_Message_Resource_Manager $MRM
86
     */
87
    public $MRM;
88
89
90
    /**
91
     * @var Registry $AssetsRegistry
92
     */
93
    public $AssetsRegistry;
94
95
    /**
96
     * StdClass object for holding addons which have registered themselves to work with EE core
97
     *
98
     * @var EE_Addon[] $addons
99
     */
100
    public $addons;
101
102
    /**
103
     * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
104
     *
105
     * @var EEM_Base[] $models
106
     */
107
    public $models = array();
108
109
    /**
110
     * @var EED_Module[] $modules
111
     */
112
    public $modules;
113
114
    /**
115
     * @var EES_Shortcode[] $shortcodes
116
     */
117
    public $shortcodes;
118
119
    /**
120
     * @var WP_Widget[] $widgets
121
     */
122
    public $widgets;
123
124
    /**
125
     * this is an array of all implemented model names (i.e. not the parent abstract models, or models
126
     * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
127
     * Keys are model "short names" (eg "Event") as used in model relations, and values are
128
     * classnames (eg "EEM_Event")
129
     *
130
     * @var array $non_abstract_db_models
131
     */
132
    public $non_abstract_db_models = array();
133
134
135
    /**
136
     * internationalization for JS strings
137
     *    usage:   EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' );
138
     *    in js file:  var translatedString = eei18n.string_key;
139
     *
140
     * @var array $i18n_js_strings
141
     */
142
    public static $i18n_js_strings = array();
143
144
145
    /**
146
     * $main_file - path to espresso.php
147
     *
148
     * @var array $main_file
149
     */
150
    public $main_file;
151
152
    /**
153
     * array of ReflectionClass objects where the key is the class name
154
     *
155
     * @var ReflectionClass[] $_reflectors
156
     */
157
    public $_reflectors;
158
159
    /**
160
     * boolean flag to indicate whether or not to load/save dependencies from/to the cache
161
     *
162
     * @var boolean $_cache_on
163
     */
164
    protected $_cache_on = true;
165
166
167
168
    /**
169
     * @singleton method used to instantiate class object
170
     * @param  EE_Dependency_Map $dependency_map
171
     * @return EE_Registry instance
172
     * @throws InvalidArgumentException
173
     * @throws InvalidInterfaceException
174
     * @throws InvalidDataTypeException
175
     */
176
    public static function instance(EE_Dependency_Map $dependency_map = null)
177
    {
178
        // check if class object is instantiated
179
        if (! self::$_instance instanceof EE_Registry) {
180
            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 176 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...
181
        }
182
        return self::$_instance;
183
    }
184
185
186
187
    /**
188
     * protected constructor to prevent direct creation
189
     *
190
     * @Constructor
191
     * @param  EE_Dependency_Map $dependency_map
192
     * @throws InvalidDataTypeException
193
     * @throws InvalidInterfaceException
194
     * @throws InvalidArgumentException
195
     */
196
    protected function __construct(EE_Dependency_Map $dependency_map)
197
    {
198
        $this->_dependency_map = $dependency_map;
199
        $this->LIB = new stdClass();
200
        $this->addons = new stdClass();
201
        $this->modules = new stdClass();
202
        $this->shortcodes = new stdClass();
203
        $this->widgets = new stdClass();
204
        add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
205
    }
206
207
208
209
    /**
210
     * initialize
211
     *
212
     * @throws EE_Error
213
     * @throws ReflectionException
214
     */
215
    public function initialize()
216
    {
217
        $this->_class_abbreviations = apply_filters(
218
            'FHEE__EE_Registry____construct___class_abbreviations',
219
            array(
220
                'EE_Config'                                       => 'CFG',
221
                'EE_Session'                                      => 'SSN',
222
                'EE_Capabilities'                                 => 'CAP',
223
                'EE_Cart'                                         => 'CART',
224
                'EE_Network_Config'                               => 'NET_CFG',
225
                'EE_Request_Handler'                              => 'REQ',
226
                'EE_Message_Resource_Manager'                     => 'MRM',
227
                'EventEspresso\core\services\commands\CommandBus' => 'BUS',
228
                'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
229
            )
230
        );
231
        $this->load_core('Base', array(), true);
232
        // add our request and response objects to the cache
233
        $request_loader = $this->_dependency_map->class_loader('EE_Request');
234
        $this->_set_cached_class(
235
            $request_loader(),
236
            'EE_Request'
237
        );
238
        $response_loader = $this->_dependency_map->class_loader('EE_Response');
239
        $this->_set_cached_class(
240
            $response_loader(),
241
            'EE_Response'
242
        );
243
        add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
244
    }
245
246
247
248
    /**
249
     * @return void
250
     */
251
    public function init()
252
    {
253
        // Get current page protocol
254
        $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
255
        // Output admin-ajax.php URL with same protocol as current page
256
        self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
257
        self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
258
    }
259
260
261
262
    /**
263
     * localize_i18n_js_strings
264
     *
265
     * @return string
266
     */
267
    public static function localize_i18n_js_strings()
268
    {
269
        $i18n_js_strings = (array)self::$i18n_js_strings;
270
        foreach ($i18n_js_strings as $key => $value) {
271
            if (is_scalar($value)) {
272
                $i18n_js_strings[$key] = html_entity_decode((string)$value, ENT_QUOTES, 'UTF-8');
273
            }
274
        }
275
        return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
276
    }
277
278
279
280
    /**
281
     * @param mixed string | EED_Module $module
282
     * @throws EE_Error
283
     * @throws ReflectionException
284
     */
285
    public function add_module($module)
286
    {
287
        if ($module instanceof EED_Module) {
288
            $module_class = get_class($module);
289
            $this->modules->{$module_class} = $module;
290
        } else {
291
            if ( ! class_exists('EE_Module_Request_Router', false)) {
292
                $this->load_core('Module_Request_Router');
293
            }
294
            EE_Module_Request_Router::module_factory($module);
295
        }
296
    }
297
298
299
300
    /**
301
     * @param string $module_name
302
     * @return mixed EED_Module | NULL
303
     */
304
    public function get_module($module_name = '')
305
    {
306
        return isset($this->modules->{$module_name})
307
            ? $this->modules->{$module_name}
308
            : null;
309
    }
310
311
312
313
    /**
314
     * loads core classes - must be singletons
315
     *
316
     * @param string $class_name - simple class name ie: session
317
     * @param mixed  $arguments
318
     * @param bool   $load_only
319
     * @return mixed
320
     * @throws EE_Error
321
     * @throws ReflectionException
322
     */
323
    public function load_core($class_name, $arguments = array(), $load_only = false)
324
    {
325
        $core_paths = apply_filters(
326
            'FHEE__EE_Registry__load_core__core_paths',
327
            array(
328
                EE_CORE,
329
                EE_ADMIN,
330
                EE_CPTS,
331
                EE_CORE . 'data_migration_scripts' . DS,
332
                EE_CORE . 'capabilities' . DS,
333
                EE_CORE . 'request_stack' . DS,
334
                EE_CORE . 'middleware' . DS,
335
            )
336
        );
337
        // retrieve instantiated class
338
        return $this->_load(
339
            $core_paths,
340
            'EE_',
341
            $class_name,
342
            'core',
343
            $arguments,
344
            false,
345
            true,
346
            $load_only
347
        );
348
    }
349
350
351
352
    /**
353
     * loads service classes
354
     *
355
     * @param string $class_name - simple class name ie: session
356
     * @param mixed  $arguments
357
     * @param bool   $load_only
358
     * @return mixed
359
     * @throws EE_Error
360
     * @throws ReflectionException
361
     */
362
    public function load_service($class_name, $arguments = array(), $load_only = false)
363
    {
364
        $service_paths = apply_filters(
365
            'FHEE__EE_Registry__load_service__service_paths',
366
            array(
367
                EE_CORE . 'services' . DS,
368
            )
369
        );
370
        // retrieve instantiated class
371
        return $this->_load(
372
            $service_paths,
373
            'EE_',
374
            $class_name,
375
            'class',
376
            $arguments,
377
            false,
378
            true,
379
            $load_only
380
        );
381
    }
382
383
384
385
    /**
386
     * loads data_migration_scripts
387
     *
388
     * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
389
     * @param mixed  $arguments
390
     * @return EE_Data_Migration_Script_Base|mixed
391
     * @throws EE_Error
392
     * @throws ReflectionException
393
     */
394
    public function load_dms($class_name, $arguments = array())
395
    {
396
        // retrieve instantiated class
397
        return $this->_load(
398
            EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
399
            'EE_DMS_',
400
            $class_name,
401
            'dms',
402
            $arguments,
403
            false,
404
            false
405
        );
406
    }
407
408
409
410
    /**
411
     * loads object creating classes - must be singletons
412
     *
413
     * @param string $class_name - simple class name ie: attendee
414
     * @param mixed  $arguments  - an array of arguments to pass to the class
415
     * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
416
     *                           instantiate
417
     * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
418
     *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
419
     * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
420
     *                           (default)
421
     * @return EE_Base_Class | bool
422
     * @throws EE_Error
423
     * @throws ReflectionException
424
     */
425
    public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
426
    {
427
        $paths = apply_filters(
428
            'FHEE__EE_Registry__load_class__paths', array(
429
            EE_CORE,
430
            EE_CLASSES,
431
            EE_BUSINESS,
432
        )
433
        );
434
        // retrieve instantiated class
435
        return $this->_load(
436
            $paths,
437
            'EE_',
438
            $class_name,
439
            'class',
440
            $arguments,
441
            $from_db,
442
            $cache,
443
            $load_only
444
        );
445
    }
446
447
448
449
    /**
450
     * loads helper classes - must be singletons
451
     *
452
     * @param string $class_name - simple class name ie: price
453
     * @param mixed  $arguments
454
     * @param bool   $load_only
455
     * @return EEH_Base | bool
456
     * @throws EE_Error
457
     * @throws ReflectionException
458
     */
459
    public function load_helper($class_name, $arguments = array(), $load_only = true)
460
    {
461
        // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
462
        $helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
463
        // retrieve instantiated class
464
        return $this->_load(
465
            $helper_paths,
466
            'EEH_',
467
            $class_name,
468
            'helper',
469
            $arguments,
470
            false,
471
            true,
472
            $load_only
473
        );
474
    }
475
476
477
478
    /**
479
     * loads core classes - must be singletons
480
     *
481
     * @param string $class_name - simple class name ie: session
482
     * @param mixed  $arguments
483
     * @param bool   $load_only
484
     * @param bool   $cache      whether to cache the object or not.
485
     * @return mixed
486
     * @throws EE_Error
487
     * @throws ReflectionException
488
     */
489
    public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
490
    {
491
        $paths = array(
492
            EE_LIBRARIES,
493
            EE_LIBRARIES . 'messages' . DS,
494
            EE_LIBRARIES . 'shortcodes' . DS,
495
            EE_LIBRARIES . 'qtips' . DS,
496
            EE_LIBRARIES . 'payment_methods' . DS,
497
        );
498
        // retrieve instantiated class
499
        return $this->_load(
500
            $paths,
501
            'EE_',
502
            $class_name,
503
            'lib',
504
            $arguments,
505
            false,
506
            $cache,
507
            $load_only
508
        );
509
    }
510
511
512
513
    /**
514
     * loads model classes - must be singletons
515
     *
516
     * @param string $class_name - simple class name ie: price
517
     * @param mixed  $arguments
518
     * @param bool   $load_only
519
     * @return EEM_Base | bool
520
     * @throws EE_Error
521
     * @throws ReflectionException
522
     */
523
    public function load_model($class_name, $arguments = array(), $load_only = false)
524
    {
525
        $paths = apply_filters(
526
            'FHEE__EE_Registry__load_model__paths', array(
527
            EE_MODELS,
528
            EE_CORE,
529
        )
530
        );
531
        // retrieve instantiated class
532
        return $this->_load(
533
            $paths,
534
            'EEM_',
535
            $class_name,
536
            'model',
537
            $arguments,
538
            false,
539
            true,
540
            $load_only
541
        );
542
    }
543
544
545
546
    /**
547
     * loads model classes - must be singletons
548
     *
549
     * @param string $class_name - simple class name ie: price
550
     * @param mixed  $arguments
551
     * @param bool   $load_only
552
     * @return mixed | bool
553
     * @throws EE_Error
554
     * @throws ReflectionException
555
     */
556
    public function load_model_class($class_name, $arguments = array(), $load_only = true)
557
    {
558
        $paths = array(
559
            EE_MODELS . 'fields' . DS,
560
            EE_MODELS . 'helpers' . DS,
561
            EE_MODELS . 'relations' . DS,
562
            EE_MODELS . 'strategies' . DS,
563
        );
564
        // retrieve instantiated class
565
        return $this->_load(
566
            $paths,
567
            'EE_',
568
            $class_name,
569
            '',
570
            $arguments,
571
            false,
572
            true,
573
            $load_only
574
        );
575
    }
576
577
578
579
    /**
580
     * Determines if $model_name is the name of an actual EE model.
581
     *
582
     * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
583
     * @return boolean
584
     */
585
    public function is_model_name($model_name)
586
    {
587
        return isset($this->models[$model_name]);
588
    }
589
590
591
592
    /**
593
     * generic class loader
594
     *
595
     * @param string $path_to_file - directory path to file location, not including filename
596
     * @param string $file_name    - file name  ie:  my_file.php, including extension
597
     * @param string $type         - file type - core? class? helper? model?
598
     * @param mixed  $arguments
599
     * @param bool   $load_only
600
     * @return mixed
601
     * @throws EE_Error
602
     * @throws ReflectionException
603
     */
604
    public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
605
    {
606
        // retrieve instantiated class
607
        return $this->_load(
608
            $path_to_file,
609
            '',
610
            $file_name,
611
            $type,
612
            $arguments,
613
            false,
614
            true,
615
            $load_only
616
        );
617
    }
618
619
620
621
    /**
622
     * @param string $path_to_file - directory path to file location, not including filename
623
     * @param string $class_name   - full class name  ie:  My_Class
624
     * @param string $type         - file type - core? class? helper? model?
625
     * @param mixed  $arguments
626
     * @param bool   $load_only
627
     * @return bool|EE_Addon|object
628
     * @throws EE_Error
629
     * @throws ReflectionException
630
     */
631
    public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
632
    {
633
        // retrieve instantiated class
634
        return $this->_load(
635
            $path_to_file,
636
            'addon',
637
            $class_name,
638
            $type,
639
            $arguments,
640
            false,
641
            true,
642
            $load_only
643
        );
644
    }
645
646
647
648
    /**
649
     * instantiates, caches, and automatically resolves dependencies
650
     * for classes that use a Fully Qualified Class Name.
651
     * if the class is not capable of being loaded using PSR-4 autoloading,
652
     * then you need to use one of the existing load_*() methods
653
     * which can resolve the classname and filepath from the passed arguments
654
     *
655
     * @param bool|string $class_name   Fully Qualified Class Name
656
     * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
657
     * @param bool        $cache        whether to cache the instantiated object for reuse
658
     * @param bool        $from_db      some classes are instantiated from the db
659
     *                                  and thus call a different method to instantiate
660
     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
661
     * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
662
     * @return bool|null|mixed          null = failure to load or instantiate class object.
663
     *                                  object = class loaded and instantiated successfully.
664
     *                                  bool = fail or success when $load_only is true
665
     * @throws EE_Error
666
     * @throws ReflectionException
667
     */
668
    public function create(
669
        $class_name = false,
670
        $arguments = array(),
671
        $cache = false,
672
        $from_db = false,
673
        $load_only = false,
674
        $addon = false
675
    ) {
676
        $class_name = ltrim($class_name, '\\');
677
        $class_name = $this->_dependency_map->get_alias($class_name);
678
        $class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
679
        // if a non-FQCN was passed, then verifyClassExists() might return an object
680
        // or it could return null if the class just could not be found anywhere
681
        if ($class_exists instanceof $class_name || $class_exists === null){
682
            // either way, return the results
683
            return $class_exists;
684
        }
685
        $class_name = $class_exists;
686
        // if we're only loading the class and it already exists, then let's just return true immediately
687
        if ($load_only) {
688
            return true;
689
        }
690
        $addon = $addon
691
            ? 'addon'
692
            : '';
693
        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
694
        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
695
        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
696 View Code Duplication
        if ($this->_cache_on && $cache && ! $load_only) {
697
            // return object if it's already cached
698
            $cached_class = $this->_get_cached_class($class_name, $addon);
699
            if ($cached_class !== null) {
700
                return $cached_class;
701
            }
702
        }
703
        // obtain the loader method from the dependency map
704
        $loader = $this->_dependency_map->class_loader($class_name);
705
        // instantiate the requested object
706
        if ($loader instanceof Closure) {
707
            $class_obj = $loader($arguments);
708
        } else if ($loader && method_exists($this, $loader)) {
709
            $class_obj = $this->{$loader}($class_name, $arguments);
710
        } else {
711
            $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
712
        }
713
        if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) {
714
            // save it for later... kinda like gum  { : $
715
            $this->_set_cached_class($class_obj, $class_name, $addon, $from_db);
716
        }
717
        $this->_cache_on = true;
718
        return $class_obj;
719
    }
720
721
722
723
    /**
724
     * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
725
     *
726
     * @param string $class_name
727
     * @param array  $arguments
728
     * @param int    $attempt
729
     * @return mixed
730
     */
731
    private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1) {
732
        if (is_object($class_name) || class_exists($class_name)) {
733
            return $class_name;
734
        }
735
        switch ($attempt) {
736
            case 1:
737
                // if it's a FQCN then maybe the class is registered with a preceding \
738
                $class_name = strpos($class_name, '\\') !== false
739
                    ? '\\' . ltrim($class_name, '\\')
740
                    : $class_name;
741
                break;
742
            case 2:
743
                //
744
                $loader = $this->_dependency_map->class_loader($class_name);
745
                if ($loader && method_exists($this, $loader)) {
746
                    return $this->{$loader}($class_name, $arguments);
747
                }
748
                break;
749
            case 3:
750
            default;
751
                return null;
752
        }
753
        $attempt++;
754
        return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
755
    }
756
757
758
759
    /**
760
     * instantiates, caches, and injects dependencies for classes
761
     *
762
     * @param array       $file_paths   an array of paths to folders to look in
763
     * @param string      $class_prefix EE  or EEM or... ???
764
     * @param bool|string $class_name   $class name
765
     * @param string      $type         file type - core? class? helper? model?
766
     * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
767
     * @param bool        $from_db      some classes are instantiated from the db
768
     *                                  and thus call a different method to instantiate
769
     * @param bool        $cache        whether to cache the instantiated object for reuse
770
     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
771
     * @return bool|null|object null = failure to load or instantiate class object.
772
     *                                  object = class loaded and instantiated successfully.
773
     *                                  bool = fail or success when $load_only is true
774
     * @throws EE_Error
775
     * @throws ReflectionException
776
     */
777
    protected function _load(
778
        $file_paths = array(),
779
        $class_prefix = 'EE_',
780
        $class_name = false,
781
        $type = 'class',
782
        $arguments = array(),
783
        $from_db = false,
784
        $cache = true,
785
        $load_only = false
786
    ) {
787
        $class_name = ltrim($class_name, '\\');
788
        // strip php file extension
789
        $class_name = str_replace('.php', '', trim($class_name));
790
        // does the class have a prefix ?
791
        if (! empty($class_prefix) && $class_prefix !== 'addon') {
792
            // make sure $class_prefix is uppercase
793
            $class_prefix = strtoupper(trim($class_prefix));
794
            // add class prefix ONCE!!!
795
            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
796
        }
797
        $class_name = $this->_dependency_map->get_alias($class_name);
798
        $class_exists = class_exists($class_name, false);
799
        // if we're only loading the class and it already exists, then let's just return true immediately
800
        if ($load_only && $class_exists) {
801
            return true;
802
        }
803
        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
804
        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
805
        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
806 View Code Duplication
        if ($this->_cache_on && $cache && ! $load_only) {
807
            // return object if it's already cached
808
            $cached_class = $this->_get_cached_class($class_name, $class_prefix);
809
            if ($cached_class !== null) {
810
                return $cached_class;
811
            }
812
        }
813
        // if the class doesn't already exist.. then we need to try and find the file and load it
814
        if (! $class_exists) {
815
            // get full path to file
816
            $path = $this->_resolve_path($class_name, $type, $file_paths);
817
            // load the file
818
            $loaded = $this->_require_file($path, $class_name, $type, $file_paths);
819
            // if loading failed, or we are only loading a file but NOT instantiating an object
820
            if (! $loaded || $load_only) {
821
                // return boolean if only loading, or null if an object was expected
822
                return $load_only
823
                    ? $loaded
824
                    : null;
825
            }
826
        }
827
        // instantiate the requested object
828
        $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
829
        if ($this->_cache_on && $cache) {
830
            // save it for later... kinda like gum  { : $
831
            $this->_set_cached_class($class_obj, $class_name, $class_prefix, $from_db);
832
        }
833
        $this->_cache_on = true;
834
        return $class_obj;
835
    }
836
837
838
839
    /**
840
     * @param string $class_name
841
     * @param string $default have to specify something, but not anything that will conflict
842
     * @return mixed|string
843
     */
844
    protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS')
845
    {
846
        return isset($this->_class_abbreviations[$class_name])
847
            ? $this->_class_abbreviations[$class_name]
848
            : $default;
849
    }
850
851
    /**
852
     * attempts to find a cached version of the requested class
853
     * by looking in the following places:
854
     *        $this->{$class_abbreviation}            ie:    $this->CART
855
     *        $this->{$class_name}                        ie:    $this->Some_Class
856
     *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
857
     *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
858
     *
859
     * @param string $class_name
860
     * @param string $class_prefix
861
     * @return mixed
862
     */
863
    protected function _get_cached_class($class_name, $class_prefix = '')
864
    {
865
        if ($class_name === 'EE_Registry') {
866
            return $this;
867
        }
868
        $class_abbreviation = $this->get_class_abbreviation($class_name);
869
        $class_name = str_replace('\\', '_', $class_name);
870
        // check if class has already been loaded, and return it if it has been
871
        if (isset($this->{$class_abbreviation})) {
872
            return $this->{$class_abbreviation};
873
        }
874
        if (isset ($this->{$class_name})) {
875
            return $this->{$class_name};
876
        }
877
        if (isset ($this->LIB->{$class_name})) {
878
            return $this->LIB->{$class_name};
879
        }
880
        if ($class_prefix === 'addon' && isset ($this->addons->{$class_name})) {
881
            return $this->addons->{$class_name};
882
        }
883
        return null;
884
    }
885
886
887
888
    /**
889
     * removes a cached version of the requested class
890
     *
891
     * @param string  $class_name
892
     * @param boolean $addon
893
     * @return boolean
894
     */
895
    public function clear_cached_class($class_name, $addon = false)
896
    {
897
        $class_abbreviation = $this->get_class_abbreviation($class_name);
898
        $class_name = str_replace('\\', '_', $class_name);
899
        // check if class has already been loaded, and return it if it has been
900
        if (isset($this->{$class_abbreviation})) {
901
            $this->{$class_abbreviation} = null;
902
            return true;
903
        }
904
        if (isset($this->{$class_name})) {
905
            $this->{$class_name} = null;
906
            return true;
907
        }
908
        if (isset($this->LIB->{$class_name})) {
909
            unset($this->LIB->{$class_name});
910
            return true;
911
        }
912
        if ($addon && isset($this->addons->{$class_name})) {
913
            unset($this->addons->{$class_name});
914
            return true;
915
        }
916
        return false;
917
    }
918
919
920
921
    /**
922
     * attempts to find a full valid filepath for the requested class.
923
     * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
924
     * then returns that path if the target file has been found and is readable
925
     *
926
     * @param string $class_name
927
     * @param string $type
928
     * @param array  $file_paths
929
     * @return string | bool
930
     */
931
    protected function _resolve_path($class_name, $type = '', $file_paths = array())
932
    {
933
        // make sure $file_paths is an array
934
        $file_paths = is_array($file_paths)
935
            ? $file_paths
936
            : array($file_paths);
937
        // cycle thru paths
938
        foreach ($file_paths as $key => $file_path) {
939
            // convert all separators to proper DS, if no filepath, then use EE_CLASSES
940
            $file_path = $file_path
941
                ? str_replace(array('/', '\\'), DS, $file_path)
942
                : EE_CLASSES;
943
            // prep file type
944
            $type = ! empty($type)
945
                ? trim($type, '.') . '.'
946
                : '';
947
            // build full file path
948
            $file_paths[$key] = rtrim($file_path, DS) . DS . $class_name . '.' . $type . 'php';
949
            //does the file exist and can be read ?
950
            if (is_readable($file_paths[$key])) {
951
                return $file_paths[$key];
952
            }
953
        }
954
        return false;
955
    }
956
957
958
959
    /**
960
     * basically just performs a require_once()
961
     * but with some error handling
962
     *
963
     * @param  string $path
964
     * @param  string $class_name
965
     * @param  string $type
966
     * @param  array  $file_paths
967
     * @return bool
968
     * @throws EE_Error
969
     * @throws ReflectionException
970
     */
971
    protected function _require_file($path, $class_name, $type = '', $file_paths = array())
972
    {
973
        $this->resolve_legacy_class_parent($class_name);
974
        // don't give up! you gotta...
975
        try {
976
            //does the file exist and can it be read ?
977
            if (! $path) {
978
                // just in case the file has already been autoloaded,
979
                // but discrepancies in the naming schema are preventing it from
980
                // being loaded via one of the EE_Registry::load_*() methods,
981
                // then let's try one last hail mary before throwing an exception
982
                // and call class_exists() again, but with autoloading turned ON
983
                if(class_exists($class_name)) {
984
                    return true;
985
                }
986
                // so sorry, can't find the file
987
                throw new EE_Error (
988
                    sprintf(
989
                        esc_html__(
990
                            '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',
991
                            'event_espresso'
992
                        ),
993
                        trim($type, '.'),
994
                        $class_name,
995
                        '<br />' . implode(',<br />', $file_paths)
996
                    )
997
                );
998
            }
999
            // get the file
1000
            require_once($path);
1001
            // if the class isn't already declared somewhere
1002
            if (class_exists($class_name, false) === false) {
1003
                // so sorry, not a class
1004
                throw new EE_Error(
1005
                    sprintf(
1006
                        esc_html__('The %s file %s does not appear to contain the %s Class.', 'event_espresso'),
1007
                        $type,
1008
                        $path,
1009
                        $class_name
1010
                    )
1011
                );
1012
            }
1013
        } catch (EE_Error $e) {
1014
            $e->get_error();
1015
            return false;
1016
        }
1017
        return true;
1018
    }
1019
1020
1021
1022
    /**
1023
     * Some of our legacy classes that extended a parent class would simply use a require() statement
1024
     * before their class declaration in order to ensure that the parent class was loaded.
1025
     * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1026
     * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1027
     *
1028
     * @param string $class_name
1029
     */
1030
    protected function resolve_legacy_class_parent($class_name = '')
1031
    {
1032
        try {
1033
            $legacy_parent_class_map = array(
1034
                'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php'
1035
            );
1036
            if(isset($legacy_parent_class_map[$class_name])) {
1037
                require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[$class_name];
1038
            }
1039
        } catch (Exception $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1040
        }
1041
    }
1042
1043
1044
1045
    /**
1046
     * _create_object
1047
     * Attempts to instantiate the requested class via any of the
1048
     * commonly used instantiation methods employed throughout EE.
1049
     * The priority for instantiation is as follows:
1050
     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1051
     *        - model objects via their 'new_instance_from_db' method
1052
     *        - model objects via their 'new_instance' method
1053
     *        - "singleton" classes" via their 'instance' method
1054
     *    - standard instantiable classes via their __constructor
1055
     * Prior to instantiation, if the classname exists in the dependency_map,
1056
     * then the constructor for the requested class will be examined to determine
1057
     * if any dependencies exist, and if they can be injected.
1058
     * If so, then those classes will be added to the array of arguments passed to the constructor
1059
     *
1060
     * @param string $class_name
1061
     * @param array  $arguments
1062
     * @param string $type
1063
     * @param bool   $from_db
1064
     * @return null|object
1065
     * @throws EE_Error
1066
     * @throws ReflectionException
1067
     */
1068
    protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
1069
    {
1070
        // create reflection
1071
        $reflector = $this->get_ReflectionClass($class_name);
1072
        // make sure arguments are an array
1073
        $arguments = is_array($arguments)
1074
            ? $arguments
1075
            : array($arguments);
1076
        // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1077
        // else wrap it in an additional array so that it doesn't get split into multiple parameters
1078
        $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1079
            ? $arguments
1080
            : array($arguments);
1081
        // attempt to inject dependencies ?
1082
        if ($this->_dependency_map->has($class_name)) {
1083
            $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1084
        }
1085
        // instantiate the class if possible
1086
        if ($reflector->isAbstract()) {
1087
            // nothing to instantiate, loading file was enough
1088
            // does not throw an exception so $instantiation_mode is unused
1089
            // $instantiation_mode = "1) no constructor abstract class";
1090
            return true;
1091
        }
1092
        if (empty($arguments) && $reflector->getConstructor() === null && $reflector->isInstantiable()) {
1093
            // no constructor = static methods only... nothing to instantiate, loading file was enough
1094
            // $instantiation_mode = "2) no constructor but instantiable";
1095
            return $reflector->newInstance();
1096
        }
1097
        if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1098
            // $instantiation_mode = "3) new_instance_from_db()";
1099
            return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1100
        }
1101
        if (method_exists($class_name, 'new_instance')) {
1102
            // $instantiation_mode = "4) new_instance()";
1103
            return call_user_func_array(array($class_name, 'new_instance'), $arguments);
1104
        }
1105
        if (method_exists($class_name, 'instance')) {
1106
            // $instantiation_mode = "5) instance()";
1107
            return call_user_func_array(array($class_name, 'instance'), $arguments);
1108
        }
1109
        if ($reflector->isInstantiable()) {
1110
            // $instantiation_mode = "6) constructor";
1111
            return $reflector->newInstanceArgs($arguments);
1112
        }
1113
        // heh ? something's not right !
1114
        throw new EE_Error(
1115
            sprintf(
1116
                __('The %s file %s could not be instantiated.', 'event_espresso'),
1117
                $type,
1118
                $class_name
1119
            )
1120
        );
1121
    }
1122
1123
1124
1125
    /**
1126
     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1127
     * @param array $array
1128
     * @return bool
1129
     */
1130
    protected function _array_is_numerically_and_sequentially_indexed(array $array)
1131
    {
1132
        return ! empty($array)
1133
            ? array_keys($array) === range(0, count($array) - 1)
1134
            : true;
1135
    }
1136
1137
1138
1139
    /**
1140
     * getReflectionClass
1141
     * checks if a ReflectionClass object has already been generated for a class
1142
     * and returns that instead of creating a new one
1143
     *
1144
     * @param string $class_name
1145
     * @return ReflectionClass
1146
     * @throws ReflectionException
1147
     */
1148 View Code Duplication
    public function get_ReflectionClass($class_name)
1149
    {
1150
        if (
1151
            ! isset($this->_reflectors[$class_name])
1152
            || ! $this->_reflectors[$class_name] instanceof ReflectionClass
1153
        ) {
1154
            $this->_reflectors[$class_name] = new ReflectionClass($class_name);
1155
        }
1156
        return $this->_reflectors[$class_name];
1157
    }
1158
1159
1160
1161
    /**
1162
     * _resolve_dependencies
1163
     * examines the constructor for the requested class to determine
1164
     * if any dependencies exist, and if they can be injected.
1165
     * If so, then those classes will be added to the array of arguments passed to the constructor
1166
     * PLZ NOTE: this is achieved by type hinting the constructor params
1167
     * For example:
1168
     *        if attempting to load a class "Foo" with the following constructor:
1169
     *        __construct( Bar $bar_class, Fighter $grohl_class )
1170
     *        then $bar_class and $grohl_class will be added to the $arguments array,
1171
     *        but only IF they are NOT already present in the incoming arguments array,
1172
     *        and the correct classes can be loaded
1173
     *
1174
     * @param ReflectionClass $reflector
1175
     * @param string          $class_name
1176
     * @param array           $arguments
1177
     * @return array
1178
     * @throws EE_Error
1179
     * @throws ReflectionException
1180
     */
1181
    protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, $arguments = array())
1182
    {
1183
        // let's examine the constructor
1184
        $constructor = $reflector->getConstructor();
1185
        // whu? huh? nothing?
1186
        if (! $constructor) {
1187
            return $arguments;
1188
        }
1189
        // get constructor parameters
1190
        $params = $constructor->getParameters();
1191
        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1192
        $argument_keys = array_keys($arguments);
1193
        // now loop thru all of the constructors expected parameters
1194
        foreach ($params as $index => $param) {
1195
            // is this a dependency for a specific class ?
1196
            $param_class = $param->getClass()
1197
                ? $param->getClass()->name
1198
                : null;
1199
            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1200
            $param_class = $this->_dependency_map->has_alias($param_class, $class_name)
1201
                ? $this->_dependency_map->get_alias($param_class, $class_name)
1202
                : $param_class;
1203
            if (
1204
                // param is not even a class
1205
                $param_class === null
1206
                // and something already exists in the incoming arguments for this param
1207
                && array_key_exists($index, $argument_keys)
1208
                && array_key_exists($argument_keys[$index], $arguments)
1209
            ) {
1210
                // so let's skip this argument and move on to the next
1211
                continue;
1212
            }
1213
            if (
1214
                // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1215
                $param_class !== null
1216
                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1217
                && $arguments[$argument_keys[$index]] instanceof $param_class
1218
            ) {
1219
                // skip this argument and move on to the next
1220
                continue;
1221
            }
1222
            if (
1223
                // parameter is type hinted as a class, and should be injected
1224
                $param_class !== null
1225
                && $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1226
            ) {
1227
                $arguments = $this->_resolve_dependency(
1228
                    $class_name,
1229
                    $param_class,
1230
                    $arguments,
1231
                    $index,
1232
                    $argument_keys
1233
                );
1234
            } else {
1235
                try {
1236
                    $arguments[$index] = $param->isDefaultValueAvailable()
1237
                        ? $param->getDefaultValue()
1238
                        : null;
1239
                } catch (ReflectionException $e) {
1240
                    throw new ReflectionException(
1241
                        sprintf(
1242
                            esc_html__('%1$s for parameter "$%2$s on classname "%3$s"', 'event_espresso'),
1243
                            $e->getMessage(),
1244
                            $param->getName(),
1245
                            $class_name
1246
                        )
1247
                    );
1248
                }
1249
            }
1250
        }
1251
        return $arguments;
1252
    }
1253
1254
1255
1256
    /**
1257
     * @param string $class_name
1258
     * @param string $param_class
1259
     * @param array  $arguments
1260
     * @param mixed  $index
1261
     * @param array  $argument_keys
1262
     * @return array
1263
     * @throws EE_Error
1264
     * @throws ReflectionException
1265
     * @throws InvalidArgumentException
1266
     * @throws InvalidInterfaceException
1267
     * @throws InvalidDataTypeException
1268
     */
1269
    protected function _resolve_dependency($class_name, $param_class, $arguments, $index, array $argument_keys)
1270
    {
1271
        $dependency = null;
1272
        // should dependency be loaded from cache ?
1273
        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1274
            $class_name,
1275
            $param_class
1276
        );
1277
        $cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1278
        // we might have a dependency...
1279
        // let's MAYBE try and find it in our cache if that's what's been requested
1280
        $cached_class = $cache_on
1281
            ? $this->_get_cached_class($param_class)
1282
            : null;
1283
        // and grab it if it exists
1284
        if ($cached_class instanceof $param_class) {
1285
            $dependency = $cached_class;
1286
        } else if ($param_class !== $class_name) {
1287
            // obtain the loader method from the dependency map
1288
            $loader = $this->_dependency_map->class_loader($param_class);
1289
            // is loader a custom closure ?
1290
            if ($loader instanceof Closure) {
1291
                $dependency = $loader($arguments);
1292
            } else {
1293
                // set the cache on property for the recursive loading call
1294
                $this->_cache_on = $cache_on;
1295
                // if not, then let's try and load it via the registry
1296
                if ($loader && method_exists($this, $loader)) {
1297
                    $dependency = $this->{$loader}($param_class);
1298
                } else {
1299
                    $dependency = LoaderFactory::getLoader()->load(
1300
                        $param_class,
1301
                        array(),
1302
                        $cache_on
1303
                    );
1304
                }
1305
            }
1306
        }
1307
        // did we successfully find the correct dependency ?
1308
        if ($dependency instanceof $param_class) {
1309
            // then let's inject it into the incoming array of arguments at the correct location
1310
            $arguments[$index] = $dependency;
1311
        }
1312
        return $arguments;
1313
    }
1314
1315
1316
1317
    /**
1318
     * _set_cached_class
1319
     * attempts to cache the instantiated class locally
1320
     * in one of the following places, in the following order:
1321
     *        $this->{class_abbreviation}   ie:    $this->CART
1322
     *        $this->{$class_name}          ie:    $this->Some_Class
1323
     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1324
     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1325
     *
1326
     * @param object $class_obj
1327
     * @param string $class_name
1328
     * @param string $class_prefix
1329
     * @param bool   $from_db
1330
     * @return void
1331
     */
1332
    protected function _set_cached_class($class_obj, $class_name, $class_prefix = '', $from_db = false)
1333
    {
1334
        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1335
            return;
1336
        }
1337
        // return newly instantiated class
1338
        $class_abbreviation = $this->get_class_abbreviation($class_name, '');
1339
        if ($class_abbreviation) {
1340
            $this->{$class_abbreviation} = $class_obj;
1341
            return;
1342
        }
1343
        $class_name = str_replace('\\', '_', $class_name);
1344
        if (property_exists($this, $class_name)) {
1345
            $this->{$class_name} = $class_obj;
1346
            return;
1347
        }
1348
        if ($class_prefix === 'addon') {
1349
            $this->addons->{$class_name} = $class_obj;
1350
            return;
1351
        }
1352
        if (! $from_db) {
1353
            $this->LIB->{$class_name} = $class_obj;
1354
        }
1355
    }
1356
1357
1358
1359
    /**
1360
     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1361
     *
1362
     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1363
     *                          in the EE_Dependency_Map::$_class_loaders array,
1364
     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1365
     * @param array  $arguments
1366
     * @return object
1367
     */
1368
    public static function factory($classname, $arguments = array())
1369
    {
1370
        $loader = self::instance()->_dependency_map->class_loader($classname);
1371
        if ($loader instanceof Closure) {
1372
            return $loader($arguments);
1373
        }
1374
        if (method_exists(self::instance(), $loader)) {
1375
            return self::instance()->{$loader}($classname, $arguments);
1376
        }
1377
        return null;
1378
    }
1379
1380
1381
1382
    /**
1383
     * Gets the addon by its class name
1384
     *
1385
     * @param string $class_name
1386
     * @return EE_Addon
1387
     */
1388
    public function getAddon($class_name)
1389
    {
1390
        $class_name = str_replace('\\', '_', $class_name);
1391
        return $this->addons->{$class_name};
1392
    }
1393
1394
1395
    /**
1396
     * removes the addon from the internal cache
1397
     *
1398
     * @param string $class_name
1399
     * @return EE_Addon
1400
     */
1401
    public function removeAddon($class_name)
1402
    {
1403
        $class_name = str_replace('\\', '_', $class_name);
1404
        $this->addons->{$class_name} = null;
1405
    }
1406
1407
1408
1409
    /**
1410
     * Gets the addon by its name/slug (not classname. For that, just
1411
     * use the get_addon() method above
1412
     *
1413
     * @param string $name
1414
     * @return EE_Addon
1415
     */
1416
    public function get_addon_by_name($name)
1417
    {
1418
        foreach ($this->addons as $addon) {
1419
            if ($addon->name() === $name) {
1420
                return $addon;
1421
            }
1422
        }
1423
        return null;
1424
    }
1425
1426
1427
1428
    /**
1429
     * Gets an array of all the registered addons, where the keys are their names.
1430
     * (ie, what each returns for their name() function)
1431
     * They're already available on EE_Registry::instance()->addons as properties,
1432
     * where each property's name is the addon's classname,
1433
     * So if you just want to get the addon by classname,
1434
     * OR use the get_addon() method above.
1435
     * PLEASE  NOTE:
1436
     * addons with Fully Qualified Class Names
1437
     * have had the namespace separators converted to underscores,
1438
     * so a classname like Fully\Qualified\ClassName
1439
     * would have been converted to Fully_Qualified_ClassName
1440
     *
1441
     * @return EE_Addon[] where the KEYS are the addon's name()
1442
     */
1443
    public function get_addons_by_name()
1444
    {
1445
        $addons = array();
1446
        foreach ($this->addons as $addon) {
1447
            $addons[$addon->name()] = $addon;
1448
        }
1449
        return $addons;
1450
    }
1451
1452
1453
    /**
1454
     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1455
     * a stale copy of it around
1456
     *
1457
     * @param string $model_name
1458
     * @return \EEM_Base
1459
     * @throws \EE_Error
1460
     */
1461
    public function reset_model($model_name)
1462
    {
1463
        $model_class_name = strpos($model_name, 'EEM_') !== 0
1464
            ? "EEM_{$model_name}"
1465
            : $model_name;
1466
        if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1467
            return null;
1468
        }
1469
        //get that model reset it and make sure we nuke the old reference to it
1470
        if ($this->LIB->{$model_class_name} instanceof $model_class_name
1471
            && is_callable(
1472
                array($model_class_name, 'reset')
1473
            )) {
1474
            $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1475
        } else {
1476
            throw new EE_Error(sprintf(esc_html__('Model %s does not have a method "reset"', 'event_espresso'), $model_name));
1477
        }
1478
        return $this->LIB->{$model_class_name};
1479
    }
1480
1481
1482
1483
    /**
1484
     * Resets the registry.
1485
     * The criteria for what gets reset is based on what can be shared between sites on the same request when
1486
     * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1487
     * - $_dependency_map
1488
     * - $_class_abbreviations
1489
     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1490
     * - $REQ:  Still on the same request so no need to change.
1491
     * - $CAP: There is no site specific state in the EE_Capability class.
1492
     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1493
     * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1494
     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1495
     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1496
     *             switch or on the restore.
1497
     * - $modules
1498
     * - $shortcodes
1499
     * - $widgets
1500
     *
1501
     * @param boolean $hard             [deprecated]
1502
     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1503
     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1504
     *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1505
     * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1506
     *                                  client
1507
     *                                  code instead can just change the model context to a different blog id if
1508
     *                                  necessary
1509
     * @return EE_Registry
1510
     * @throws EE_Error
1511
     * @throws ReflectionException
1512
     */
1513
    public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1514
    {
1515
        $instance = self::instance();
1516
        $instance->_cache_on = true;
1517
        // reset some "special" classes
1518
        EEH_Activation::reset();
1519
        $hard = apply_filters( 'FHEE__EE_Registry__reset__hard', $hard);
1520
        $instance->CFG = EE_Config::reset($hard, $reinstantiate);
1521
        $instance->CART = null;
1522
        $instance->MRM = null;
1523
        $instance->AssetsRegistry = $instance->create('EventEspresso\core\services\assets\Registry');
1524
        //messages reset
1525
        EED_Messages::reset();
1526
        //handle of objects cached on LIB
1527
        foreach (array('LIB', 'modules') as $cache) {
1528
            foreach ($instance->{$cache} as $class_name => $class) {
1529
                if (self::_reset_and_unset_object($class, $reset_models)) {
1530
                    unset($instance->{$cache}->{$class_name});
1531
                }
1532
            }
1533
        }
1534
        return $instance;
1535
    }
1536
1537
1538
1539
    /**
1540
     * if passed object implements ResettableInterface, then call it's reset() method
1541
     * if passed object implements InterminableInterface, then return false,
1542
     * to indicate that it should NOT be cleared from the Registry cache
1543
     *
1544
     * @param      $object
1545
     * @param bool $reset_models
1546
     * @return bool returns true if cached object should be unset
1547
     */
1548
    private static function _reset_and_unset_object($object, $reset_models)
1549
    {
1550
        if (! is_object($object)) {
1551
            // don't unset anything that's not an object
1552
            return false;
1553
        }
1554
        if ($object instanceof EED_Module) {
1555
            $object::reset();
1556
            // don't unset modules
1557
            return false;
1558
        }
1559
        if ($object instanceof ResettableInterface) {
1560
            if ($object instanceof EEM_Base) {
1561
                if ($reset_models) {
1562
                    $object->reset();
1563
                    return true;
1564
                }
1565
                return false;
1566
            }
1567
            $object->reset();
1568
            return true;
1569
        }
1570
        if (! $object instanceof InterminableInterface) {
1571
            return true;
1572
        }
1573
        return false;
1574
    }
1575
1576
1577
1578
    /**
1579
     * Gets all the custom post type models defined
1580
     *
1581
     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1582
     */
1583
    public function cpt_models()
1584
    {
1585
        $cpt_models = array();
1586
        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1587
            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1588
                $cpt_models[$short_name] = $classname;
1589
            }
1590
        }
1591
        return $cpt_models;
1592
    }
1593
1594
1595
1596
    /**
1597
     * @return \EE_Config
1598
     */
1599
    public static function CFG()
1600
    {
1601
        return self::instance()->CFG;
1602
    }
1603
1604
1605
}
1606
// End of file EE_Registry.core.php
1607
// Location: ./core/EE_Registry.core.php
1608