Completed
Branch FET-10785-ee-system-loader (d67185)
by
unknown
106:46 queued 95:31
created

EE_Registry::load_file()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 5
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\interfaces\InterminableInterface;
4
use EventEspresso\core\interfaces\ResettableInterface;
5
use EventEspresso\core\services\assets\Registry;
6
7
defined('EVENT_ESPRESSO_VERSION') || exit;
8
9
10
11
/**
12
 * EE_Registry Class
13
 * Centralized Application Data Storage and Management
14
 *
15
 * @package                   Event Espresso
16
 * @subpackage                core
17
 * @author                    Brent Christensen
18
 */
19
class EE_Registry implements ResettableInterface
20
{
21
22
    /**
23
     *    EE_Registry Object
24
     *
25
     * @var EE_Registry $_instance
26
     * @access    private
27
     */
28
    private static $_instance = null;
29
30
    /**
31
     * @var EE_Dependency_Map $_dependency_map
32
     * @access    protected
33
     */
34
    protected $_dependency_map = null;
35
36
    /**
37
     * @var array $_class_abbreviations
38
     * @access    protected
39
     */
40
    protected $_class_abbreviations = array();
41
42
    /**
43
     * @access public
44
     * @var \EventEspresso\core\services\commands\CommandBusInterface $BUS
45
     */
46
    public $BUS;
47
48
    /**
49
     *    EE_Cart Object
50
     *
51
     * @access    public
52
     * @var    EE_Cart $CART
53
     */
54
    public $CART = null;
55
56
    /**
57
     *    EE_Config Object
58
     *
59
     * @access    public
60
     * @var    EE_Config $CFG
61
     */
62
    public $CFG = null;
63
64
    /**
65
     * EE_Network_Config Object
66
     *
67
     * @access public
68
     * @var EE_Network_Config $NET_CFG
69
     */
70
    public $NET_CFG = null;
71
72
    /**
73
     *    StdClass object for storing library classes in
74
     *
75
     * @public LIB
76
     * @var StdClass $LIB
77
     */
78
    public $LIB = null;
79
80
    /**
81
     *    EE_Request_Handler Object
82
     *
83
     * @access    public
84
     * @var    EE_Request_Handler $REQ
85
     */
86
    public $REQ = null;
87
88
    /**
89
     *    EE_Session Object
90
     *
91
     * @access    public
92
     * @var    EE_Session $SSN
93
     */
94
    public $SSN = null;
95
96
    /**
97
     * holds the ee capabilities object.
98
     *
99
     * @since 4.5.0
100
     * @var EE_Capabilities
101
     */
102
    public $CAP = null;
103
104
    /**
105
     * holds the EE_Message_Resource_Manager object.
106
     *
107
     * @since 4.9.0
108
     * @var EE_Message_Resource_Manager
109
     */
110
    public $MRM = null;
111
112
113
    /**
114
     * Holds the Assets Registry instance
115
     * @var Registry
116
     */
117
    public $AssetsRegistry = null;
118
119
    /**
120
     *    $addons - StdClass object for holding addons which have registered themselves to work with EE core
121
     *
122
     * @access    public
123
     * @var    EE_Addon[]
124
     */
125
    public $addons = null;
126
127
    /**
128
     *    $models
129
     * @access    public
130
     * @var    EEM_Base[] $models keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
131
     */
132
    public $models = array();
133
134
    /**
135
     *    $modules
136
     * @access    public
137
     * @var    EED_Module[] $modules
138
     */
139
    public $modules = null;
140
141
    /**
142
     *    $shortcodes
143
     * @access    public
144
     * @var    EES_Shortcode[] $shortcodes
145
     */
146
    public $shortcodes = null;
147
148
    /**
149
     *    $widgets
150
     * @access    public
151
     * @var    WP_Widget[] $widgets
152
     */
153
    public $widgets = null;
154
155
    /**
156
     * $non_abstract_db_models
157
     * @access public
158
     * @var array this is an array of all implemented model names (i.e. not the parent abstract models, or models
159
     * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
160
     * Keys are model "short names" (eg "Event") as used in model relations, and values are
161
     * classnames (eg "EEM_Event")
162
     */
163
    public $non_abstract_db_models = array();
164
165
166
    /**
167
     *    $i18n_js_strings - internationalization for JS strings
168
     *    usage:   EE_Registry::i18n_js_strings['string_key'] = __( 'string to translate.', 'event_espresso' );
169
     *    in js file:  var translatedString = eei18n.string_key;
170
     *
171
     * @access    public
172
     * @var    array
173
     */
174
    public static $i18n_js_strings = array();
175
176
177
    /**
178
     *    $main_file - path to espresso.php
179
     *
180
     * @access    public
181
     * @var    array
182
     */
183
    public $main_file;
184
185
    /**
186
     * array of ReflectionClass objects where the key is the class name
187
     *
188
     * @access    public
189
     * @var ReflectionClass[]
190
     */
191
    public $_reflectors;
192
193
    /**
194
     * boolean flag to indicate whether or not to load/save dependencies from/to the cache
195
     *
196
     * @access    protected
197
     * @var boolean $_cache_on
198
     */
199
    protected $_cache_on = true;
200
201
202
203
    /**
204
     * @singleton method used to instantiate class object
205
     * @access    public
206
     * @param  \EE_Dependency_Map $dependency_map
207
     * @return \EE_Registry instance
208
     */
209
    public static function instance(\EE_Dependency_Map $dependency_map = null)
210
    {
211
        // check if class object is instantiated
212
        if ( ! self::$_instance instanceof EE_Registry) {
213
            self::$_instance = new EE_Registry($dependency_map);
0 ignored issues
show
Bug introduced by
It seems like $dependency_map defined by parameter $dependency_map on line 209 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...
214
        }
215
        return self::$_instance;
216
    }
217
218
219
220
    /**
221
     *protected constructor to prevent direct creation
222
     *
223
     * @Constructor
224
     * @access protected
225
     * @param  \EE_Dependency_Map $dependency_map
226
     */
227
    protected function __construct(\EE_Dependency_Map $dependency_map)
228
    {
229
        $this->_dependency_map = $dependency_map;
230
        $this->LIB = new stdClass();
231
        $this->addons = new stdClass();
232
        $this->modules = new stdClass();
233
        $this->shortcodes = new stdClass();
234
        $this->widgets = new stdClass();
235
        add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
236
    }
237
238
239
240
    /**
241
     * initialize
242
     */
243
    public function initialize()
244
    {
245
        $this->_class_abbreviations = apply_filters(
246
            'FHEE__EE_Registry____construct___class_abbreviations',
247
            array(
248
                'EE_Config'                                       => 'CFG',
249
                'EE_Session'                                      => 'SSN',
250
                'EE_Capabilities'                                 => 'CAP',
251
                'EE_Cart'                                         => 'CART',
252
                'EE_Network_Config'                               => 'NET_CFG',
253
                'EE_Request_Handler'                              => 'REQ',
254
                'EE_Message_Resource_Manager'                     => 'MRM',
255
                'EventEspresso\core\services\commands\CommandBus' => 'BUS',
256
                'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
257
            )
258
        );
259
        $this->load_core('Base', array(), true);
260
        // add our request and response objects to the cache
261
        $request_loader = $this->_dependency_map->class_loader('EE_Request');
262
        $this->_set_cached_class(
263
            $request_loader(),
264
            'EE_Request'
265
        );
266
        $response_loader = $this->_dependency_map->class_loader('EE_Response');
267
        $this->_set_cached_class(
268
            $response_loader(),
269
            'EE_Response'
270
        );
271
        add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
272
    }
273
274
275
276
    /**
277
     *    init
278
     *
279
     * @access    public
280
     * @return    void
281
     */
282
    public function init()
283
    {
284
        // Get current page protocol
285
        $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
286
        // Output admin-ajax.php URL with same protocol as current page
287
        self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
288
        self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
289
    }
290
291
292
293
    /**
294
     * localize_i18n_js_strings
295
     *
296
     * @return string
297
     */
298
    public static function localize_i18n_js_strings()
299
    {
300
        $i18n_js_strings = (array)EE_Registry::$i18n_js_strings;
301
        foreach ($i18n_js_strings as $key => $value) {
302
            if (is_scalar($value)) {
303
                $i18n_js_strings[$key] = html_entity_decode((string)$value, ENT_QUOTES, 'UTF-8');
304
            }
305
        }
306
        return "/* <![CDATA[ */ var eei18n = " . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
307
    }
308
309
310
311
    /**
312
     * @param mixed string | EED_Module $module
313
     */
314
    public function add_module($module)
315
    {
316
        if ($module instanceof EED_Module) {
317
            $module_class = get_class($module);
318
            $this->modules->{$module_class} = $module;
319
        } else {
320
            if ( ! class_exists('EE_Module_Request_Router')) {
321
                $this->load_core('Module_Request_Router');
322
            }
323
            $this->modules->{$module} = EE_Module_Request_Router::module_factory($module);
324
        }
325
    }
326
327
328
329
    /**
330
     * @param string $module_name
331
     * @return mixed EED_Module | NULL
332
     */
333
    public function get_module($module_name = '')
334
    {
335
        return isset($this->modules->{$module_name}) ? $this->modules->{$module_name} : null;
336
    }
337
338
339
340
    /**
341
     *    loads core classes - must be singletons
342
     *
343
     * @access    public
344
     * @param string $class_name - simple class name ie: session
345
     * @param mixed  $arguments
346
     * @param bool   $load_only
347
     * @return mixed
348
     */
349
    public function load_core($class_name, $arguments = array(), $load_only = false)
350
    {
351
        $core_paths = apply_filters(
352
            'FHEE__EE_Registry__load_core__core_paths',
353
            array(
354
                EE_CORE,
355
                EE_ADMIN,
356
                EE_CPTS,
357
                EE_CORE . 'data_migration_scripts' . DS,
358
                EE_CORE . 'request_stack' . DS,
359
                EE_CORE . 'middleware' . DS,
360
            )
361
        );
362
        // retrieve instantiated class
363
        return $this->_load($core_paths, 'EE_', $class_name, 'core', $arguments, false, true, $load_only);
364
    }
365
366
367
368
    /**
369
     *    loads service classes
370
     *
371
     * @access    public
372
     * @param string $class_name - simple class name ie: session
373
     * @param mixed  $arguments
374
     * @param bool   $load_only
375
     * @return mixed
376
     */
377
    public function load_service($class_name, $arguments = array(), $load_only = false)
378
    {
379
        $service_paths = apply_filters(
380
            'FHEE__EE_Registry__load_service__service_paths',
381
            array(
382
                EE_CORE . 'services' . DS,
383
            )
384
        );
385
        // retrieve instantiated class
386
        return $this->_load($service_paths, 'EE_', $class_name, 'class', $arguments, false, true, $load_only);
387
    }
388
389
390
391
    /**
392
     *    loads data_migration_scripts
393
     *
394
     * @access    public
395
     * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
396
     * @param mixed  $arguments
397
     * @return EE_Data_Migration_Script_Base|mixed
398
     */
399
    public function load_dms($class_name, $arguments = array())
400
    {
401
        // retrieve instantiated class
402
        return $this->_load(EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(), 'EE_DMS_', $class_name, 'dms', $arguments, false, false, false);
403
    }
404
405
406
407
    /**
408
     *    loads object creating classes - must be singletons
409
     *
410
     * @param string $class_name - simple class name ie: attendee
411
     * @param mixed  $arguments  - an array of arguments to pass to the class
412
     * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to instantiate
413
     * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then set this to FALSE (ie. when instantiating model objects from client in a loop)
414
     * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate (default)
415
     * @return EE_Base_Class | bool
416
     */
417
    public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
418
    {
419
        $paths = apply_filters('FHEE__EE_Registry__load_class__paths', array(
420
            EE_CORE,
421
            EE_CLASSES,
422
            EE_BUSINESS,
423
        ));
424
        // retrieve instantiated class
425
        return $this->_load($paths, 'EE_', $class_name, 'class', $arguments, $from_db, $cache, $load_only);
426
    }
427
428
429
430
    /**
431
     *    loads helper classes - must be singletons
432
     *
433
     * @param string $class_name - simple class name ie: price
434
     * @param mixed  $arguments
435
     * @param bool   $load_only
436
     * @return EEH_Base | bool
437
     */
438
    public function load_helper($class_name, $arguments = array(), $load_only = true)
439
    {
440
        // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
441
        $helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
442
        // retrieve instantiated class
443
        return $this->_load($helper_paths, 'EEH_', $class_name, 'helper', $arguments, false, true, $load_only);
444
    }
445
446
447
448
    /**
449
     *    loads core classes - must be singletons
450
     *
451
     * @access    public
452
     * @param string $class_name - simple class name ie: session
453
     * @param mixed  $arguments
454
     * @param bool   $load_only
455
     * @param bool   $cache      whether to cache the object or not.
456
     * @return mixed
457
     */
458
    public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
459
    {
460
        $paths = array(
461
            EE_LIBRARIES,
462
            EE_LIBRARIES . 'messages' . DS,
463
            EE_LIBRARIES . 'shortcodes' . DS,
464
            EE_LIBRARIES . 'qtips' . DS,
465
            EE_LIBRARIES . 'payment_methods' . DS,
466
        );
467
        // retrieve instantiated class
468
        return $this->_load($paths, 'EE_', $class_name, 'lib', $arguments, false, $cache, $load_only);
469
    }
470
471
472
473
    /**
474
     *    loads model classes - must be singletons
475
     *
476
     * @param string $class_name - simple class name ie: price
477
     * @param mixed  $arguments
478
     * @param bool   $load_only
479
     * @return EEM_Base | bool
480
     */
481
    public function load_model($class_name, $arguments = array(), $load_only = false)
482
    {
483
        $paths = apply_filters('FHEE__EE_Registry__load_model__paths', array(
484
            EE_MODELS,
485
            EE_CORE,
486
        ));
487
        // retrieve instantiated class
488
        return $this->_load($paths, 'EEM_', $class_name, 'model', $arguments, false, true, $load_only);
489
    }
490
491
492
493
    /**
494
     *    loads model classes - must be singletons
495
     *
496
     * @param string $class_name - simple class name ie: price
497
     * @param mixed  $arguments
498
     * @param bool   $load_only
499
     * @return mixed | bool
500
     */
501
    public function load_model_class($class_name, $arguments = array(), $load_only = true)
502
    {
503
        $paths = array(
504
            EE_MODELS . 'fields' . DS,
505
            EE_MODELS . 'helpers' . DS,
506
            EE_MODELS . 'relations' . DS,
507
            EE_MODELS . 'strategies' . DS,
508
        );
509
        // retrieve instantiated class
510
        return $this->_load($paths, 'EE_', $class_name, '', $arguments, false, true, $load_only);
511
    }
512
513
514
515
    /**
516
     * Determines if $model_name is the name of an actual EE model.
517
     *
518
     * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
519
     * @return boolean
520
     */
521
    public function is_model_name($model_name)
522
    {
523
        return isset($this->models[$model_name]) ? true : false;
524
    }
525
526
527
528
    /**
529
     *    generic class loader
530
     *
531
     * @param string $path_to_file - directory path to file location, not including filename
532
     * @param string $file_name    - file name  ie:  my_file.php, including extension
533
     * @param string $type         - file type - core? class? helper? model?
534
     * @param mixed  $arguments
535
     * @param bool   $load_only
536
     * @return mixed
537
     */
538
    public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
539
    {
540
        // retrieve instantiated class
541
        return $this->_load($path_to_file, '', $file_name, $type, $arguments, false, true, $load_only);
542
    }
543
544
545
546
    /**
547
     *    load_addon
548
     *
549
     * @param string $path_to_file - directory path to file location, not including filename
550
     * @param string $class_name   - full class name  ie:  My_Class
551
     * @param string $type         - file type - core? class? helper? model?
552
     * @param mixed  $arguments
553
     * @param bool   $load_only
554
     * @return EE_Addon
555
     */
556
    public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
557
    {
558
        // retrieve instantiated class
559
        return $this->_load($path_to_file, 'addon', $class_name, $type, $arguments, false, true, $load_only);
560
    }
561
562
563
564
    /**
565
     * instantiates, caches, and automatically resolves dependencies
566
     * for classes that use a Fully Qualified Class Name.
567
     * if the class is not capable of being loaded using PSR-4 autoloading,
568
     * then you need to use one of the existing load_*() methods
569
     * which can resolve the classname and filepath from the passed arguments
570
     *
571
     * @param bool|string $class_name   Fully Qualified Class Name
572
     * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
573
     * @param bool        $cache        whether to cache the instantiated object for reuse
574
     * @param bool        $from_db      some classes are instantiated from the db
575
     *                                  and thus call a different method to instantiate
576
     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
577
     * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
578
     * @return mixed null = failure to load or instantiate class object.
579
     *                                  object = class loaded and instantiated successfully.
580
     *                                  bool = fail or success when $load_only is true
581
     * @throws EE_Error
582
     */
583
    public function create(
584
        $class_name = false,
585
        $arguments = array(),
586
        $cache = false,
587
        $from_db = false,
588
        $load_only = false,
589
        $addon = false
590
    ) {
591
        $class_name = ltrim($class_name, '\\');
592
        $class_name = $this->_dependency_map->get_alias($class_name);
593
        $class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
594
        // if a non-FQCN was passed, then verifyClassExists() might return an object
595
        // or it could return null if the class just could not be found anywhere
596
        if ($class_exists instanceof $class_name || $class_exists === null){
597
            // either way, return the results
598
            return $class_exists;
599
        }
600
        $class_name = $class_exists;
601
        // if we're only loading the class and it already exists, then let's just return true immediately
602
        if ($load_only) {
603
            return true;
604
        }
605
        $addon = $addon ? 'addon' : '';
606
        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
607
        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
608
        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
609 View Code Duplication
        if ($this->_cache_on && $cache && ! $load_only) {
610
            // return object if it's already cached
611
            $cached_class = $this->_get_cached_class($class_name, $addon);
612
            if ($cached_class !== null) {
613
                return $cached_class;
614
            }
615
        }
616
        // instantiate the requested object
617
        $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $class_obj is correct as $this->_create_object($c...ents, $addon, $from_db) (which targets EE_Registry::_create_object()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
618
        // if caching is turned on OR this class is cached in a class property
619
        if (($this->_cache_on && $cache) || isset($this->_class_abbreviations[ $class_name ])) {
620
            // save it for later... kinda like gum  { : $
621
            $this->_set_cached_class($class_obj, $class_name, $addon, $from_db);
622
        }
623
        $this->_cache_on = true;
624
        return $class_obj;
625
    }
626
627
628
629
    /**
630
     * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
631
     *
632
     * @param string $class_name
633
     * @param array  $arguments
634
     * @param int    $attempt
635
     * @return mixed
636
     */
637
    private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1) {
638
        if (is_object($class_name) || class_exists($class_name)) {
639
            return $class_name;
640
        }
641
        switch ($attempt) {
642
            case 1:
643
                // if it's a FQCN then maybe the class is registered with a preceding \
644
                $class_name = strpos($class_name, '\\') !== false
645
                    ? '\\' . ltrim($class_name, '\\')
646
                    : $class_name;
647
                break;
648
            case 2:
649
                //
650
                $loader = $this->_dependency_map->class_loader($class_name);
651
                if ($loader && method_exists($this, $loader)) {
652
                    return $this->{$loader}($class_name, $arguments);
653
                }
654
                break;
655
            case 3:
656
            default;
657
                return null;
658
        }
659
        $attempt++;
660
        return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
661
    }
662
663
664
665
    /**
666
     * instantiates, caches, and injects dependencies for classes
667
     *
668
     * @param array       $file_paths   an array of paths to folders to look in
669
     * @param string      $class_prefix EE  or EEM or... ???
670
     * @param bool|string $class_name   $class name
671
     * @param string      $type         file type - core? class? helper? model?
672
     * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
673
     * @param bool        $from_db      some classes are instantiated from the db
674
     *                                  and thus call a different method to instantiate
675
     * @param bool        $cache        whether to cache the instantiated object for reuse
676
     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
677
     * @return bool|null|object null = failure to load or instantiate class object.
678
     *                                  object = class loaded and instantiated successfully.
679
     *                                  bool = fail or success when $load_only is true
680
     * @throws EE_Error
681
     */
682
    protected function _load(
683
        $file_paths = array(),
684
        $class_prefix = 'EE_',
685
        $class_name = false,
686
        $type = 'class',
687
        $arguments = array(),
688
        $from_db = false,
689
        $cache = true,
690
        $load_only = false
691
    ) {
692
        $class_name = ltrim($class_name, '\\');
693
        // strip php file extension
694
        $class_name = str_replace('.php', '', trim($class_name));
695
        // does the class have a prefix ?
696
        if ( ! empty($class_prefix) && $class_prefix != 'addon') {
697
            // make sure $class_prefix is uppercase
698
            $class_prefix = strtoupper(trim($class_prefix));
699
            // add class prefix ONCE!!!
700
            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
701
        }
702
        $class_name = $this->_dependency_map->get_alias($class_name);
703
        $class_exists = class_exists($class_name);
704
        // if we're only loading the class and it already exists, then let's just return true immediately
705
        if ($load_only && $class_exists) {
706
            return true;
707
        }
708
        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
709
        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
710
        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
711 View Code Duplication
        if ($this->_cache_on && $cache && ! $load_only) {
712
            // return object if it's already cached
713
            $cached_class = $this->_get_cached_class($class_name, $class_prefix);
714
            if ($cached_class !== null) {
715
                return $cached_class;
716
            }
717
        }
718
        // if the class doesn't already exist.. then we need to try and find the file and load it
719
        if ( ! $class_exists) {
720
            // get full path to file
721
            $path = $this->_resolve_path($class_name, $type, $file_paths);
722
            // load the file
723
            $loaded = $this->_require_file($path, $class_name, $type, $file_paths);
724
            // if loading failed, or we are only loading a file but NOT instantiating an object
725
            if ( ! $loaded || $load_only) {
726
                // return boolean if only loading, or null if an object was expected
727
                return $load_only ? $loaded : null;
728
            }
729
        }
730
        // instantiate the requested object
731
        $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $class_obj is correct as $this->_create_object($c...ments, $type, $from_db) (which targets EE_Registry::_create_object()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
732
        if ($this->_cache_on && $cache) {
733
            // save it for later... kinda like gum  { : $
734
            $this->_set_cached_class($class_obj, $class_name, $class_prefix, $from_db);
735
        }
736
        $this->_cache_on = true;
737
        return $class_obj;
738
    }
739
740
741
742
743
    /**
744
     * _get_cached_class
745
     * attempts to find a cached version of the requested class
746
     * by looking in the following places:
747
     *        $this->{$class_abbreviation}            ie:    $this->CART
748
     *        $this->{$class_name}                        ie:    $this->Some_Class
749
     *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
750
     *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
751
     *
752
     * @access protected
753
     * @param string $class_name
754
     * @param string $class_prefix
755
     * @return mixed
756
     */
757
    protected function _get_cached_class($class_name, $class_prefix = '')
758
    {
759
        if ($class_name === 'EE_Registry') {
760
            return $this;
761
        }
762
        // have to specify something, but not anything that will conflict
763
        $class_abbreviation = isset($this->_class_abbreviations[ $class_name ])
764
            ? $this->_class_abbreviations[ $class_name ]
765
            : 'FANCY_BATMAN_PANTS';
766
        $class_name = str_replace('\\', '_', $class_name);
767
        // check if class has already been loaded, and return it if it has been
768 View Code Duplication
        if (isset($this->{$class_abbreviation}) && ! is_null($this->{$class_abbreviation})) {
769
            return $this->{$class_abbreviation};
770
        }
771
        if (isset ($this->{$class_name})) {
772
            return $this->{$class_name};
773
        }
774
        if (isset ($this->LIB->{$class_name})) {
775
            return $this->LIB->{$class_name};
776
        }
777
        if ($class_prefix === 'addon' && isset ($this->addons->{$class_name})) {
778
            return $this->addons->{$class_name};
779
        }
780
        return null;
781
    }
782
783
784
785
    /**
786
     * removes a cached version of the requested class
787
     *
788
     * @param string $class_name
789
     * @param boolean $addon
790
     * @return boolean
791
     */
792
    public function clear_cached_class($class_name, $addon = false)
793
    {
794
        // have to specify something, but not anything that will conflict
795
        $class_abbreviation = isset($this->_class_abbreviations[ $class_name ])
796
            ? $this->_class_abbreviations[ $class_name ]
797
            : 'FANCY_BATMAN_PANTS';
798
        $class_name = str_replace('\\', '_', $class_name);
799
        // check if class has already been loaded, and return it if it has been
800 View Code Duplication
        if (isset($this->{$class_abbreviation}) && ! is_null($this->{$class_abbreviation})) {
801
            $this->{$class_abbreviation} = null;
802
            return true;
803
        }
804
        if (isset($this->{$class_name})) {
805
            $this->{$class_name} = null;
806
            return true;
807
        }
808
        if (isset($this->LIB->{$class_name})) {
809
            unset($this->LIB->{$class_name});
810
            return true;
811
        }
812
        if ($addon && isset($this->addons->{$class_name})) {
813
            unset($this->addons->{$class_name});
814
            return true;
815
        }
816
        return false;
817
    }
818
819
820
    /**
821
     * _resolve_path
822
     * attempts to find a full valid filepath for the requested class.
823
     * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
824
     * then returns that path if the target file has been found and is readable
825
     *
826
     * @access protected
827
     * @param string $class_name
828
     * @param string $type
829
     * @param array  $file_paths
830
     * @return string | bool
831
     */
832
    protected function _resolve_path($class_name, $type = '', $file_paths = array())
833
    {
834
        // make sure $file_paths is an array
835
        $file_paths = is_array($file_paths) ? $file_paths : array($file_paths);
836
        // cycle thru paths
837
        foreach ($file_paths as $key => $file_path) {
838
            // convert all separators to proper DS, if no filepath, then use EE_CLASSES
839
            $file_path = $file_path ? str_replace(array('/', '\\'), DS, $file_path) : EE_CLASSES;
840
            // prep file type
841
            $type = ! empty($type) ? trim($type, '.') . '.' : '';
842
            // build full file path
843
            $file_paths[$key] = rtrim($file_path, DS) . DS . $class_name . '.' . $type . 'php';
844
            //does the file exist and can be read ?
845
            if (is_readable($file_paths[$key])) {
846
                return $file_paths[$key];
847
            }
848
        }
849
        return false;
850
    }
851
852
853
854
    /**
855
     * _require_file
856
     * basically just performs a require_once()
857
     * but with some error handling
858
     *
859
     * @access protected
860
     * @param  string $path
861
     * @param  string $class_name
862
     * @param  string $type
863
     * @param  array  $file_paths
864
     * @return boolean
865
     * @throws \EE_Error
866
     */
867
    protected function _require_file($path, $class_name, $type = '', $file_paths = array())
868
    {
869
        // don't give up! you gotta...
870
        try {
871
            //does the file exist and can it be read ?
872 View Code Duplication
            if ( ! $path) {
873
                // so sorry, can't find the file
874
                throw new EE_Error (
875
                    sprintf(
876
                        __('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', 'event_espresso'),
877
                        trim($type, '.'),
878
                        $class_name,
879
                        '<br />' . implode(',<br />', $file_paths)
880
                    )
881
                );
882
            }
883
            // get the file
884
            require_once($path);
885
            // if the class isn't already declared somewhere
886 View Code Duplication
            if (class_exists($class_name, false) === false) {
887
                // so sorry, not a class
888
                throw new EE_Error(
889
                    sprintf(
890
                        __('The %s file %s does not appear to contain the %s Class.', 'event_espresso'),
891
                        $type,
892
                        $path,
893
                        $class_name
894
                    )
895
                );
896
            }
897
        } catch (EE_Error $e) {
898
            $e->get_error();
899
            return false;
900
        }
901
        return true;
902
    }
903
904
905
906
    /**
907
     * _create_object
908
     * Attempts to instantiate the requested class via any of the
909
     * commonly used instantiation methods employed throughout EE.
910
     * The priority for instantiation is as follows:
911
     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
912
     *        - model objects via their 'new_instance_from_db' method
913
     *        - model objects via their 'new_instance' method
914
     *        - "singleton" classes" via their 'instance' method
915
     *    - standard instantiable classes via their __constructor
916
     * Prior to instantiation, if the classname exists in the dependency_map,
917
     * then the constructor for the requested class will be examined to determine
918
     * if any dependencies exist, and if they can be injected.
919
     * If so, then those classes will be added to the array of arguments passed to the constructor
920
     *
921
     * @access protected
922
     * @param string $class_name
923
     * @param array  $arguments
924
     * @param string $type
925
     * @param bool   $from_db
926
     * @return null | object
927
     * @throws \EE_Error
928
     */
929
    protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
930
    {
931
        $class_obj = null;
932
        $instantiation_mode = '0) none';
933
        // don't give up! you gotta...
934
        try {
935
            // create reflection
936
            $reflector = $this->get_ReflectionClass($class_name);
937
            // make sure arguments are an array
938
            $arguments = is_array($arguments) ? $arguments : array($arguments);
939
            // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
940
            // else wrap it in an additional array so that it doesn't get split into multiple parameters
941
            $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
942
                ? $arguments
943
                : array($arguments);
944
            // attempt to inject dependencies ?
945
            if ($this->_dependency_map->has($class_name)) {
946
                $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
947
            }
948
            // instantiate the class if possible
949
            if ($reflector->isAbstract()) {
950
                // nothing to instantiate, loading file was enough
951
                // does not throw an exception so $instantiation_mode is unused
952
                // $instantiation_mode = "1) no constructor abstract class";
953
                $class_obj = true;
954
            } else if ($reflector->getConstructor() === null && $reflector->isInstantiable() && empty($arguments)) {
955
                // no constructor = static methods only... nothing to instantiate, loading file was enough
956
                $instantiation_mode = "2) no constructor but instantiable";
957
                $class_obj = $reflector->newInstance();
958
            } else if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
959
                $instantiation_mode = "3) new_instance_from_db()";
960
                $class_obj = call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
961
            } else if (method_exists($class_name, 'new_instance')) {
962
                $instantiation_mode = "4) new_instance()";
963
                $class_obj = call_user_func_array(array($class_name, 'new_instance'), $arguments);
964
            } else if (method_exists($class_name, 'instance')) {
965
                $instantiation_mode = "5) instance()";
966
                $class_obj = call_user_func_array(array($class_name, 'instance'), $arguments);
967
            } else if ($reflector->isInstantiable()) {
968
                $instantiation_mode = "6) constructor";
969
                $class_obj = $reflector->newInstanceArgs($arguments);
970
            } else {
971
                // heh ? something's not right !
972
                throw new EE_Error(
973
                    sprintf(
974
                        __('The %s file %s could not be instantiated.', 'event_espresso'),
975
                        $type,
976
                        $class_name
977
                    )
978
                );
979
            }
980
        } catch (Exception $e) {
981
            if ( ! $e instanceof EE_Error) {
982
                $e = new EE_Error(
983
                    sprintf(
984
                        __('The following error occurred while attempting to instantiate "%1$s": %2$s %3$s %2$s instantiation mode : %4$s', 'event_espresso'),
985
                        $class_name,
986
                        '<br />',
987
                        $e->getMessage(),
988
                        $instantiation_mode
989
                    )
990
                );
991
            }
992
            $e->get_error();
993
        }
994
        return $class_obj;
995
    }
996
997
998
999
    /**
1000
     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1001
     * @param array $array
1002
     * @return bool
1003
     */
1004
    protected function _array_is_numerically_and_sequentially_indexed(array $array)
1005
    {
1006
        return ! empty($array) ? array_keys($array) === range(0, count($array) - 1) : true;
1007
    }
1008
1009
1010
1011
    /**
1012
     * getReflectionClass
1013
     * checks if a ReflectionClass object has already been generated for a class
1014
     * and returns that instead of creating a new one
1015
     *
1016
     * @access public
1017
     * @param string $class_name
1018
     * @return ReflectionClass
1019
     */
1020 View Code Duplication
    public function get_ReflectionClass($class_name)
1021
    {
1022
        if (
1023
            ! isset($this->_reflectors[$class_name])
1024
            || ! $this->_reflectors[$class_name] instanceof ReflectionClass
1025
        ) {
1026
            $this->_reflectors[$class_name] = new ReflectionClass($class_name);
1027
        }
1028
        return $this->_reflectors[$class_name];
1029
    }
1030
1031
1032
1033
    /**
1034
     * _resolve_dependencies
1035
     * examines the constructor for the requested class to determine
1036
     * if any dependencies exist, and if they can be injected.
1037
     * If so, then those classes will be added to the array of arguments passed to the constructor
1038
     * PLZ NOTE: this is achieved by type hinting the constructor params
1039
     * For example:
1040
     *        if attempting to load a class "Foo" with the following constructor:
1041
     *        __construct( Bar $bar_class, Fighter $grohl_class )
1042
     *        then $bar_class and $grohl_class will be added to the $arguments array,
1043
     *        but only IF they are NOT already present in the incoming arguments array,
1044
     *        and the correct classes can be loaded
1045
     *
1046
     * @access protected
1047
     * @param ReflectionClass $reflector
1048
     * @param string          $class_name
1049
     * @param array           $arguments
1050
     * @return array
1051
     * @throws \ReflectionException
1052
     */
1053
    protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, $arguments = array())
