Completed
Branch FET/11450/reserved-instance-in... (972752)
by
unknown
55:29 queued 42:15
created

EE_Registry::_load()   C

Complexity

Conditions 15
Paths 28

Size

Total Lines 59
Code Lines 34

Duplication

Lines 7
Ratio 11.86 %

Importance

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

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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