Completed
Branch FET-10416-autoload-b4-bootstra... (9a39f6)
by
unknown
119:38 queued 108:09
created

EE_Registry::_load()   C

Complexity

Conditions 15
Paths 28

Size

Total Lines 59
Code Lines 34

Duplication

Lines 7
Ratio 11.86 %

Importance

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

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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

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

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

function notNullable(stdClass $x) { }

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

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

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