1054
    {
1055
        // let's examine the constructor
1056
        $constructor = $reflector->getConstructor();
1057
        // whu? huh? nothing?
1058
        if ( ! $constructor) {
1059
            return $arguments;
1060
        }
1061
        // get constructor parameters
1062
        $params = $constructor->getParameters();
1063
        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1064
        $argument_keys = array_keys($arguments);
1065
        // now loop thru all of the constructors expected parameters
1066
        foreach ($params as $index => $param) {
1067
            // is this a dependency for a specific class ?
1068
            $param_class = $param->getClass() ? $param->getClass()->name : null;
1069
            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1070
            $param_class = $this->_dependency_map->has_alias($param_class, $class_name)
1071
                ? $this->_dependency_map->get_alias($param_class, $class_name)
1072
                : $param_class;
1073
            if (
1074
                // param is not even a class
1075
                empty($param_class)
1076
                // and something already exists in the incoming arguments for this param
1077
                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1078
            ) {
1079
                // so let's skip this argument and move on to the next
1080
                continue;
1081
            }
1082
            if (
1083
                // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1084
                ! empty($param_class)
1085
                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1086
                && $arguments[$argument_keys[$index]] instanceof $param_class
1087
            ) {
1088
                // skip this argument and move on to the next
1089
                continue;
1090
            }
1091
            if (
1092
                // parameter is type hinted as a class, and should be injected
1093
                ! empty($param_class)
1094
                && $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1095
            ) {
1096
                $arguments = $this->_resolve_dependency($class_name, $param_class, $arguments, $index);
1097
            } else {
1098
                try {
1099
                    $arguments[$index] = $param->getDefaultValue();
1100
                } catch (ReflectionException $e) {
1101
                    throw new ReflectionException(
1102
                        sprintf(
1103
                            __('%1$s for parameter "$%2$s"', 'event_espresso'),
1104
                            $e->getMessage(),
1105
                            $param->getName()
1106
                        )
1107
                    );
1108
                }
1109
            }
1110
        }
1111
        return $arguments;
1112
    }
