Completed
Branch FET/asset-manager (018c4e)
by
unknown
87:46 queued 74:14
created

EE_Registry::_load()   C

Complexity

Conditions 15
Paths 54

Size

Total Lines 68
Code Lines 40

Duplication

Lines 7
Ratio 10.29 %

Importance

Changes 0
Metric Value
cc 15
eloc 40
nc 54
nop 8
dl 7
loc 68
rs 5.7335
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
        $arguments = is_array($arguments) ? $arguments : array($arguments);
878
        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
879
        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
880
        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
881 View Code Duplication
        if ($this->_cache_on && $cache && ! $load_only) {
882
            // return object if it's already cached
883
            $cached_class = $this->_get_cached_class($class_name, $class_prefix, $arguments);
884
            if ($cached_class !== null) {
885
                return $cached_class;
886
            }
887
        }
888
        // if the class doesn't already exist.. then we need to try and find the file and load it
889
        if (! $class_exists) {
890
            // get full path to file
891
            $path = $this->_resolve_path($class_name, $type, $file_paths);
892
            // load the file
893
            $loaded = $this->_require_file($path, $class_name, $type, $file_paths);
894
            // if we are only loading a file but NOT instantiating an object
895
            // then return boolean for whether class was loaded or not
896
            if ($load_only) {
897
                return $loaded;
898
            }
899
            // if an object was expected but loading failed, then return nothing
900
            if (! $loaded) {
901
                return null;
902
            }
903
        }
904
        // instantiate the requested object
905
        $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
906
        if ($this->_cache_on && $cache) {
907
            // save it for later... kinda like gum  { : $
908
            $this->_set_cached_class(
909
                $class_obj,
910
                $class_name,
911
                $class_prefix,
912
                $from_db,
913
                $arguments
914
            );
915
        }
916
        $this->_cache_on = true;
917
        return $class_obj;
918
    }
919
920
921
    /**
922
     * @param string $class_name
923
     * @param string $default have to specify something, but not anything that will conflict
924
     * @return mixed|string
925
     */
926
    protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS')
927
    {
928
        return isset($this->_class_abbreviations[ $class_name ])
929
            ? $this->_class_abbreviations[ $class_name ]
930
            : $default;
931
    }
932
933
934
    /**
935
     * attempts to find a cached version of the requested class
936
     * by looking in the following places:
937
     *        $this->{$class_abbreviation}            ie:    $this->CART
938
     *        $this->{$class_name}                        ie:    $this->Some_Class
939
     *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
940
     *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
941
     *
942
     * @param string $class_name
943
     * @param string $class_prefix
944
     * @param array  $arguments
945
     * @return mixed
946
     */
947
    protected function _get_cached_class(
948
        $class_name,
949
        $class_prefix = '',
950
        $arguments = array()
951
    ) {
952
        if ($class_name === 'EE_Registry') {
953
            return $this;
954
        }
955
        $class_abbreviation = $this->get_class_abbreviation($class_name);
956
        // check if class has already been loaded, and return it if it has been
957
        if (isset($this->{$class_abbreviation})) {
958
            return $this->{$class_abbreviation};
959
        }
960
        $class_name = str_replace('\\', '_', $class_name);
961
        if (isset ($this->{$class_name})) {
962
            return $this->{$class_name};
963
        }
964
        if ($class_prefix === 'addon' && isset ($this->addons->{$class_name})) {
965
            return $this->addons->{$class_name};
966
        }
967
        $object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments);
968
        if (isset($this->LIB->{$object_identifier})) {
969
            return $this->LIB->{$object_identifier};
970
        }
971
        foreach ($this->LIB as $key => $object) {
972
            if (
973
                // request does not contain new arguments and therefore no args identifier
974
                ! $this->object_identifier->hasArguments($object_identifier)
975
                // but previously cached class with args was found
976
                && $this->object_identifier->fqcnMatchesObjectIdentifier($class_name, $key)
977
            ) {
978
                return $object;
979
            }
980
        }
981
        return null;
982
    }
