Completed
Branch BUG-10878-event-spaces-remaini... (07bd4d)
by
unknown
42:38 queued 31:47
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')) {
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);
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
        // don't give up! you gotta...
974
        try {
975
            //does the file exist and can it be read ?
976 View Code Duplication
            if (! $path) {
977
                // so sorry, can't find the file
978
                throw new EE_Error (
979
                    sprintf(
980
                        esc_html__(
981
                            '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',
982
                            'event_espresso'
983
                        ),
984
                        trim($type, '.'),
985
                        $class_name,
986
                        '<br />' . implode(',<br />', $file_paths)
987
                    )
988
                );
989
            }
990
            // get the file
991
            require_once($path);
992
            // if the class isn't already declared somewhere
993
            if (class_exists($class_name, false) === false) {
994
                // so sorry, not a class
995
                throw new EE_Error(
996
                    sprintf(
997
                        esc_html__('The %s file %s does not appear to contain the %s Class.', 'event_espresso'),
998
                        $type,
999
                        $path,
1000
                        $class_name
1001
                    )
1002
                );
1003
            }
1004
        } catch (EE_Error $e) {
1005
            $e->get_error();
1006
            return false;
1007
        }
1008
        return true;
1009
    }
1010
1011
1012
1013
    /**
1014
     * _create_object
1015
     * Attempts to instantiate the requested class via any of the
1016
     * commonly used instantiation methods employed throughout EE.
1017
     * The priority for instantiation is as follows:
1018
     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1019
     *        - model objects via their 'new_instance_from_db' method
1020
     *        - model objects via their 'new_instance' method
1021
     *        - "singleton" classes" via their 'instance' method
1022
     *    - standard instantiable classes via their __constructor
1023
     * Prior to instantiation, if the classname exists in the dependency_map,
1024
     * then the constructor for the requested class will be examined to determine
1025
     * if any dependencies exist, and if they can be injected.
1026
     * If so, then those classes will be added to the array of arguments passed to the constructor
1027
     *
1028
     * @param string $class_name
1029
     * @param array  $arguments
1030
     * @param string $type
1031
     * @param bool   $from_db
1032
     * @return null|object
1033
     * @throws EE_Error
1034
     * @throws ReflectionException
1035
     */
1036
    protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
1037
    {
1038
        $class_obj = null;
1039
        $instantiation_mode = '0) none';
1040
        // don't give up! you gotta...
1041
        try {
1042
            // create reflection
1043
            $reflector = $this->get_ReflectionClass($class_name);
1044
            // make sure arguments are an array
1045
            $arguments = is_array($arguments)
1046
                ? $arguments
1047
                : array($arguments);
1048
            // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1049
            // else wrap it in an additional array so that it doesn't get split into multiple parameters
1050
            $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1051
                ? $arguments
1052
                : array($arguments);
1053
            // attempt to inject dependencies ?
1054
            if ($this->_dependency_map->has($class_name)) {
1055
                $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1056
            }
1057
            // instantiate the class if possible
1058
            if ($reflector->isAbstract()) {
1059
                // nothing to instantiate, loading file was enough
1060
                // does not throw an exception so $instantiation_mode is unused
1061
                // $instantiation_mode = "1) no constructor abstract class";
1062
                $class_obj = true;
1063
            } else if (empty($arguments) && $reflector->getConstructor() === null && $reflector->isInstantiable()) {
1064
                // no constructor = static methods only... nothing to instantiate, loading file was enough
1065
                $instantiation_mode = '2) no constructor but instantiable';
1066
                $class_obj = $reflector->newInstance();
1067
            } else if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1068
                $instantiation_mode = '3) new_instance_from_db()';
1069
                $class_obj = call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1070
            } else if (method_exists($class_name, 'new_instance')) {
1071
                $instantiation_mode = '4) new_instance()';
1072
                $class_obj = call_user_func_array(array($class_name, 'new_instance'), $arguments);
1073
            } else if (method_exists($class_name, 'instance')) {
1074
                $instantiation_mode = '5) instance()';
1075
                $class_obj = call_user_func_array(array($class_name, 'instance'), $arguments);
1076
            } else if ($reflector->isInstantiable()) {
1077
                $instantiation_mode = '6) constructor';
1078
                $class_obj = $reflector->newInstanceArgs($arguments);
1079
            } else {
1080
                // heh ? something's not right !
1081
                throw new EE_Error(
1082
                    sprintf(
1083
                        esc_html__('The %s file %s could not be instantiated.', 'event_espresso'),
1084
                        $type,
1085
                        $class_name
1086
                    )
1087
                );
1088
            }
1089
        } catch (Exception $e) {
1090
            if (! $e instanceof EE_Error) {
1091
                $e = new EE_Error(
1092
                    sprintf(
1093
                        esc_html__(
1094
                            'The following error occurred while attempting to instantiate "%1$s": %2$s %3$s %2$s instantiation mode : %4$s',
1095
                            'event_espresso'
1096
                        ),
1097
                        $class_name,
1098
                        '<br />',
1099
                        $e->getMessage(),
1100
                        $instantiation_mode
1101
                    )
1102
                );
1103
            }
1104
            $e->get_error();
1105
        }
