Completed
Branch TASK/11208/update-bundled-gate... (60edbd)
by
unknown
12:10
created

EE_Registry::create()   C

Complexity

Conditions 15
Paths 28

Size

Total Lines 52
Code Lines 33

Duplication

Lines 7
Ratio 13.46 %

Importance

Changes 0
Metric Value
cc 15
eloc 33
nc 28
nop 6
dl 7
loc 52
rs 5.9385
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

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