983
984
985
    /**
986
     * removes a cached version of the requested class
987
     *
988
     * @param string  $class_name
989
     * @param boolean $addon
990
     * @param array   $arguments
991
     * @return boolean
992
     */
993
    public function clear_cached_class(
994
        $class_name,
995
        $addon = false,
996
        $arguments = array()
997
    ) {
998
        $class_abbreviation = $this->get_class_abbreviation($class_name);
999
        // check if class has already been loaded, and return it if it has been
1000
        if (isset($this->{$class_abbreviation})) {
1001
            $this->{$class_abbreviation} = null;
1002
            return true;
1003
        }
1004
        $class_name = str_replace('\\', '_', $class_name);
1005
        if (isset($this->{$class_name})) {
1006
            $this->{$class_name} = null;
1007
            return true;
1008
        }
1009
        if ($addon && isset($this->addons->{$class_name})) {
1010
            unset($this->addons->{$class_name});
1011
            return true;
1012
        }
1013
        $class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1014
        if (isset($this->LIB->{$class_name})) {
1015
            unset($this->LIB->{$class_name});
1016
            return true;
1017
        }
1018
        return false;
1019
    }
1020
1021
1022
    /**
1023
     * _set_cached_class
1024
     * attempts to cache the instantiated class locally
1025
     * in one of the following places, in the following order:
1026
     *        $this->{class_abbreviation}   ie:    $this->CART
1027
     *        $this->{$class_name}          ie:    $this->Some_Class
1028
     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1029
     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1030
     *
1031
     * @param object $class_obj
1032
     * @param string $class_name
1033
     * @param string $class_prefix
1034
     * @param bool   $from_db
1035
     * @param array  $arguments
1036
     * @return void
1037
     */
1038
    protected function _set_cached_class(
1039
        $class_obj,
1040
        $class_name,
1041
        $class_prefix = '',
1042
        $from_db = false,
1043
        $arguments = array()
1044
    ) {
1045
        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1046
            return;
1047
        }
1048
        // return newly instantiated class
1049
        $class_abbreviation = $this->get_class_abbreviation($class_name, '');
1050
        if ($class_abbreviation) {
1051
            $this->{$class_abbreviation} = $class_obj;
1052
            return;
1053
        }
1054
        $class_name = str_replace('\\', '_', $class_name);
1055
        if (property_exists($this, $class_name)) {
1056
            $this->{$class_name} = $class_obj;
1057
            return;
1058
        }
1059
        if ($class_prefix === 'addon') {
1060
            $this->addons->{$class_name} = $class_obj;
1061
            return;
1062
        }
1063
        if (! $from_db) {
1064
            $class_name               = $this->object_identifier->getIdentifier($class_name, $arguments);
1065
            $this->LIB->{$class_name} = $class_obj;
1066
        }
1067
    }
1068
1069
1070
    /**
1071
     * attempts to find a full valid filepath for the requested class.
1072
     * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
1073
     * then returns that path if the target file has been found and is readable
1074
     *
1075
     * @param string $class_name
1076
     * @param string $type
1077
     * @param array  $file_paths
1078
     * @return string | bool
1079
     */
1080
    protected function _resolve_path($class_name, $type = '', $file_paths = array())
1081
    {
1082
        // make sure $file_paths is an array
1083
        $file_paths = is_array($file_paths)
1084
            ? $file_paths
1085
            : array($file_paths);
1086
        // cycle thru paths
1087
        foreach ($file_paths as $key => $file_path) {
1088
            // convert all separators to proper DS, if no filepath, then use EE_CLASSES
1089
            $file_path = $file_path
1090
                ? str_replace(array('/', '\\'), DS, $file_path)
1091
                : EE_CLASSES;
1092
            // prep file type
1093
            $type = ! empty($type)
1094
                ? trim($type, '.') . '.'
1095
                : '';
1096
            // build full file path
1097
            $file_paths[ $key ] = rtrim($file_path, DS) . DS . $class_name . '.' . $type . 'php';
1098
            //does the file exist and can be read ?
1099
            if (is_readable($file_paths[ $key ])) {
1100
                return $file_paths[ $key ];
1101
            }
1102
        }
1103
        return false;
1104
    }