1113
1114
1115
1116
    /**
1117
     * @access protected
1118
     * @param string $class_name
1119
     * @param string $param_class
1120
     * @param array  $arguments
1121
     * @param mixed  $index
1122
     * @return array
1123
     */
1124
    protected function _resolve_dependency($class_name, $param_class, $arguments, $index)
1125
    {
1126
        $dependency = null;
1127
        // should dependency be loaded from cache ?
1128
        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency($class_name, $param_class)
1129
                    !== EE_Dependency_Map::load_new_object
1130
            ? true
1131
            : false;
1132
        // we might have a dependency...
1133
        // let's MAYBE try and find it in our cache if that's what's been requested
1134
        $cached_class = $cache_on ? $this->_get_cached_class($param_class) : null;
1135
        // and grab it if it exists
1136
        if ($cached_class instanceof $param_class) {
1137
            $dependency = $cached_class;
1138
        } else if ($param_class !== $class_name) {
1139
            // obtain the loader method from the dependency map
1140
            $loader = $this->_dependency_map->class_loader($param_class);
1141
            // is loader a custom closure ?
1142
            if ($loader instanceof Closure) {
1143
                $dependency = $loader();
1144
            } else {
1145
                // set the cache on property for the recursive loading call
1146
                $this->_cache_on = $cache_on;
1147
                // if not, then let's try and load it via the registry
1148
                if ($loader && method_exists($this, $loader)) {
1149
                    $dependency = $this->{$loader}($param_class);
1150
                } else {
1151
                    $dependency = $this->create($param_class, array(), $cache_on);
1152
                }
1153
            }
1154
        }
1155
        // did we successfully find the correct dependency ?
1156
        if ($dependency instanceof $param_class) {
1157
            // then let's inject it into the incoming array of arguments at the correct location
1158
            if (isset($argument_keys[$index])) {
0 ignored issues
show
Bug introduced by
The variable $argument_keys seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
1159
                $arguments[$argument_keys[$index]] = $dependency;
1160
            } else {
1161
                $arguments[$index] = $dependency;
1162
            }
1163
        }
1164
        return $arguments;
1165
    }
