Completed
Branch FET/11450/reserved-instance-in... (7eae78)
by
unknown
39:56 queued 27:31
created

EE_Registry::_load()   C

Complexity

Conditions 14
Paths 28

Size

Total Lines 67
Code Lines 39

Duplication

Lines 7
Ratio 10.45 %

Importance

Changes 0
Metric Value
cc 14
eloc 39
nc 28
nop 8
dl 7
loc 67
rs 5.8135
c 0
b 0
f 0

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