1106
        return $class_obj;
1107
    }
1108
1109
1110
1111
    /**
1112
     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1113
     * @param array $array
1114
     * @return bool
1115
     */
1116
    protected function _array_is_numerically_and_sequentially_indexed(array $array)
1117
    {
1118
        return ! empty($array)
1119
            ? array_keys($array) === range(0, count($array) - 1)
1120
            : true;
1121
    }
1122
1123
1124
1125
    /**
1126
     * getReflectionClass
1127
     * checks if a ReflectionClass object has already been generated for a class
1128
     * and returns that instead of creating a new one
1129
     *
1130
     * @param string $class_name
1131
     * @return ReflectionClass
1132
     * @throws ReflectionException
1133
     */
1134 View Code Duplication
    public function get_ReflectionClass($class_name)
1135
    {
1136
        if (
1137
            ! isset($this->_reflectors[$class_name])
1138
            || ! $this->_reflectors[$class_name] instanceof ReflectionClass
1139
        ) {
1140
            $this->_reflectors[$class_name] = new ReflectionClass($class_name);
1141
        }
1142
        return $this->_reflectors[$class_name];
1143
    }
1144
1145
1146
1147
    /**
1148
     * _resolve_dependencies
1149
     * examines the constructor for the requested class to determine
1150
     * if any dependencies exist, and if they can be injected.
1151
     * If so, then those classes will be added to the array of arguments passed to the constructor
1152
     * PLZ NOTE: this is achieved by type hinting the constructor params
1153
     * For example:
1154
     *        if attempting to load a class "Foo" with the following constructor:
1155
     *        __construct( Bar $bar_class, Fighter $grohl_class )
1156
     *        then $bar_class and $grohl_class will be added to the $arguments array,
1157
     *        but only IF they are NOT already present in the incoming arguments array,
1158
     *        and the correct classes can be loaded
1159
     *
1160
     * @param ReflectionClass $reflector
1161
     * @param string          $class_name
1162
     * @param array           $arguments
1163
     * @return array
1164
     * @throws EE_Error
1165
     * @throws ReflectionException
1166
     */
1167
    protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, $arguments = array())