1166
1167
1168
1169
    /**
1170
     * _set_cached_class
1171
     * attempts to cache the instantiated class locally
1172
     * in one of the following places, in the following order:
1173
     *        $this->{class_abbreviation}   ie:    $this->CART
1174
     *        $this->{$class_name}          ie:    $this->Some_Class
1175
     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1176
     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1177
     *
1178
     * @access protected
1179
     * @param object $class_obj
1180
     * @param string $class_name
1181
     * @param string $class_prefix
1182
     * @param bool   $from_db
1183
     * @return void
1184
     */
1185
    protected function _set_cached_class($class_obj, $class_name, $class_prefix = '', $from_db = false)
1186
    {
1187
        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1188
            return;
1189
        }
1190
        // return newly instantiated class
1191
        if (isset($this->_class_abbreviations[$class_name])) {
1192
            $class_abbreviation = $this->_class_abbreviations[$class_name];
1193
            $this->{$class_abbreviation} = $class_obj;
1194
            return;
1195
        }
1196
        $class_name = str_replace('\\', '_', $class_name);
1197
        if (property_exists($this, $class_name)) {
1198
            $this->{$class_name} = $class_obj;
1199
            return;
1200
        }
1201
        if ($class_prefix === 'addon') {
1202
            $this->addons->{$class_name} = $class_obj;
1203
            return;
1204
        }