1105
1106
1107
    /**
1108
     * basically just performs a require_once()
1109
     * but with some error handling
1110
     *
1111
     * @param  string $path
1112
     * @param  string $class_name
1113
     * @param  string $type
1114
     * @param  array  $file_paths
1115
     * @return bool
1116
     * @throws EE_Error
1117
     * @throws ReflectionException
1118
     */
1119
    protected function _require_file($path, $class_name, $type = '', $file_paths = array())
1120
    {
1121
        $this->resolve_legacy_class_parent($class_name);
1122
        // don't give up! you gotta...
1123
        try {
1124
            //does the file exist and can it be read ?
1125
            if (! $path) {
1126
                // just in case the file has already been autoloaded,
1127
                // but discrepancies in the naming schema are preventing it from
1128
                // being loaded via one of the EE_Registry::load_*() methods,
1129
                // then let's try one last hail mary before throwing an exception
1130
                // and call class_exists() again, but with autoloading turned ON
1131
                if (class_exists($class_name)) {
1132
                    return true;
1133
                }
1134
                // so sorry, can't find the file
1135
                throw new EE_Error (
1136
                    sprintf(
1137
                        esc_html__(
1138
                            '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',
1139
                            'event_espresso'
1140
                        ),
1141
                        trim($type, '.'),
1142
                        $class_name,
1143
                        '<br />' . implode(',<br />', $file_paths)
1144
                    )
1145
                );
1146
            }
1147
            // get the file
1148
            require_once($path);
1149
            // if the class isn't already declared somewhere
1150
            if (class_exists($class_name, false) === false) {
1151
                // so sorry, not a class
1152
                throw new EE_Error(
1153
                    sprintf(
1154
                        esc_html__(
1155
                            'The %s file %s does not appear to contain the %s Class.',
1156
                            'event_espresso'
1157
                        ),
1158
                        $type,
1159
                        $path,
1160
                        $class_name
1161
                    )
1162
                );
1163
            }
1164
        } catch (EE_Error $e) {
1165
            $e->get_error();
1166
            return false;
1167
        }
1168
        return true;
1169
    }
1170
1171
1172
    /**
1173
     * Some of our legacy classes that extended a parent class would simply use a require() statement
1174
     * before their class declaration in order to ensure that the parent class was loaded.
1175
     * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1176
     * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1177
     *
1178
     * @param string $class_name
1179
     */
1180
    protected function resolve_legacy_class_parent($class_name = '')
1181
    {
1182
        try {
1183
            $legacy_parent_class_map = array(
1184
                'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php',
1185
            );
1186
            if (isset($legacy_parent_class_map[ $class_name ])) {
1187
                require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ];
1188
            }
1189
        } catch (Exception $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1190
        }
1191
    }
1192
1193
1194
    /**
1195
     * _create_object
1196
     * Attempts to instantiate the requested class via any of the
1197
     * commonly used instantiation methods employed throughout EE.
1198
     * The priority for instantiation is as follows:
1199
     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1200
     *        - model objects via their 'new_instance_from_db' method
1201
     *        - model objects via their 'new_instance' method
1202
     *        - "singleton" classes" via their 'instance' method
1203
     *    - standard instantiable classes via their __constructor
1204
     * Prior to instantiation, if the classname exists in the dependency_map,
1205
     * then the constructor for the requested class will be examined to determine
1206
     * if any dependencies exist, and if they can be injected.
1207
     * If so, then those classes will be added to the array of arguments passed to the constructor
1208
     *
1209
     * @param string $class_name
1210
     * @param array  $arguments
1211
     * @param string $type
1212
     * @param bool   $from_db
1213
     * @return null|object|bool
1214
     * @throws InvalidArgumentException
1215
     * @throws InvalidInterfaceException
1216
     * @throws EE_Error
1217
     * @throws ReflectionException
1218
     * @throws InvalidDataTypeException
1219
     */