1168
    {
1169
        // let's examine the constructor
1170
        $constructor = $reflector->getConstructor();
1171
        // whu? huh? nothing?
1172
        if (! $constructor) {
1173
            return $arguments;
1174
        }
1175
        // get constructor parameters
1176
        $params = $constructor->getParameters();
1177
        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1178
        $argument_keys = array_keys($arguments);
1179
        // now loop thru all of the constructors expected parameters
1180
        foreach ($params as $index => $param) {
1181
            // is this a dependency for a specific class ?
1182
            $param_class = $param->getClass()
1183
                ? $param->getClass()->name
1184
                : null;
1185
            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1186
            $param_class = $this->_dependency_map->has_alias($param_class, $class_name)
1187
                ? $this->_dependency_map->get_alias($param_class, $class_name)
1188
                : $param_class;
1189
            if (
1190
                // param is not even a class
1191
                $param_class === null
1192
                // and something already exists in the incoming arguments for this param
1193
                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1194
            ) {
1195
                // so let's skip this argument and move on to the next
1196
                continue;
1197
            }
1198
            if (
1199
                // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1200
                $param_class !== null
1201
                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1202
                && $arguments[$argument_keys[$index]] instanceof $param_class
1203
            ) {
1204
                // skip this argument and move on to the next
1205
                continue;
1206
            }
1207
            if (
1208
                // parameter is type hinted as a class, and should be injected
1209
                $param_class !== null
1210
                && $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1211
            ) {
1212
                $arguments = $this->_resolve_dependency(
1213
                    $class_name,
1214
                    $param_class,
1215
                    $arguments,
1216
                    $index,
1217
                    $argument_keys
1218
                );
1219
            } else {
1220
                try {
1221
                    $arguments[$index] = $param->isDefaultValueAvailable()
1222
                        ? $param->getDefaultValue()
1223
                        : null;
1224
                } catch (ReflectionException $e) {
1225
                    throw new ReflectionException(
1226
                        sprintf(
1227
                            esc_html__('%1$s for parameter "$%2$s"', 'event_espresso'),
1228
                            $e->getMessage(),
1229
                            $param->getName()
1230
                        )
1231
                    );
1232
                }
1233
            }
1234
        }
1235
        return $arguments;
1236
    }
1237
1238
1239
1240
    /**
1241
     * @param string $class_name
1242
     * @param string $param_class
1243
     * @param array  $arguments
1244
     * @param mixed  $index
1245
     * @param array  $argument_keys
1246
     * @return array
1247
     * @throws EE_Error
1248
     * @throws ReflectionException
1249
     * @throws InvalidArgumentException
1250
     * @throws InvalidInterfaceException
1251
     * @throws InvalidDataTypeException
1252
     */
1253
    protected function _resolve_dependency($class_name, $param_class, $arguments, $index, array $argument_keys)
1254
    {
1255
        $dependency = null;
1256
        // should dependency be loaded from cache ?
1257
        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1258
            $class_name,
1259
            $param_class
1260
        );
1261
        $cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1262
        // we might have a dependency...
1263
        // let's MAYBE try and find it in our cache if that's what's been requested
1264
        $cached_class = $cache_on
1265
            ? $this->_get_cached_class($param_class)
1266
            : null;
1267
        // and grab it if it exists
1268
        if ($cached_class instanceof $param_class) {
1269
            $dependency = $cached_class;
1270
        } else if ($param_class !== $class_name) {
1271
            // obtain the loader method from the dependency map
1272
            $loader = $this->_dependency_map->class_loader($param_class);
1273
            // is loader a custom closure ?
1274
            if ($loader instanceof Closure) {
1275
                $dependency = $loader($arguments);
1276
            } else {
1277
                // set the cache on property for the recursive loading call
1278
                $this->_cache_on = $cache_on;
1279
                // if not, then let's try and load it via the registry
1280
                if ($loader && method_exists($this, $loader)) {
1281
                    $dependency = $this->{$loader}($param_class);
1282
                } else {
1283
                    $dependency = LoaderFactory::getLoader()->load(
1284
                        $param_class,
1285
                        array(),
1286
                        $cache_on
1287
                    );
1288
                }
1289
            }
1290
        }
1291
        // did we successfully find the correct dependency ?
1292
        if ($dependency instanceof $param_class) {
1293
            // then let's inject it into the incoming array of arguments at the correct location
1294
            $arguments[$index] = $dependency;
1295
        }
1296
        return $arguments;
1297
    }