1205
        if ( ! $from_db) {
1206
            $this->LIB->{$class_name} = $class_obj;
1207
        }
1208
    }
1209
1210
1211
1212
    /**
1213
     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1214
     *
1215
     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1216
     *                          in the EE_Dependency_Map::$_class_loaders array,
1217
     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1218
     * @param array  $arguments
1219
     * @return object
1220
     */
1221
    public static function factory($classname, $arguments = array())
1222
    {
1223
        $loader = self::instance()->_dependency_map->class_loader($classname);
1224
        if ($loader instanceof Closure) {
1225
            return $loader($arguments);
1226
        }
1227
        if (method_exists(EE_Registry::instance(), $loader)) {
1228
            return EE_Registry::instance()->{$loader}($classname, $arguments);
1229
        }
1230
        return null;
1231
    }
1232
1233
1234
1235
    /**
1236
     * Gets the addon by its name/slug (not classname. For that, just
1237
     * use the classname as the property name on EE_Config::instance()->addons)
1238
     *
1239
     * @param string $name
1240
     * @return EE_Addon
1241
     */
1242
    public function get_addon_by_name($name)
1243
    {
1244
        foreach ($this->addons as $addon) {
1245
            if ($addon->name() == $name) {
1246
                return $addon;
1247
            }
1248
        }
1249
        return null;
1250
    }