1220
    protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
1221
    {
1222
        // create reflection
1223
        $reflector = $this->mirror->getReflectionClass($class_name);
1224
        // make sure arguments are an array
1225
        $arguments = is_array($arguments)
1226
            ? $arguments
1227
            : array($arguments);
1228
        // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1229
        // else wrap it in an additional array so that it doesn't get split into multiple parameters
1230
        $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1231
            ? $arguments
1232
            : array($arguments);
1233
        // attempt to inject dependencies ?
1234
        if ($this->_dependency_map->has($class_name)) {
1235
            $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1236
        }
1237
        // instantiate the class if possible
1238
        if ($reflector->isAbstract()) {
1239
            // nothing to instantiate, loading file was enough
1240
            // does not throw an exception so $instantiation_mode is unused
1241
            // $instantiation_mode = "1) no constructor abstract class";
1242
            return true;
1243
        }
1244
        if (
1245
            empty($arguments)
1246
            && $this->mirror->getConstructorFromReflection($reflector) === null
1247
            && $reflector->isInstantiable()
1248
        ) {
1249
            // no constructor = static methods only... nothing to instantiate, loading file was enough
1250
            // $instantiation_mode = "2) no constructor but instantiable";
1251
            return $reflector->newInstance();
1252
        }
1253
        if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1254
            // $instantiation_mode = "3) new_instance_from_db()";
1255
            return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1256
        }
1257
        if (method_exists($class_name, 'new_instance')) {
1258
            // $instantiation_mode = "4) new_instance()";
1259
            return call_user_func_array(array($class_name, 'new_instance'), $arguments);
1260
        }
1261
        if (method_exists($class_name, 'instance')) {
1262
            // $instantiation_mode = "5) instance()";
1263
            return call_user_func_array(array($class_name, 'instance'), $arguments);
1264
        }
1265
        if ($reflector->isInstantiable()) {
1266
            // $instantiation_mode = "6) constructor";
1267
            return $reflector->newInstanceArgs($arguments);
1268
        }
1269
        // heh ? something's not right !
1270
        throw new EE_Error(
1271
            sprintf(
1272
                __('The %s file %s could not be instantiated.', 'event_espresso'),
1273
                $type,
1274
                $class_name
1275
            )
1276
        );
1277
    }
1278
1279
1280
    /**
1281
     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1282
     * @param array $array
1283
     * @return bool
1284
     */
1285
    protected function _array_is_numerically_and_sequentially_indexed(array $array)
1286
    {
1287
        return ! empty($array)
1288
            ? array_keys($array) === range(0, count($array) - 1)
1289
            : true;
1290
    }
1291
1292
1293
    /**
1294
     * _resolve_dependencies
1295
     * examines the constructor for the requested class to determine
1296
     * if any dependencies exist, and if they can be injected.
1297
     * If so, then those classes will be added to the array of arguments passed to the constructor
1298
     * PLZ NOTE: this is achieved by type hinting the constructor params
1299
     * For example:
1300
     *        if attempting to load a class "Foo" with the following constructor:
1301
     *        __construct( Bar $bar_class, Fighter $grohl_class )
1302
     *        then $bar_class and $grohl_class will be added to the $arguments array,
1303
     *        but only IF they are NOT already present in the incoming arguments array,
1304
     *        and the correct classes can be loaded
1305
     *
1306
     * @param ReflectionClass $reflector
1307
     * @param string          $class_name
1308
     * @param array           $arguments
1309
     * @return array
1310
     * @throws InvalidArgumentException
1311
     * @throws InvalidDataTypeException
1312
     * @throws InvalidInterfaceException
1313
     * @throws ReflectionException
1314
     */
1315
    protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, array $arguments = array())
