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

EE_Registry::removeAddon()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
use EventEspresso\core\exceptions\InvalidDataTypeException;
3
use EventEspresso\core\exceptions\InvalidInterfaceException;
4
use EventEspresso\core\interfaces\InterminableInterface;
5
use EventEspresso\core\interfaces\ResettableInterface;
6
use EventEspresso\core\services\assets\Registry;
7
use EventEspresso\core\services\commands\CommandBusInterface;
8
use EventEspresso\core\services\loaders\LoaderFactory;
9
10
defined('EVENT_ESPRESSO_VERSION') || exit;
11
12
13
14
/**
15
 * EE_Registry Class
16
 * Centralized Application Data Storage and Management
17
 *
18
 * @package                   Event Espresso
19
 * @subpackage                core
20
 * @author                    Brent Christensen
21
 */
22
class EE_Registry implements ResettableInterface
23
{
24
25
    /**
26
     * @var EE_Registry $_instance
27
     */
28
    private static $_instance;
29
30
    /**
31
     * @var EE_Dependency_Map $_dependency_map
32
     */
33
    protected $_dependency_map;
34
35
    /**
36
     * @var array $_class_abbreviations
37
     */
38
    protected $_class_abbreviations = array();
39
40
    /**
41
     * @var CommandBusInterface $BUS
42
     */
43
    public $BUS;
44
45
    /**
46
     * @var EE_Cart $CART
47
     */
48
    public $CART;
49
50
    /**
51
     * @var EE_Config $CFG
52
     */
53
    public $CFG;
54
55
    /**
56
     * @var EE_Network_Config $NET_CFG
57
     */
58
    public $NET_CFG;
59
60
    /**
61
     * StdClass object for storing library classes in
62
     *
63
     * @var StdClass $LIB
64
     */
65
    public $LIB;
66
67
    /**
68
     * @var EE_Request_Handler $REQ
69
     */
70
    public $REQ;
71
72
    /**
73
     * @var EE_Session $SSN
74
     */
75
    public $SSN;
76
77
    /**
78
     * @since 4.5.0
79
     * @var EE_Capabilities $CAP
80
     */
81
    public $CAP;
82
83
    /**
84
     * @since 4.9.0
85
     * @var EE_Message_Resource_Manager $MRM
86
     */
87
    public $MRM;
88
89
90
    /**
91
     * @var Registry $AssetsRegistry
92
     */
93
    public $AssetsRegistry;
94
95
    /**
96
     * StdClass object for holding addons which have registered themselves to work with EE core
97
     *
98
     * @var EE_Addon[] $addons
99
     */
100
    public $addons;
101
102
    /**
103
     * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
104
     *
105
     * @var EEM_Base[] $models
106
     */
107
    public $models = array();
108
109
    /**
110
     * @var EED_Module[] $modules
111
     */
112
    public $modules;
113
114
    /**
115
     * @var EES_Shortcode[] $shortcodes
116
     */
117
    public $shortcodes;
118
119
    /**
120
     * @var WP_Widget[] $widgets
121
     */
122
    public $widgets;
123
124
    /**
125
     * this is an array of all implemented model names (i.e. not the parent abstract models, or models
126
     * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
127
     * Keys are model "short names" (eg "Event") as used in model relations, and values are
128
     * classnames (eg "EEM_Event")
129
     *
130
     * @var array $non_abstract_db_models
131
     */
132
    public $non_abstract_db_models = array();
133
134
135
    /**
136
     * internationalization for JS strings
137
     *    usage:   EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' );
138
     *    in js file:  var translatedString = eei18n.string_key;
139
     *
140
     * @var array $i18n_js_strings
141
     */
142
    public static $i18n_js_strings = array();
143
144
145
    /**
146
     * $main_file - path to espresso.php
147
     *
148
     * @var array $main_file
149
     */
150
    public $main_file;
151
152
    /**
153
     * array of ReflectionClass objects where the key is the class name
154
     *
155
     * @var ReflectionClass[] $_reflectors
156
     */
157
    public $_reflectors;
158
159
    /**
160
     * boolean flag to indicate whether or not to load/save dependencies from/to the cache
161
     *
162
     * @var boolean $_cache_on
163
     */
164
    protected $_cache_on = true;
165
166
167
168
    /**
169
     * @singleton method used to instantiate class object
170
     * @param  EE_Dependency_Map $dependency_map
171
     * @return EE_Registry instance
172
     * @throws InvalidArgumentException
173
     * @throws InvalidInterfaceException
174
     * @throws InvalidDataTypeException
175
     */
176
    public static function instance(EE_Dependency_Map $dependency_map = null)
177
    {
178
        // check if class object is instantiated
179
        if (! self::$_instance instanceof EE_Registry) {
180
            self::$_instance = new self($dependency_map);
0 ignored issues
show
Bug introduced by
It seems like $dependency_map defined by parameter $dependency_map on line 176 can be null; however, EE_Registry::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

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