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

EE_Registry::_load()   C

Complexity

Conditions 15
Paths 28

Size

Total Lines 59
Code Lines 34

Duplication

Lines 7
Ratio 11.86 %

Importance

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

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
use EventEspresso\core\exceptions\InvalidDataTypeException;
3
use EventEspresso\core\exceptions\InvalidInterfaceException;
4
use EventEspresso\core\interfaces\InterminableInterface;
5
use EventEspresso\core\interfaces\ResettableInterface;
6
use EventEspresso\core\services\assets\Registry;
7
use EventEspresso\core\services\commands\CommandBusInterface;
8
use EventEspresso\core\services\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