1316
    {
1317
        // let's examine the constructor
1318
        $constructor = $this->mirror->getConstructorFromReflection($reflector);
1319
        // whu? huh? nothing?
1320
        if (! $constructor) {
1321
            return $arguments;
1322
        }
1323
        // get constructor parameters
1324
        $params = $this->mirror->getParametersFromReflection($reflector);
1325
        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1326
        $argument_keys = array_keys($arguments);
1327
        // now loop thru all of the constructors expected parameters
1328
        foreach ($params as $index => $param) {
1329
            // is this a dependency for a specific class ?
1330
            $param_class = $this->mirror->getParameterClassName($param, $class_name, $index);
1331
            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1332
            $param_class = $this->class_cache->isAlias($param_class, $class_name)
1333
                ? $this->class_cache->getFqnForAlias($param_class, $class_name)
1334
                : $param_class;
1335
            if (
1336
                // param is not even a class
1337
                $param_class === null
1338
                // and something already exists in the incoming arguments for this param
1339
                && array_key_exists($index, $argument_keys)
1340
                && array_key_exists($argument_keys[ $index ], $arguments)
1341
            ) {
1342
                // so let's skip this argument and move on to the next
1343
                continue;
1344
            }
1345
            if (
1346
                // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1347
                $param_class !== null
1348
                && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
1349
                && $arguments[ $argument_keys[ $index ] ] instanceof $param_class
1350
            ) {
1351
                // skip this argument and move on to the next
1352
                continue;
1353
            }
1354
            if (
1355
                // parameter is type hinted as a class, and should be injected
1356
                $param_class !== null
1357
                && $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1358
            ) {
1359
                $arguments = $this->_resolve_dependency(
1360
                    $class_name,
1361
                    $param_class,
1362
                    $arguments,
1363
                    $index
1364
                );
1365
            } else {
1366
                $arguments[ $index ] = $this->mirror->getParameterDefaultValue(
1367
                    $param,
1368
                    $class_name,
1369
                    $index
1370
                );
1371
            }
1372
        }
1373
        return $arguments;
1374
    }
1375
1376
1377
    /**
1378
     * @param string $class_name
1379
     * @param string $param_class
1380
     * @param array  $arguments
1381
     * @param mixed  $index
1382
     * @return array
1383
     * @throws InvalidArgumentException
1384
     * @throws InvalidInterfaceException
1385
     * @throws InvalidDataTypeException
1386
     */
1387
    protected function _resolve_dependency($class_name, $param_class, $arguments, $index)
1388
    {
1389
        $dependency = null;
1390
        // should dependency be loaded from cache ?
1391
        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1392
            $class_name,
1393
            $param_class
1394
        );
1395
        $cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1396
        // we might have a dependency...
1397
        // let's MAYBE try and find it in our cache if that's what's been requested
1398
        $cached_class = $cache_on
1399
            ? $this->_get_cached_class($param_class)
1400
            : null;
1401
        // and grab it if it exists
1402
        if ($cached_class instanceof $param_class) {
1403
            $dependency = $cached_class;
1404
        } elseif ($param_class !== $class_name) {
1405
            // obtain the loader method from the dependency map
1406
            $loader = $this->_dependency_map->class_loader($param_class);
1407
            // is loader a custom closure ?
1408
            if ($loader instanceof Closure) {
1409
                $dependency = $loader($arguments);
1410
            } else {
1411
                // set the cache on property for the recursive loading call
1412
                $this->_cache_on = $cache_on;
1413
                // if not, then let's try and load it via the registry
1414
                if ($loader && method_exists($this, $loader)) {
1415
                    $dependency = $this->{$loader}($param_class);
1416
                } else {
1417
                    $dependency = LoaderFactory::getLoader()->load(
1418
                        $param_class,
1419
                        array(),
1420
                        $cache_on
1421
                    );
1422
                }
1423
            }
1424
        }
1425
        // did we successfully find the correct dependency ?
1426
        if ($dependency instanceof $param_class) {
1427
            // then let's inject it into the incoming array of arguments at the correct location
1428
            $arguments[ $index ] = $dependency;
1429
        }
1430
        return $arguments;
1431
    }
1432
1433
1434
    /**
1435
     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1436
     *
1437
     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1438
     *                          in the EE_Dependency_Map::$_class_loaders array,
1439
     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1440
     * @param array  $arguments
1441
     * @return object
1442
     */