1251
1252
1253
1254
    /**
1255
     * Gets an array of all the registered addons, where the keys are their names. (ie, what each returns for their name() function) They're already available on EE_Config::instance()->addons as properties, where each property's name is
1256
     * the addon's classname. So if you just want to get the addon by classname, use EE_Config::instance()->addons->{classname}
1257
     *
1258
     * @return EE_Addon[] where the KEYS are the addon's name()
1259
     */
1260
    public function get_addons_by_name()
1261
    {
1262
        $addons = array();
1263
        foreach ($this->addons as $addon) {
1264
            $addons[$addon->name()] = $addon;
1265
        }
1266
        return $addons;
1267
    }
1268
1269
1270
1271
    /**
1272
     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1273
     * a stale copy of it around
1274
     *
1275
     * @param string $model_name
1276
     * @return \EEM_Base
1277
     * @throws \EE_Error
1278
     */
1279
    public function reset_model($model_name)
1280
    {
1281
        $model_class_name = strpos($model_name, 'EEM_') !== 0 ? "EEM_{$model_name}" : $model_name;
1282
        if ( ! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1283
            return null;
1284
        }
1285
        //get that model reset it and make sure we nuke the old reference to it
1286
        if ($this->LIB->{$model_class_name} instanceof $model_class_name && is_callable(array($model_class_name, 'reset'))) {
1287
            $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1288
        } else {
1289
            throw new EE_Error(sprintf(__('Model %s does not have a method "reset"', 'event_espresso'), $model_name));
1290
        }
1291
        return $this->LIB->{$model_class_name};
1292
    }