1298
1299
1300
1301
    /**
1302
     * _set_cached_class
1303
     * attempts to cache the instantiated class locally
1304
     * in one of the following places, in the following order:
1305
     *        $this->{class_abbreviation}   ie:    $this->CART
1306
     *        $this->{$class_name}          ie:    $this->Some_Class
1307
     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1308
     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1309
     *
1310
     * @param object $class_obj
1311
     * @param string $class_name
1312
     * @param string $class_prefix
1313
     * @param bool   $from_db
1314
     * @return void
1315
     */
1316
    protected function _set_cached_class($class_obj, $class_name, $class_prefix = '', $from_db = false)
1317
    {
1318
        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1319
            return;
1320
        }
1321
        // return newly instantiated class
1322
        $class_abbreviation = $this->get_class_abbreviation($class_name, '');
1323
        if ($class_abbreviation) {
1324
            $this->{$class_abbreviation} = $class_obj;
1325
            return;
1326
        }
1327
        $class_name = str_replace('\\', '_', $class_name);
1328
        if (property_exists($this, $class_name)) {
1329
            $this->{$class_name} = $class_obj;
1330
            return;
1331
        }
1332
        if ($class_prefix === 'addon') {
1333
            $this->addons->{$class_name} = $class_obj;
1334
            return;
1335
        }
1336
        if (! $from_db) {
1337
            $this->LIB->{$class_name} = $class_obj;
1338
        }
1339
    }
1340
1341
1342
1343
    /**
1344
     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1345
     *
1346
     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1347
     *                          in the EE_Dependency_Map::$_class_loaders array,
1348
     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1349
     * @param array  $arguments
1350
     * @return object
1351
     */
1352
    public static function factory($classname, $arguments = array())
1353
    {
1354
        $loader = self::instance()->_dependency_map->class_loader($classname);
1355
        if ($loader instanceof Closure) {
1356
            return $loader($arguments);
1357
        }
1358
        if (method_exists(self::instance(), $loader)) {
1359
            return self::instance()->{$loader}($classname, $arguments);
1360
        }
1361
        return null;
1362
    }
1363
1364
1365
1366
    /**
1367
     * Gets the addon by its name/slug (not classname. For that, just
1368
     * use the classname as the property name on EE_Config::instance()->addons)
1369
     *
1370
     * @param string $name
1371
     * @return EE_Addon
1372
     */
1373
    public function get_addon_by_name($name)
1374
    {
1375
        foreach ($this->addons as $addon) {
1376
            if ($addon->name() === $name) {
1377
                return $addon;
1378
            }
1379
        }
1380
        return null;
1381
    }
1382
1383
1384
1385
    /**
1386
     * Gets an array of all the registered addons, where the keys are their names. (ie, what each returns for their
1387
     * name() function) They're already available on EE_Config::instance()->addons as properties, where each property's
1388
     * name is the addon's classname. So if you just want to get the addon by classname, use
1389
     * EE_Config::instance()->addons->{classname}
1390
     *
1391
     * @return EE_Addon[] where the KEYS are the addon's name()
1392
     */
1393
    public function get_addons_by_name()
1394
    {
1395
        $addons = array();
1396
        foreach ($this->addons as $addon) {
1397
            $addons[$addon->name()] = $addon;
1398
        }
1399
        return $addons;
1400
    }
1401
1402
1403
1404
    /**
1405
     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1406
     * a stale copy of it around
1407
     *
1408
     * @param string $model_name
1409
     * @return \EEM_Base
1410
     * @throws \EE_Error
1411
     */
1412
    public function reset_model($model_name)
1413
    {
1414
        $model_class_name = strpos($model_name, 'EEM_') !== 0
1415
            ? "EEM_{$model_name}"
1416
            : $model_name;
1417
        if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1418
            return null;
1419
        }
1420
        //get that model reset it and make sure we nuke the old reference to it
1421
        if ($this->LIB->{$model_class_name} instanceof $model_class_name
1422
            && is_callable(
1423
                array($model_class_name, 'reset')
1424
            )) {
1425
            $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1426
        } else {
1427
            throw new EE_Error(sprintf(esc_html__('Model %s does not have a method "reset"', 'event_espresso'), $model_name));
1428
        }