1443
    public static function factory($classname, $arguments = array())
1444
    {
1445
        $loader = self::instance()->_dependency_map->class_loader($classname);
1446
        if ($loader instanceof Closure) {
1447
            return $loader($arguments);
1448
        }
1449
        if (method_exists(self::instance(), $loader)) {
1450
            return self::instance()->{$loader}($classname, $arguments);
1451
        }
1452
        return null;
1453
    }
1454
1455
1456
    /**
1457
     * Gets the addon by its class name
1458
     *
1459
     * @param string $class_name
1460
     * @return EE_Addon
1461
     */
1462
    public function getAddon($class_name)
1463
    {
1464
        $class_name = str_replace('\\', '_', $class_name);
1465
        return $this->addons->{$class_name};
1466
    }
1467
1468
1469
    /**
1470
     * removes the addon from the internal cache
1471
     *
1472
     * @param string $class_name
1473
     * @return void
1474
     */
1475
    public function removeAddon($class_name)
1476
    {
1477
        $class_name = str_replace('\\', '_', $class_name);
1478
        unset($this->addons->{$class_name});
1479
    }
1480
1481
1482
    /**
1483
     * Gets the addon by its name/slug (not classname. For that, just
1484
     * use the get_addon() method above
1485
     *
1486
     * @param string $name
1487
     * @return EE_Addon
1488
     */
1489
    public function get_addon_by_name($name)
1490
    {
1491
        foreach ($this->addons as $addon) {
1492
            if ($addon->name() === $name) {
1493
                return $addon;
1494
            }
1495
        }
1496
        return null;
1497
    }
1498
1499
1500
    /**
1501
     * Gets an array of all the registered addons, where the keys are their names.
1502
     * (ie, what each returns for their name() function)
1503
     * They're already available on EE_Registry::instance()->addons as properties,
1504
     * where each property's name is the addon's classname,
1505
     * So if you just want to get the addon by classname,
1506
     * OR use the get_addon() method above.
1507
     * PLEASE  NOTE:
1508
     * addons with Fully Qualified Class Names
1509
     * have had the namespace separators converted to underscores,
1510
     * so a classname like Fully\Qualified\ClassName
1511
     * would have been converted to Fully_Qualified_ClassName
1512
     *
1513
     * @return EE_Addon[] where the KEYS are the addon's name()
1514
     */
1515
    public function get_addons_by_name()
1516
    {
1517
        $addons = array();
1518
        foreach ($this->addons as $addon) {
1519
            $addons[ $addon->name() ] = $addon;
1520
        }
1521
        return $addons;
1522
    }
1523
1524
1525
    /**
1526
     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1527
     * a stale copy of it around
1528
     *
1529
     * @param string $model_name
1530
     * @return \EEM_Base
1531
     * @throws \EE_Error
1532
     */
1533
    public function reset_model($model_name)
1534
    {
1535
        $model_class_name = strpos($model_name, 'EEM_') !== 0
1536
            ? "EEM_{$model_name}"
1537
            : $model_name;
1538
        if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1539
            return null;
1540
        }
1541
        //get that model reset it and make sure we nuke the old reference to it
1542
        if ($this->LIB->{$model_class_name} instanceof $model_class_name
1543
            && is_callable(
1544
                array($model_class_name, 'reset')
1545
            )) {
1546
            $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1547
        } else {
1548
            throw new EE_Error(
1549
                sprintf(
1550
                    esc_html__('Model %s does not have a method "reset"', 'event_espresso'),
1551
                    $model_name
1552
                )
1553
            );
1554
        }
1555
        return $this->LIB->{$model_class_name};
1556
    }
