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

EE_Registry::getIdentifierForArguments()   C

Complexity

Conditions 7
Paths 11

Size

Total Lines 23
Code Lines 18

Duplication

Lines 14
Ratio 60.87 %

Importance

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