1293
1294
1295
1296
    /**
1297
     * Resets the registry.
1298
     * The criteria for what gets reset is based on what can be shared between sites on the same request when switch_to_blog
1299
     * is used in a multisite install.  Here is a list of things that are NOT reset.
1300
     * - $_dependency_map
1301
     * - $_class_abbreviations
1302
     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1303
     * - $REQ:  Still on the same request so no need to change.
1304
     * - $CAP: There is no site specific state in the EE_Capability class.
1305
     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only one Session
1306
     *         can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1307
     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1308
     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1309
     *             switch or on the restore.
1310
     * - $modules
1311
     * - $shortcodes
1312
     * - $widgets
1313
     *
1314
     * @param boolean $hard             whether to reset data in the database too, or just refresh
1315
     *                                  the Registry to its state at the beginning of the request
1316
     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1317
     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not sure if you CAN
1318
     *                                  currently reinstantiate the singletons at the moment)
1319
     * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so client
1320
     *                                  code instead can just change the model context to a different blog id if necessary
1321
     * @return EE_Registry
1322
     */
1323
    public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1324
    {
1325
        $instance = self::instance();
1326
        $instance->_cache_on = true;
1327
        // reset some "special" classes
1328
        EEH_Activation::reset();
1329
        $instance->CFG = $instance->CFG->reset($hard, $reinstantiate);
1330
        $instance->CART = null;
1331
        $instance->MRM = null;
1332
        $instance->AssetsRegistry = null;
1333
        $instance->AssetsRegistry = $instance->create('EventEspresso\core\services\assets\Registry');
1334
        //messages reset
1335
        EED_Messages::reset();
1336
        //handle of objects cached on LIB
1337
        foreach (array('LIB', 'modules', 'shortcodes') as $cache) {
1338
            foreach ($instance->{$cache} as $class_name => $class) {
1339
                if (EE_Registry::_reset_and_unset_object($class, $reset_models)) {
1340
                    unset($instance->{$cache}->{$class_name});
1341
                }
1342
            }
1343
        }
1344
        return $instance;
1345
    }