1557
1558
1559
    /**
1560
     * Resets the registry.
1561
     * The criteria for what gets reset is based on what can be shared between sites on the same request when
1562
     * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1563
     * - $_dependency_map
1564
     * - $_class_abbreviations
1565
     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1566
     * - $REQ:  Still on the same request so no need to change.
1567
     * - $CAP: There is no site specific state in the EE_Capability class.
1568
     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1569
     * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1570
     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1571
     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1572
     *             switch or on the restore.
1573
     * - $modules
1574
     * - $shortcodes
1575
     * - $widgets
1576
     *
1577
     * @param boolean $hard             [deprecated]
1578
     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1579
     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1580
     *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1581
     * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1582
     *                                  client
1583
     *                                  code instead can just change the model context to a different blog id if
1584
     *                                  necessary
1585
     * @return EE_Registry
1586
     * @throws InvalidInterfaceException
1587
     * @throws InvalidDataTypeException
1588
     * @throws EE_Error
1589
     * @throws ReflectionException
1590
     * @throws InvalidArgumentException
1591
     */
1592
    public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1593
    {
1594
        $instance            = self::instance();
1595
        $instance->_cache_on = true;
1596
        // reset some "special" classes
1597
        EEH_Activation::reset();
1598
        $hard                     = apply_filters('FHEE__EE_Registry__reset__hard', $hard);
1599
        $instance->CFG            = EE_Config::reset($hard, $reinstantiate);
1600
        $instance->CART           = null;
1601
        $instance->MRM            = null;
1602
        $instance->AssetsRegistry = LoaderFactory::getLoader()->getShared(
1603
            'EventEspresso\core\services\assets\Registry'
1604
        );
1605
        //messages reset
1606
        EED_Messages::reset();
1607
        //handle of objects cached on LIB
1608
        foreach (array('LIB', 'modules') as $cache) {
1609
            foreach ($instance->{$cache} as $class_name => $class) {
1610
                if (self::_reset_and_unset_object($class, $reset_models)) {
1611
                    unset($instance->{$cache}->{$class_name});
1612
                }
1613
            }
1614
        }
1615
        return $instance;
1616
    }
1617
1618
1619
    /**
1620
     * if passed object implements ResettableInterface, then call it's reset() method
1621
     * if passed object implements InterminableInterface, then return false,
1622
     * to indicate that it should NOT be cleared from the Registry cache
1623
     *
1624
     * @param      $object
1625
     * @param bool $reset_models
1626
     * @return bool returns true if cached object should be unset
1627
     */
1628
    private static function _reset_and_unset_object($object, $reset_models)
1629
    {
1630
        if (! is_object($object)) {
1631
            // don't unset anything that's not an object
1632
            return false;
1633
        }
1634
        if ($object instanceof EED_Module) {
1635
            $object::reset();
1636
            // don't unset modules
1637
            return false;
1638
        }
1639
        if ($object instanceof ResettableInterface) {
1640
            if ($object instanceof EEM_Base) {
1641
                if ($reset_models) {
1642
                    $object->reset();
1643
                    return true;
1644
                }
1645
                return false;
1646
            }
1647
            $object->reset();
1648
            return true;
1649
        }
1650
        if (! $object instanceof InterminableInterface) {
1651
            return true;
1652
        }
1653
        return false;
1654
    }
1655
1656
1657
    /**
1658
     * Gets all the custom post type models defined
1659
     *
1660
     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1661
     */
1662
    public function cpt_models()
1663
    {
1664
        $cpt_models = array();
1665
        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1666
            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1667
                $cpt_models[ $short_name ] = $classname;
1668
            }
1669
        }
1670
        return $cpt_models;
1671
    }
1672
1673
1674
    /**
1675
     * @return \EE_Config
1676
     */
1677
    public static function CFG()
1678
    {
1679
        return self::instance()->CFG;
1680
    }
1681
1682
1683
    /**
1684
     * @deprecated $VID:$
1685
     * @param string $class_name
1686
     * @return ReflectionClass
1687
     * @throws ReflectionException
1688
     * @throws InvalidDataTypeException
1689
     */
1690
    public function get_ReflectionClass($class_name)
1691
    {
1692
        return $this->mirror->getReflectionClass($class_name);
1693
    }
1694
}
1695
// End of file EE_Registry.core.php
1696
// Location: ./core/EE_Registry.core.php
1697