1429
        return $this->LIB->{$model_class_name};
1430
    }
1431
1432
1433
1434
    /**
1435
     * Resets the registry.
1436
     * The criteria for what gets reset is based on what can be shared between sites on the same request when
1437
     * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1438
     * - $_dependency_map
1439
     * - $_class_abbreviations
1440
     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1441
     * - $REQ:  Still on the same request so no need to change.
1442
     * - $CAP: There is no site specific state in the EE_Capability class.
1443
     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1444
     * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1445
     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1446
     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1447
     *             switch or on the restore.
1448
     * - $modules
1449
     * - $shortcodes
1450
     * - $widgets
1451
     *
1452
     * @param boolean $hard             [deprecated]
1453
     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1454
     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1455
     *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1456
     * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1457
     *                                  client
1458
     *                                  code instead can just change the model context to a different blog id if
1459
     *                                  necessary
1460
     * @return EE_Registry
1461
     * @throws EE_Error
1462
     * @throws ReflectionException
1463
     */
1464
    public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1465
    {
1466
        $instance = self::instance();
1467
        $instance->_cache_on = true;
1468
        // reset some "special" classes
1469
        EEH_Activation::reset();
1470
        $hard = apply_filters( 'FHEE__EE_Registry__reset__hard', $hard);
1471
        $instance->CFG = EE_Config::reset($hard, $reinstantiate);
1472
        $instance->CART = null;
1473
        $instance->MRM = null;
1474
        $instance->AssetsRegistry = $instance->create('EventEspresso\core\services\assets\Registry');
1475
        //messages reset
1476
        EED_Messages::reset();
1477
        //handle of objects cached on LIB
1478
        foreach (array('LIB', 'modules') as $cache) {
1479
            foreach ($instance->{$cache} as $class_name => $class) {
1480
                if (self::_reset_and_unset_object($class, $reset_models)) {
1481
                    unset($instance->{$cache}->{$class_name});
1482
                }
1483
            }
1484
        }
1485
        return $instance;
1486
    }
1487
1488
1489
1490
    /**
1491
     * if passed object implements ResettableInterface, then call it's reset() method
1492
     * if passed object implements InterminableInterface, then return false,
1493
     * to indicate that it should NOT be cleared from the Registry cache
1494
     *
1495
     * @param      $object
1496
     * @param bool $reset_models
1497
     * @return bool returns true if cached object should be unset
1498
     */
1499
    private static function _reset_and_unset_object($object, $reset_models)
1500
    {
1501
        if (! is_object($object)) {
1502
            // don't unset anything that's not an object
1503
            return false;
1504
        }
1505
        if ($object instanceof EED_Module) {
1506
            $object::reset();
1507
            // don't unset modules
1508
            return false;
1509
        }
1510
        if ($object instanceof ResettableInterface) {
1511
            if ($object instanceof EEM_Base) {
1512
                if ($reset_models) {
1513
                    $object->reset();
1514
                    return true;
1515
                }
1516
                return false;
1517
            }
1518
            $object->reset();
1519
            return true;
1520
        }
1521
        if (! $object instanceof InterminableInterface) {
1522
            return true;
1523
        }
1524
        return false;
1525
    }
1526
1527
1528
1529
    /**
1530
     * Gets all the custom post type models defined
1531
     *
1532
     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1533
     */
1534
    public function cpt_models()
1535
    {
1536
        $cpt_models = array();
1537
        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1538
            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1539
                $cpt_models[$short_name] = $classname;
1540
            }
1541
        }
1542
        return $cpt_models;
1543
    }
1544
1545
1546
1547
    /**
1548
     * @return \EE_Config
1549
     */
1550
    public static function CFG()
1551
    {
1552
        return self::instance()->CFG;
1553
    }
1554
1555
1556
}
1557
// End of file EE_Registry.core.php
1558
// Location: ./core/EE_Registry.core.php
1559