1346
1347
1348
1349
    /**
1350
     * if passed object implements ResettableInterface, then call it's reset() method
1351
     * if passed object implements InterminableInterface, then return false,
1352
     * to indicate that it should NOT be cleared from the Registry cache
1353
     *
1354
     * @param      $object
1355
     * @param bool $reset_models
1356
     * @return bool returns true if cached object should be unset
1357
     */
1358
    private static function _reset_and_unset_object($object, $reset_models)
1359
    {
1360
        static $count = 0;
1361
        $count++;
1362
        if ($object instanceof ResettableInterface) {
1363
            if ($object instanceof EEM_Base) {
1364
                if ($reset_models) {
1365
                    $object->reset();
1366
                    return true;
1367
                }
1368
                return false;
1369
            }
1370
            $object->reset();
1371
            return true;
1372
        }
1373
        if ( ! $object instanceof InterminableInterface) {
1374
            return true;
1375
        }
1376
        return false;
1377
    }
1378
1379
1380
1381
    /**
1382
     * @override magic methods
1383
     * @return void
1384
     */
1385
    public final function __destruct()
1386
    {
1387
    }
1388
1389
1390
1391
    /**
1392
     * @param $a
1393
     * @param $b
1394
     */
1395
    public final function __call($a, $b)
1396
    {
1397
    }
1398
1399
1400
1401
    /**
1402
     * @param $a
1403
     */
1404
    public final function __get($a)
1405
    {
1406
    }
1407
1408
1409
1410
    /**
1411
     * @param $a
1412
     * @param $b
1413
     */
1414
    public final function __set($a, $b)
1415
    {
1416
    }
1417
1418
1419
1420
    /**
1421
     * @param $a
1422
     */
1423
    public final function __isset($a)
1424
    {
1425
    }
1426
1427
1428
1429
    /**
1430
     * @param $a
1431
     */
1432
    public final function __unset($a)
1433
    {
1434
    }
1435
1436
1437
1438
    /**
1439
     * @return array
1440
     */
1441
    public final function __sleep()
1442
    {
1443
        return array();
1444
    }
1445
1446
1447
1448
    public final function __wakeup()
1449
    {
1450
    }
1451
1452
1453
1454
    /**
1455
     * @return string
1456
     */
1457
    public final function __toString()
1458
    {
1459
        return '';
1460
    }
1461
1462
1463
1464
    public final function __invoke()
1465
    {
1466
    }
1467
1468
1469
1470
    public final static function __set_state($array = array())
1471
    {
1472
        return EE_Registry::instance();
1473
    }
1474
1475
1476
1477
    public final function __clone()
1478
    {
1479
    }
1480
1481
1482
1483
    /**
1484
     * @param $a
1485
     * @param $b
1486
     */
1487
    public final static function __callStatic($a, $b)
1488
    {
1489
    }
1490
1491
1492
1493
    /**
1494
     * Gets all the custom post type models defined
1495
     *
1496
     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1497
     */
1498
    public function cpt_models()
1499
    {
1500
        $cpt_models = array();
1501
        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1502
            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1503
                $cpt_models[$short_name] = $classname;
1504
            }
1505
        }
1506
        return $cpt_models;
1507
    }
1508
1509
1510
1511
    /**
1512
     * @return \EE_Config
1513
     */
1514
    public static function CFG()
1515
    {
1516
        return self::instance()->CFG;
1517
    }
1518
1519
1520
}
1521
// End of file EE_Registry.core.php
1522
// Location: ./core/EE_Registry.core.php
1523