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