Completed
Branch BUG-9871-email-validation (e62b1a)
by
unknown
350:41 queued 333:27
created

EE_Registry::add_module()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) { exit('No direct script access allowed'); }
2
/**
3
 * EE_Registry Class
4
 *
5
 * Centralized Application Data Storage and Management
6
 *
7
 * @package                Event Espresso
8
 * @subpackage            core
9
 * @author                    Brent Christensen
10
 */
11
class EE_Registry {
12
13
	/**
14
	 *    EE_Registry Object
15
	 *
16
	 * @var EE_Registry $_instance
17
	 * @access    private
18
	 */
19
	private static $_instance = null;
20
21
	/**
22
	 * @var EE_Dependency_Map $_dependency_map
23
	 * @access    protected
24
	 */
25
	protected $_dependency_map = null;
26
27
	/**
28
	 * @var array $_class_abbreviations
29
	 * @access    protected
30
	 */
31
	protected $_class_abbreviations = array();
32
33
	/**
34
	 * @access public
35
	 * @var \EventEspresso\core\services\commands\CommandBusInterface $BUS
36
	 */
37
	public $BUS;
38
39
	/**
40
	 *    EE_Cart Object
41
	 * @access    public
42
	 * @var    EE_Cart $CART
43
	 */
44
	public $CART = null;
45
46
	/**
47
	 *    EE_Config Object
48
	 * @access    public
49
	 * @var    EE_Config $CFG
50
	 */
51
	public $CFG = null;
52
53
	/**
54
	 * EE_Network_Config Object
55
	 * @access public
56
	 * @var EE_Network_Config $NET_CFG
57
	 */
58
	public $NET_CFG = null;
59
60
	/**
61
	 *    StdClass object for storing library classes in
62
	 *
63
	 * @public LIB
64
	 * @var StdClass $LIB
65
	 */
66
	public $LIB = null;
67
68
	/**
69
	 *    EE_Request_Handler Object
70
	 * @access    public
71
	 * @var    EE_Request_Handler $REQ
72
	 */
73
	public $REQ = null;
74
75
	/**
76
	 *    EE_Session Object
77
	 * @access    public
78
	 * @var    EE_Session $SSN
79
	 */
80
	public $SSN = null;
81
82
	/**
83
	 * holds the ee capabilities object.
84
	 *
85
	 * @since 4.5.0
86
	 *
87
	 * @var EE_Capabilities
88
	 */
89
	public $CAP = null;
90
91
	/**
92
	 * holds the EE_Message_Resource_Manager object.
93
	 *
94
	 * @since 4.9.0
95
	 *
96
	 * @var EE_Message_Resource_Manager
97
	 */
98
	public $MRM = null;
99
100
	/**
101
	 *    $addons - StdClass object for holding addons which have registered themselves to work with EE core
102
	 * @access    public
103
	 * @var    EE_Addon[]
104
	 */
105
	public $addons = null;
106
107
	/**
108
	 *    $models
109
	 * @access    public
110
	 * @var    EEM_Base[] $models keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
111
	 */
112
	public $models = array();
113
114
	/**
115
	 *    $modules
116
	 * @access    public
117
	 * @var    EED_Module[] $modules
118
	 */
119
	public $modules = null;
120
121
	/**
122
	 *    $shortcodes
123
	 * @access    public
124
	 * @var    EES_Shortcode[] $shortcodes
125
	 */
126
	public $shortcodes = null;
127
128
	/**
129
	 *    $widgets
130
	 * @access    public
131
	 * @var    WP_Widget[] $widgets
132
	 */
133
	public $widgets = null;
134
135
	/**
136
	 * $non_abstract_db_models
137
	 * @access public
138
	 * @var array this is an array of all implemented model names (i.e. not the parent abstract models, or models
139
	 * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
140
	 * Keys are model "short names" (eg "Event") as used in model relations, and values are
141
	 * classnames (eg "EEM_Event")
142
	 */
143
	public $non_abstract_db_models = array();
144
145
	/**
146
	 *    $i18n_js_strings - internationalization for JS strings
147
	 *    usage:   EE_Registry::i18n_js_strings['string_key'] = __( 'string to translate.', 'event_espresso' );
148
	 *    in js file:  var translatedString = eei18n.string_key;
149
	 *
150
	 * @access    public
151
	 * @var    array
152
	 */
153
	public static $i18n_js_strings = array();
154
155
	/**
156
	 *    $main_file - path to espresso.php
157
	 *
158
	 * @access    public
159
	 * @var    array
160
	 */
161
	public $main_file;
162
163
	/**
164
	 * array of ReflectionClass objects where the key is the class name
165
	 *
166
	 * @access    public
167
	 * @var ReflectionClass[]
168
	 */
169
	public $_reflectors;
170
171
	/**
172
	 * boolean flag to indicate whether or not to load/save dependencies from/to the cache
173
	 *
174
	 * @access    protected
175
	 * @var boolean $_cache_on
176
	 */
177
	protected $_cache_on = true;
178
179
180
181
	/**
182
	 * @singleton method used to instantiate class object
183
	 * @access    public
184
	 * @param  \EE_Dependency_Map $dependency_map
185
	 * @return \EE_Registry instance
186
	 */
187
	public static function instance( \EE_Dependency_Map $dependency_map = null ) {
188
		// check if class object is instantiated
189
		if ( ! self::$_instance instanceof EE_Registry ) {
190
			self::$_instance = new EE_Registry( $dependency_map );
0 ignored issues
show
Bug introduced by
It seems like $dependency_map defined by parameter $dependency_map on line 187 can be null; however, EE_Registry::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
191
		}
192
		return self::$_instance;
193
	}
194
195
196
197
	/**
198
	 *protected constructor to prevent direct creation
199
	 *
200
	 * @Constructor
201
	 * @access protected
202
	 * @param  \EE_Dependency_Map $dependency_map
203
	 * @return \EE_Registry
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
204
	 */
205
	protected function __construct( \EE_Dependency_Map $dependency_map ) {
206
		$this->_dependency_map = $dependency_map;
207
		add_action( 'EE_Load_Espresso_Core__handle_request__initialize_core_loading', array( $this, 'initialize' ) );
208
	}
209
210
211
212
	/**
213
	 * initialize
214
	 */
215
	public function initialize() {
216
		$this->_class_abbreviations = apply_filters(
217
			'FHEE__EE_Registry____construct___class_abbreviations',
218
			array(
219
				'EE_Config'                   => 'CFG',
220
				'EE_Session'                  => 'SSN',
221
				'EE_Capabilities'             => 'CAP',
222
				'EE_Cart'                     => 'CART',
223
				'EE_Network_Config'           => 'NET_CFG',
224
				'EE_Request_Handler'          => 'REQ',
225
				'EE_Message_Resource_Manager' => 'MRM',
226
				'EventEspresso\core\services\commands\CommandBus' => 'BUS',
227
			)
228
		);
229
		// class library
230
		$this->LIB = new stdClass();
231
		$this->addons = new stdClass();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \stdClass() of type object<stdClass> is incompatible with the declared type array<integer,object<EE_Addon>> of property $addons.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
232
		$this->modules = new stdClass();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \stdClass() of type object<stdClass> is incompatible with the declared type array<integer,object<EED_Module>> of property $modules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
233
		$this->shortcodes = new stdClass();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \stdClass() of type object<stdClass> is incompatible with the declared type array<integer,object<EES_Shortcode>> of property $shortcodes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
234
		$this->widgets = new stdClass();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \stdClass() of type object<stdClass> is incompatible with the declared type array<integer,object<WP_Widget>> of property $widgets.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
235
		$this->load_core( 'Base', array(), true );
236
		// add our request and response objects to the cache
237
		$request_loader = $this->_dependency_map->class_loader( 'EE_Request' );
238
		$this->_set_cached_class(
239
			$request_loader(),
240
			'EE_Request'
241
		);
242
		$response_loader = $this->_dependency_map->class_loader( 'EE_Response' );
243
		$this->_set_cached_class(
244
			$response_loader(),
245
			'EE_Response'
246
		);
247
		add_action( 'AHEE__EE_System__set_hooks_for_core', array( $this, 'init' ) );
248
	}
249
250
251
252
	/**
253
	 *    init
254
	 *
255
	 * @access    public
256
	 * @return    void
257
	 */
258
	public function init() {
259
		// Get current page protocol
260
		$protocol = isset( $_SERVER[ 'HTTPS' ] ) ? 'https://' : 'http://';
261
		// Output admin-ajax.php URL with same protocol as current page
262
		self::$i18n_js_strings[ 'ajax_url' ] = admin_url( 'admin-ajax.php', $protocol );
263
		self::$i18n_js_strings[ 'wp_debug' ] = defined( 'WP_DEBUG' ) ? WP_DEBUG : false;
264
	}
265
266
267
268
	/**
269
	 * localize_i18n_js_strings
270
	 *
271
	 * @return string
272
	 */
273
	public static function localize_i18n_js_strings() {
274
		$i18n_js_strings = (array)EE_Registry::$i18n_js_strings;
275
		foreach ( $i18n_js_strings as $key => $value ) {
276
			if ( is_scalar( $value ) ) {
277
				$i18n_js_strings[ $key ] = html_entity_decode( (string)$value, ENT_QUOTES, 'UTF-8' );
278
			}
279
		}
280
281
		return "/* <![CDATA[ */ var eei18n = " . wp_json_encode( $i18n_js_strings ) . '; /* ]]> */';
282
	}
283
284
285
286
	/**
287
	 * @param mixed string | EED_Module $module
288
	 */
289
	public function add_module( $module ) {
290
		if ( $module instanceof EED_Module ) {
291
			$module_class = get_class( $module );
292
			$this->modules->{$module_class} = $module;
293
		} else {
294
			if ( ! class_exists( 'EE_Module_Request_Router' ) ) {
295
				$this->load_core( 'Module_Request_Router' );
296
			}
297
			$this->modules->{$module} = EE_Module_Request_Router::module_factory( $module );
298
		}
299
	}
300
301
302
303
	/**
304
	 * @param string $module_name
305
	 * @return mixed EED_Module | NULL
306
	 */
307
	public function get_module( $module_name = '' ) {
308
		return isset( $this->modules->{$module_name} ) ? $this->modules->{$module_name} : null;
309
	}
310
311
312
313
	/**
314
	 *    loads core classes - must be singletons
315
	 *
316
	 * @access    public
317
	 * @param string $class_name - simple class name ie: session
318
	 * @param mixed $arguments
319
	 * @param bool $load_only
320
	 * @return mixed
321
	 */
322
	public function load_core( $class_name, $arguments = array(), $load_only = false ) {
323
		$core_paths = apply_filters(
324
			'FHEE__EE_Registry__load_core__core_paths',
325
			array(
326
				EE_CORE,
327
				EE_ADMIN,
328
				EE_CPTS,
329
				EE_CORE . 'data_migration_scripts' . DS,
330
				EE_CORE . 'request_stack' . DS,
331
				EE_CORE . 'middleware' . DS,
332
			)
333
		);
334
		// retrieve instantiated class
335
		return $this->_load( $core_paths, 'EE_', $class_name, 'core', $arguments, false, true, $load_only );
336
	}
337
338
339
340
	/**
341
	 *    loads service classes
342
	 *
343
	 * @access    public
344
	 * @param string $class_name - simple class name ie: session
345
	 * @param mixed $arguments
346
	 * @param bool $load_only
347
	 * @return mixed
348
	 */
349
	public function load_service( $class_name, $arguments = array(), $load_only = false ) {
350
		$service_paths = apply_filters(
351
			'FHEE__EE_Registry__load_service__service_paths',
352
			array(
353
				EE_CORE . 'services' . DS,
354
			)
355
		);
356
		// retrieve instantiated class
357
		return $this->_load( $service_paths, 'EE_', $class_name, 'class', $arguments, false, true, $load_only );
358
	}
359
360
361
362
	/**
363
	 *    loads data_migration_scripts
364
	 *
365
	 * @access    public
366
	 * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
367
	 * @param mixed $arguments
368
	 * @return EE_Data_Migration_Script_Base
369
	 */
370
	public function load_dms( $class_name, $arguments = array() ) {
371
		// retrieve instantiated class
372
		return $this->_load( EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(), 'EE_DMS_', $class_name, 'dms', $arguments, false, false, false );
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_load(\EE_Data_Mi..., false, false, false); of type null|object|boolean adds the type boolean to the return on line 372 which is incompatible with the return type documented by EE_Registry::load_dms of type EE_Data_Migration_Script_Base|null.
Loading history...
373
	}
374
375
376
377
	/**
378
	 *    loads object creating classes - must be singletons
379
	 *
380
	 * @param string $class_name - simple class name ie: attendee
381
	 * @param mixed $arguments - an array of arguments to pass to the class
382
	 * @param bool $from_db - some classes are instantiated from the db and thus call a different method to instantiate
383
	 * @param bool $cache if you don't want the class to be stored in the internal cache (non-persistent) then set this to FALSE (ie. when instantiating model objects from client in a loop)
384
	 * @param bool $load_only whether or not to just load the file and NOT instantiate, or load AND instantiate (default)
385
	 * @return EE_Base_Class | bool
386
	 */
387
	public function load_class( $class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false ) {
388
		$paths = apply_filters( 'FHEE__EE_Registry__load_class__paths', array(
389
			EE_CORE,
390
			EE_CLASSES,
391
			EE_BUSINESS
392
		) );
393
		// retrieve instantiated class
394
		return $this->_load( $paths, 'EE_', $class_name, 'class', $arguments, $from_db, $cache, $load_only );
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_load($paths, 'EE...b, $cache, $load_only); of type null|object|boolean adds the type boolean to the return on line 394 which is incompatible with the return type documented by EE_Registry::load_class of type EE_Base_Class|null.
Loading history...
395
	}
396
397
398
399
	/**
400
	 *    loads helper classes - must be singletons
401
	 *
402
	 * @param string $class_name - simple class name ie: price
403
	 * @param mixed $arguments
404
	 * @param bool $load_only
405
	 * @return EEH_Base | bool
406
	 */
407
	public function load_helper( $class_name, $arguments = array(), $load_only = true ) {
408
		// todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
409
		$helper_paths = apply_filters( 'FHEE__EE_Registry__load_helper__helper_paths', array( EE_HELPERS ) );
410
		// retrieve instantiated class
411
		return $this->_load( $helper_paths, 'EEH_', $class_name, 'helper', $arguments, false, true, $load_only );
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_load($helper_pat...lse, true, $load_only); of type null|object|boolean adds the type boolean to the return on line 411 which is incompatible with the return type documented by EE_Registry::load_helper of type EEH_Base|null.
Loading history...
412
	}
413
414
415
416
	/**
417
	 *    loads core classes - must be singletons
418
	 *
419
	 * @access    public
420
	 * @param string $class_name - simple class name ie: session
421
	 * @param mixed $arguments
422
	 * @param bool $load_only
423
	 * @param bool $cache  whether to cache the object or not.
424
	 * @return mixed
425
	 */
426
	public function load_lib( $class_name, $arguments = array(), $load_only = false, $cache = true ) {
427
		$paths = array(
428
			EE_LIBRARIES,
429
			EE_LIBRARIES . 'messages' . DS,
430
			EE_LIBRARIES . 'shortcodes' . DS,
431
			EE_LIBRARIES . 'qtips' . DS,
432
			EE_LIBRARIES . 'payment_methods' . DS,
433
		);
434
		// retrieve instantiated class
435
		return $this->_load( $paths, 'EE_', $class_name, 'lib', $arguments, false, $cache, $load_only );
436
	}
437
438
439
440
	/**
441
	 *    loads model classes - must be singletons
442
	 *
443
	 * @param string $class_name - simple class name ie: price
444
	 * @param mixed $arguments
445
	 * @param bool $load_only
446
	 * @return EEM_Base | bool
447
	 */
448
	public function load_model( $class_name, $arguments = array(), $load_only = false ) {
449
		$paths = apply_filters( 'FHEE__EE_Registry__load_model__paths', array(
450
			EE_MODELS,
451
			EE_CORE
452
		) );
453
		// retrieve instantiated class
454
		return $this->_load( $paths, 'EEM_', $class_name, 'model', $arguments, false, true, $load_only );
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_load($paths, 'EE...lse, true, $load_only); of type null|object|boolean adds the type boolean to the return on line 454 which is incompatible with the return type documented by EE_Registry::load_model of type EEM_Base|null.
Loading history...
455
	}
456
457
458
459
	/**
460
	 *    loads model classes - must be singletons
461
	 *
462
	 * @param string $class_name - simple class name ie: price
463
	 * @param mixed $arguments
464
	 * @param bool $load_only
465
	 * @return mixed | bool
466
	 */
467
	public function load_model_class( $class_name, $arguments = array(), $load_only = true ) {
468
		$paths = array(
469
			EE_MODELS . 'fields' . DS,
470
			EE_MODELS . 'helpers' . DS,
471
			EE_MODELS . 'relations' . DS,
472
			EE_MODELS . 'strategies' . DS
473
		);
474
		// retrieve instantiated class
475
		return $this->_load( $paths, 'EE_', $class_name, '', $arguments, false, true, $load_only );
476
	}
477
478
479
480
	/**
481
	 * Determines if $model_name is the name of an actual EE model.
482
	 * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
483
	 * @return boolean
484
	 */
485
	public function is_model_name( $model_name ) {
486
		return isset( $this->models[ $model_name ] ) ? true : false;
487
	}
488
489
490
491
	/**
492
	 *    generic class loader
493
	 *
494
	 * @param string $path_to_file - directory path to file location, not including filename
495
	 * @param string $file_name - file name  ie:  my_file.php, including extension
496
	 * @param string $type - file type - core? class? helper? model?
497
	 * @param mixed $arguments
498
	 * @param bool $load_only
499
	 * @return mixed
500
	 */
501
	public function load_file( $path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true ) {
502
		// retrieve instantiated class
503
		return $this->_load( $path_to_file, '', $file_name, $type, $arguments, false, true, $load_only );
0 ignored issues
show
Documentation introduced by
$path_to_file is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
504
	}
505
506
507
508
	/**
509
	 *    load_addon
510
	 *
511
	 * @param string $path_to_file - directory path to file location, not including filename
512
	 * @param string $class_name - full class name  ie:  My_Class
513
	 * @param string $type - file type - core? class? helper? model?
514
	 * @param mixed $arguments
515
	 * @param bool $load_only
516
	 * @return EE_Addon
517
	 */
518
	public function load_addon( $path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false ) {
519
		// retrieve instantiated class
520
		return $this->_load( $path_to_file, 'addon', $class_name, $type, $arguments, false, true, $load_only );
0 ignored issues
show
Documentation introduced by
$path_to_file is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug Compatibility introduced by
The expression $this->_load($path_to_fi...lse, true, $load_only); of type null|object|boolean adds the type boolean to the return on line 520 which is incompatible with the return type documented by EE_Registry::load_addon of type EE_Addon|null.
Loading history...
521
	}
522
523
524
525
	/**
526
	 * instantiates, caches, and automatically resolves dependencies
527
	 * for classes that use a Fully Qualified Class Name.
528
	 * if the class is not capable of being loaded using PSR-4 autoloading,
529
	 * then you need to use one of the existing load_*() methods
530
	 * which can resolve the classname and filepath from the passed arguments
531
	 *
532
	 * @param bool|string $class_name   Fully Qualified Class Name
533
	 * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
534
	 * @param bool        $cache        whether to cache the instantiated object for reuse
535
	 * @param bool        $from_db      some classes are instantiated from the db
536
	 *                                  and thus call a different method to instantiate
537
	 * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
538
	 * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
539
	 * @return mixed                    null = failure to load or instantiate class object.
540
	 *                                  object = class loaded and instantiated successfully.
541
	 *                                  bool = fail or success when $load_only is true
542
	 */
543
	public function create(
544
		$class_name = false,
545
		$arguments = array(),
546
		$cache = false,
547
		$from_db = false,
548
		$load_only = false,
549
		$addon = false
550
	) {
551
		$class_name = $this->_dependency_map->get_alias( $class_name );
0 ignored issues
show
Bug introduced by
It seems like $class_name defined by $this->_dependency_map->get_alias($class_name) on line 551 can also be of type boolean; however, EE_Dependency_Map::get_alias() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
552
		if ( ! class_exists( $class_name ) ) {
553
			// maybe the class is registered with a preceding \
554
			$class_name = strpos( $class_name, '\\' ) !== 0 ? '\\' . $class_name : $class_name;
555
			// still doesn't exist ?
556
			if ( ! class_exists( $class_name ) ) {
557
				return null;
558
			}
559
		}
560
		// if we're only loading the class and it already exists, then let's just return true immediately
561
		if ( $load_only ) {
562
			return true;
563
		}
564
		$addon = $addon ? 'addon' : '';
565
		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
566
		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
567
		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
568 View Code Duplication
		if ( $this->_cache_on && $cache && ! $load_only ) {
569
			// return object if it's already cached
570
			$cached_class = $this->_get_cached_class( $class_name, $addon );
0 ignored issues
show
Bug introduced by
It seems like $class_name can also be of type boolean; however, EE_Registry::_get_cached_class() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
571
			if ( $cached_class !== null ) {
572
				return $cached_class;
573
			}
574
		}
575
		// instantiate the requested object
576
		$class_obj = $this->_create_object( $class_name, $arguments, $addon, $from_db );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $class_obj is correct as $this->_create_object($c...ents, $addon, $from_db) (which targets EE_Registry::_create_object()) seems to always return null.

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

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

}

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

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

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

Loading history...
Bug introduced by
It seems like $class_name can also be of type boolean; however, EE_Registry::_create_object() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
577
		if ( $this->_cache_on && $cache ) {
578
			// save it for later... kinda like gum  { : $
579
			$this->_set_cached_class( $class_obj, $class_name, $addon, $from_db );
0 ignored issues
show
Documentation introduced by
$class_obj is of type null, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like $class_name can also be of type boolean; however, EE_Registry::_set_cached_class() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
580
		}
581
		$this->_cache_on = true;
582
		return $class_obj;
583
	}
584
585
586
587
	/**
588
	 * instantiates, caches, and injects dependencies for classes
589
	 *
590
	 * @param array $file_paths         an array of paths to folders to look in
591
	 * @param string      $class_prefix EE  or EEM or... ???
592
	 * @param bool|string $class_name   $class name
593
	 * @param string      $type         file type - core? class? helper? model?
594
	 * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
595
	 * @param bool        $from_db      some classes are instantiated from the db
596
	 *                                  and thus call a different method to instantiate
597
	 * @param bool        $cache        whether to cache the instantiated object for reuse
598
	 * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
599
	 * @return null|object|bool         null = failure to load or instantiate class object.
600
	 *                                  object = class loaded and instantiated successfully.
601
	 *                                  bool = fail or success when $load_only is true
602
	 */
603
	protected function _load(
604
		$file_paths = array(),
605
		$class_prefix = 'EE_',
606
		$class_name = false,
607
		$type = 'class',
608
		$arguments = array(),
609
		$from_db = false,
610
		$cache = true,
611
		$load_only = false
612
	) {
613
		// strip php file extension
614
		$class_name = str_replace( '.php', '', trim( $class_name ) );
615
		// does the class have a prefix ?
616
		if ( ! empty( $class_prefix ) && $class_prefix != 'addon' ) {
617
			// make sure $class_prefix is uppercase
618
			$class_prefix = strtoupper( trim( $class_prefix ) );
619
			// add class prefix ONCE!!!
620
			$class_name = $class_prefix . str_replace( $class_prefix, '', $class_name );
621
		}
622
		$class_name = $this->_dependency_map->get_alias( $class_name );
623
		$class_exists = class_exists( $class_name );
624
		// if we're only loading the class and it already exists, then let's just return true immediately
625
		if ( $load_only && $class_exists ) {
626
			return true;
627
		}
628
		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
629
		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
630
		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
631 View Code Duplication
		if ( $this->_cache_on && $cache && ! $load_only ) {
632
			// return object if it's already cached
633
			$cached_class = $this->_get_cached_class( $class_name, $class_prefix );
0 ignored issues
show
Documentation introduced by
$class_name is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
634
			if ( $cached_class !== null ) {
635
				return $cached_class;
636
			}
637
		}
638
		// if the class doesn't already exist.. then we need to try and find the file and load it
639
		if ( ! $class_exists ) {
640
			// get full path to file
641
			$path = $this->_resolve_path( $class_name, $type, $file_paths );
0 ignored issues
show
Documentation introduced by
$class_name is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
642
			// load the file
643
			$loaded = $this->_require_file( $path, $class_name, $type, $file_paths );
0 ignored issues
show
Security Bug introduced by
It seems like $path defined by $this->_resolve_path($cl...me, $type, $file_paths) on line 641 can also be of type false; however, EE_Registry::_require_file() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
Documentation introduced by
$class_name is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
644
			// if loading failed, or we are only loading a file but NOT instantiating an object
645
			if ( ! $loaded || $load_only ) {
646
				// return boolean if only loading, or null if an object was expected
647
				return $load_only ? $loaded : null;
648
			}
649
		}
650
		// instantiate the requested object
651
		$class_obj = $this->_create_object( $class_name, $arguments, $type, $from_db );
0 ignored issues
show
Documentation introduced by
$class_name is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
Are you sure the assignment to $class_obj is correct as $this->_create_object($c...ments, $type, $from_db) (which targets EE_Registry::_create_object()) seems to always return null.

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

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

}

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

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

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

Loading history...
652
		if ( $this->_cache_on && $cache ) {
653
			// save it for later... kinda like gum  { : $
654
			$this->_set_cached_class( $class_obj, $class_name, $class_prefix, $from_db );
0 ignored issues
show
Documentation introduced by
$class_obj is of type null, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$class_name is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
655
		}
656
		$this->_cache_on = true;
657
		return $class_obj;
658
	}
659
660
661
662
	/**
663
	 * _get_cached_class
664
	 *
665
	 * attempts to find a cached version of the requested class
666
	 * by looking in the following places:
667
	 * 		$this->{$class_abbreviation} 		 	ie:   	$this->CART
668
	 * 		$this->{$class_name}           		 		ie:    $this->Some_Class
669
	 * 		$this->LIB->{$class_name}				ie: 	$this->LIB->Some_Class
670
	 * 		$this->addon->{$class_name}	ie: 	$this->addon->Some_Addon_Class
671
	 *
672
	 * @access protected
673
	 * @param string $class_name
674
	 * @param string $class_prefix
675
	 * @return null|object
676
	 */
677
	protected function _get_cached_class( $class_name, $class_prefix = '' ) {
678
		if ( isset( $this->_class_abbreviations[ $class_name ] ) ) {
679
			$class_abbreviation = $this->_class_abbreviations[ $class_name ];
680
		} else {
681
			// have to specify something, but not anything that will conflict
682
			$class_abbreviation = 'FANCY_BATMAN_PANTS';
683
		}
684
		// check if class has already been loaded, and return it if it has been
685
		if ( isset( $this->{$class_abbreviation} ) && ! is_null( $this->{$class_abbreviation} ) ) {
686
			return $this->{$class_abbreviation};
687
		} else if ( isset ( $this->{$class_name} ) ) {
688
			return $this->{$class_name};
689
		} else if ( isset ( $this->LIB->{$class_name} ) ) {
690
			return $this->LIB->{$class_name};
691
		} else if ( $class_prefix == 'addon' && isset ( $this->addons->{$class_name} ) ) {
692
			return $this->addons->{$class_name};
693
		}
694
		return null;
695
	}
696
697
698
699
	/**
700
	 * _resolve_path
701
	 *
702
	 * attempts to find a full valid filepath for the requested class.
703
	 * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
704
	 * then returns that path if the target file has been found and is readable
705
	 *
706
	 * @access protected
707
	 * @param string $class_name
708
	 * @param string $type
709
	 * @param array $file_paths
710
	 * @return string | bool
711
	 */
712
	protected function _resolve_path( $class_name, $type = '', $file_paths = array() ) {
713
		// make sure $file_paths is an array
714
		$file_paths = is_array( $file_paths ) ? $file_paths : array( $file_paths );
715
		// cycle thru paths
716
		foreach ( $file_paths as $key => $file_path ) {
717
			// convert all separators to proper DS, if no filepath, then use EE_CLASSES
718
			$file_path = $file_path ? str_replace( array( '/', '\\' ), DS, $file_path ) : EE_CLASSES;
719
			// prep file type
720
			$type = ! empty( $type ) ? trim( $type, '.' ) . '.' : '';
721
			// build full file path
722
			$file_paths[ $key ] = rtrim( $file_path, DS ) . DS . $class_name . '.' . $type . 'php';
723
			//does the file exist and can be read ?
724
			if ( is_readable( $file_paths[ $key ] ) ) {
725
				return $file_paths[ $key ];
726
			}
727
		}
728
		return false;
729
	}
730
731
732
733
	/**
734
	 * _require_file
735
	 *
736
	 * basically just performs a require_once()
737
	 * but with some error handling
738
	 *
739
	 * @access protected
740
	 * @param  string $path
741
	 * @param  string $class_name
742
	 * @param  string $type
743
	 * @param  array $file_paths
744
	 * @return boolean
745
	 * @throws \EE_Error
746
	 */
747
	protected function _require_file( $path, $class_name, $type = '', $file_paths = array() ) {
748
		// don't give up! you gotta...
749
		try {
750
			//does the file exist and can it be read ?
751 View Code Duplication
			if ( ! $path ) {
752
				// so sorry, can't find the file
753
				throw new EE_Error (
754
					sprintf(
755
						__( 'The %1$s file %2$s could not be located or is not readable due to file permissions. Please ensure that the following filepath(s) are correct: %3$s', 'event_espresso' ),
756
						trim( $type, '.' ),
757
						$class_name,
758
						'<br />' . implode( ',<br />', $file_paths )
759
					)
760
				);
761
			}
762
			// get the file
763
			require_once( $path );
764
			// if the class isn't already declared somewhere
765 View Code Duplication
			if ( class_exists( $class_name, false ) === false ) {
766
				// so sorry, not a class
767
				throw new EE_Error(
768
					sprintf(
769
						__( 'The %s file %s does not appear to contain the %s Class.', 'event_espresso' ),
770
						$type,
771
						$path,
772
						$class_name
773
					)
774
				);
775
			}
776
777
		} catch ( EE_Error $e ) {
778
			$e->get_error();
779
			return false;
780
		}
781
		return true;
782
	}
783
784
785
786
	/**
787
	 * _create_object
788
	 * Attempts to instantiate the requested class via any of the
789
	 * commonly used instantiation methods employed throughout EE.
790
	 * The priority for instantiation is as follows:
791
	 * 		- abstract classes or any class flagged as "load only" (no instantiation occurs)
792
	 * 	 	- model objects via their 'new_instance_from_db' method
793
	 * 	 	- model objects via their 'new_instance' method
794
	 * 	 	- "singleton" classes" via their 'instance' method
795
	 *  	- standard instantiable classes via their __constructor
796
	 * Prior to instantiation, if the classname exists in the dependency_map,
797
	 * then the constructor for the requested class will be examined to determine
798
	 * if any dependencies exist, and if they can be injected.
799
	 * If so, then those classes will be added to the array of arguments passed to the constructor
800
	 *
801
	 * @access protected
802
	 * @param string $class_name
803
	 * @param array $arguments
804
	 * @param string $type
805
	 * @param bool $from_db
806
	 * @return null | object
807
	 * @throws \EE_Error
808
	 */
809
	protected function _create_object( $class_name, $arguments = array(), $type = '', $from_db = false ) {
810
		$class_obj = null;
811
		$instantiation_mode = '0) none';
812
		// don't give up! you gotta...
813
		try {
814
			// create reflection
815
			$reflector = $this->get_ReflectionClass( $class_name );
816
			// make sure arguments are an array
817
			$arguments = is_array( $arguments ) ? $arguments : array( $arguments );
818
			// and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
819
			// else wrap it in an additional array so that it doesn't get split into multiple parameters
820
			$arguments = $this->_array_is_numerically_and_sequentially_indexed( $arguments )
821
				? $arguments
822
				: array( $arguments );
823
			// attempt to inject dependencies ?
824
			if ( $this->_dependency_map->has( $class_name ) ) {
825
				$arguments = $this->_resolve_dependencies( $reflector, $class_name, $arguments );
826
			}
827
			// instantiate the class if possible
828
			if ( $reflector->isAbstract() ) {
829
				// nothing to instantiate, loading file was enough
830
				// does not throw an exception so $instantiation_mode is unused
831
				// $instantiation_mode = "1) no constructor abstract class";
832
				$class_obj = true;
833
			} else if ( $reflector->getConstructor() === null && $reflector->isInstantiable() && empty( $arguments ) ) {
834
				// no constructor = static methods only... nothing to instantiate, loading file was enough
835
				$instantiation_mode = "2) no constructor but instantiable";
836
				$class_obj = $reflector->newInstance();
837
			} else if ( $from_db && method_exists( $class_name, 'new_instance_from_db' ) ) {
838
				$instantiation_mode = "3) new_instance_from_db()";
839
				$class_obj = call_user_func_array( array( $class_name, 'new_instance_from_db' ), $arguments );
840
			} else if ( method_exists( $class_name, 'new_instance' ) ) {
841
				$instantiation_mode = "4) new_instance()";
842
				$class_obj = call_user_func_array( array( $class_name, 'new_instance' ), $arguments );
843
			} else if ( method_exists( $class_name, 'instance' ) ) {
844
				$instantiation_mode = "5) instance()";
845
				$class_obj = call_user_func_array( array( $class_name, 'instance' ), $arguments );
846
			} else if ( $reflector->isInstantiable() ) {
847
				$instantiation_mode = "6) constructor";
848
				$class_obj = $reflector->newInstanceArgs( $arguments );
849
			} else {
850
				// heh ? something's not right !
851
				throw new EE_Error(
852
					sprintf(
853
						__( 'The %s file %s could not be instantiated.', 'event_espresso' ),
854
						$type,
855
						$class_name
856
					)
857
				);
858
			}
859
		} catch ( Exception $e ) {
860
			if ( ! $e instanceof EE_Error ) {
861
				$e = new EE_Error(
862
					sprintf(
863
						__( 'The following error occurred while attempting to instantiate "%1$s": %2$s %3$s %2$s instantiation mode : %4$s', 'event_espresso' ),
864
						$class_name,
865
						'<br />',
866
						$e->getMessage(),
867
						$instantiation_mode
868
					)
869
				);
870
			}
871
			$e->get_error();
872
		}
873
		return $class_obj;
874
	}
875
876
877
878
	/**
879
	 * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
880
	 * @param array $array
881
	 * @return bool
882
	 */
883
	protected function _array_is_numerically_and_sequentially_indexed( array $array ) {
884
		return ! empty( $array ) ? array_keys( $array ) === range( 0, count( $array ) - 1 ) : true;
885
	}
886
887
888
889
	/**
890
	 * getReflectionClass
891
	 *
892
	 * checks if a ReflectionClass object has already been generated for a class
893
	 * and returns that instead of creating a new one
894
	 *
895
	 * @access public
896
	 * @param string $class_name
897
	 * @return ReflectionClass
898
	 */
899 View Code Duplication
	public function get_ReflectionClass( $class_name ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
900
		if (
901
			! isset( $this->_reflectors[ $class_name ] )
902
			|| ! $this->_reflectors[ $class_name ] instanceof ReflectionClass
903
		) {
904
			$this->_reflectors[ $class_name ] = new ReflectionClass( $class_name );
905
		}
906
		return $this->_reflectors[ $class_name ];
907
	}
908
909
910
911
	/**
912
	 * _resolve_dependencies
913
	 * examines the constructor for the requested class to determine
914
	 * if any dependencies exist, and if they can be injected.
915
	 * If so, then those classes will be added to the array of arguments passed to the constructor
916
	 * PLZ NOTE: this is achieved by type hinting the constructor params
917
	 * For example:
918
	 *        if attempting to load a class "Foo" with the following constructor:
919
	 *        __construct( Bar $bar_class, Fighter $grohl_class )
920
	 *        then $bar_class and $grohl_class will be added to the $arguments array,
921
	 *        but only IF they are NOT already present in the incoming arguments array,
922
	 *        and the correct classes can be loaded
923
	 *
924
	 * @access protected
925
	 * @param ReflectionClass $reflector
926
	 * @param string          $class_name
927
	 * @param array           $arguments
928
	 * @return array
929
	 * @throws \ReflectionException
930
	 */
931
	protected function _resolve_dependencies( ReflectionClass $reflector, $class_name, $arguments = array() ) {
932
		// let's examine the constructor
933
		$constructor = $reflector->getConstructor();
934
		// whu? huh? nothing?
935
		if ( ! $constructor ) {
936
			return $arguments;
937
		}
938
		// get constructor parameters
939
		$params = $constructor->getParameters();
940
		// and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
941
		$argument_keys = array_keys( $arguments );
942
		// now loop thru all of the constructors expected parameters
943
		foreach ( $params as $index => $param ) {
944
			// is this a dependency for a specific class ?
945
			$param_class = $param->getClass() ? $param->getClass()->name : null;
946
			if (
947
				// param is not even a class
948
				empty( $param_class )
949
				// and something already exists in the incoming arguments for this param
950
				&& isset( $argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ] )
951
			) {
952
				// so let's skip this argument and move on to the next
953
				continue;
954
			} else if (
955
				// parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
956
				! empty( $param_class )
957
				&& isset( $argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ] )
958
				&& $arguments[ $argument_keys[ $index ] ] instanceof $param_class
959
			) {
960
				// skip this argument and move on to the next
961
				continue;
962
			} else if (
963
				// parameter is type hinted as a class, and should be injected
964
				! empty( $param_class )
965
				&& $this->_dependency_map->has_dependency_for_class( $class_name, $param_class )
966
			) {
967
				$arguments = $this->_resolve_dependency( $class_name, $param_class, $arguments, $index );
968
			} else {
969
				try {
970
					$arguments[ $index ] = $param->getDefaultValue();
971
				} catch ( ReflectionException $e ) {
972
					throw new ReflectionException(
973
						sprintf(
974
							__( '%1$s for parameter "$%2$s"', 'event_espresso' ),
975
							$e->getMessage(),
976
							$param->getName()
977
						)
978
					);
979
				}
980
			}
981
982
		}
983
		return $arguments;
984
	}
985
986
987
988
	/**
989
	 * @access protected
990
	 * @param string $class_name
991
	 * @param string $param_class
992
	 * @param array $arguments
993
	 * @param mixed $index
994
	 * @return array
995
	 */
996
	protected function _resolve_dependency( $class_name, $param_class , $arguments, $index ) {
997
		$dependency = null;
998
		// should dependency be loaded from cache ?
999
		$cache_on = $this->_dependency_map->loading_strategy_for_class_dependency( $class_name, $param_class )
1000
		            !== EE_Dependency_Map::load_new_object
1001
			? true
1002
			: false;
1003
		// we might have a dependency...
1004
		// let's MAYBE try and find it in our cache if that's what's been requested
1005
		$cached_class = $cache_on ? $this->_get_cached_class( $param_class ) : null;
1006
		// and grab it if it exists
1007
		if ( $cached_class instanceof $param_class ) {
1008
			$dependency = $cached_class;
1009
		} else if ( $param_class != $class_name ) {
1010
			// obtain the loader method from the dependency map
1011
			$loader = $this->_dependency_map->class_loader( $param_class );
1012
			// is loader a custom closure ?
1013
			if ( $loader instanceof Closure ) {
1014
				$dependency = $loader();
1015
			} else {
1016
				// set the cache on property for the recursive loading call
1017
				$this->_cache_on = $cache_on;
1018
				// if not, then let's try and load it via the registry
1019
				if ( method_exists( $this, $loader ) ) {
1020
					$dependency = $this->{$loader}($param_class);
1021
				} else {
1022
					$dependency = $this->create($param_class, array(), $cache_on);
1023
				}
1024
			}
1025
		}
1026
		// did we successfully find the correct dependency ?
1027
		if ( $dependency instanceof $param_class ) {
1028
			// then let's inject it into the incoming array of arguments at the correct location
1029
			if ( isset( $argument_keys[ $index ] ) ) {
0 ignored issues
show
Bug introduced by
The variable $argument_keys seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

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

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

Loading history...
1030
				$arguments[ $argument_keys[ $index ] ] = $dependency;
1031
			} else {
1032
				$arguments[ $index ] = $dependency;
1033
			}
1034
		}
1035
		return $arguments;
1036
	}
1037
1038
1039
1040
	/**
1041
	 * _set_cached_class
1042
	 *
1043
	 * attempts to cache the instantiated class locally
1044
	 * in one of the following places, in the following order:
1045
	 *        $this->{class_abbreviation}   ie:    $this->CART
1046
	 *        $this->{$class_name}          ie:    $this->Some_Class
1047
	 *        $this->addon->{$$class_name} 	ie:    $this->addon->Some_Addon_Class
1048
	 *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1049
	 *
1050
	 * @access protected
1051
	 * @param object $class_obj
1052
	 * @param string $class_name
1053
	 * @param string $class_prefix
1054
	 * @param bool $from_db
1055
	 * @return void
1056
	 */
1057
	protected function _set_cached_class( $class_obj, $class_name, $class_prefix = '', $from_db = false ) {
1058
		if ( empty( $class_obj ) ) {
1059
			return;
1060
		}
1061
		// return newly instantiated class
1062
		if ( isset( $this->_class_abbreviations[ $class_name ] ) ) {
1063
			$class_abbreviation = $this->_class_abbreviations[ $class_name ];
1064
			$this->{$class_abbreviation} = $class_obj;
1065
		} else if ( property_exists( $this, $class_name ) ) {
1066
			$this->{$class_name} = $class_obj;
1067
		} else if ( $class_prefix == 'addon' ) {
1068
			$this->addons->{$class_name} = $class_obj;
1069
		} else if ( ! $from_db ) {
1070
			$this->LIB->{$class_name} = $class_obj;
1071
		}
1072
	}
1073
1074
1075
1076
	/**
1077
	 * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1078
	 *
1079
	 *
1080
	 * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1081
	 *                          in the EE_Dependency_Map::$_class_loaders array,
1082
	 *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1083
	 * @param array  $arguments
1084
	 * @return object
1085
	 */
1086
	public static function factory( $classname, $arguments = array() ) {
1087
		$loader = self::instance()->_dependency_map->class_loader( $classname );
1088
		if ( $loader instanceof Closure ) {
1089
			return $loader( $arguments );
1090
		} else if ( method_exists( EE_Registry::instance(), $loader ) ) {
1091
			return EE_Registry::instance()->{$loader}( $classname, $arguments );
1092
		}
1093
		return null;
1094
	}
1095
1096
1097
1098
	/**
1099
	 * Gets the addon by its name/slug (not classname. For that, just
1100
	 * use the classname as the property name on EE_Config::instance()->addons)
1101
	 * @param string $name
1102
	 * @return EE_Addon
1103
	 */
1104
	public function get_addon_by_name( $name ) {
1105
		foreach ( $this->addons as $addon ) {
1106
			if ( $addon->name() == $name ) {
1107
				return $addon;
1108
			}
1109
		}
1110
		return null;
1111
	}
1112
1113
1114
1115
	/**
1116
	 * Gets an array of all the registered addons, where the keys are their names. (ie, what each returns for their name() function) They're already available on EE_Config::instance()->addons as properties, where each property's name is the addon's classname. So if you just want to get the addon by classname, use EE_Config::instance()->addons->{classname}
1117
	 *
1118
	 * @return EE_Addon[] where the KEYS are the addon's name()
1119
	 */
1120
	public function get_addons_by_name() {
1121
		$addons = array();
1122
		foreach ( $this->addons as $addon ) {
1123
			$addons[ $addon->name() ] = $addon;
1124
		}
1125
		return $addons;
1126
	}
1127
1128
1129
1130
	/**
1131
	 * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1132
	 * a stale copy of it around
1133
	 *
1134
	 * @param string $model_name
1135
	 * @return \EEM_Base
1136
	 * @throws \EE_Error
1137
	 */
1138
	public function reset_model( $model_name ) {
1139
		$model = $this->load_model( $model_name );
1140
		$model_class_name = get_class( $model );
1141
		//get that model reset it and make sure we nuke the old reference to it
1142
		if ( $model instanceof $model_class_name && is_callable( array( $model_class_name, 'reset' ))) {
1143
			$this->LIB->{$model_class_name} = $model::reset();
1144
		} else {
1145
			throw new EE_Error( sprintf( __( 'Model %s does not have a method "reset"', 'event_espresso' ), $model_name ) );
1146
		}
1147
		return $this->LIB->{$model_class_name};
1148
	}
1149
1150
1151
1152
	/**
1153
	 * Resets the registry.
1154
	 *
1155
	 * The criteria for what gets reset is based on what can be shared between sites on the same request when switch_to_blog
1156
	 * is used in a multisite install.  Here is a list of things that are NOT reset.
1157
	 *
1158
	 * - $_dependency_map
1159
	 * - $_class_abbreviations
1160
	 * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1161
	 * - $REQ:  Still on the same request so no need to change.
1162
	 * - $CAP: There is no site specific state in the EE_Capability class.
1163
	 * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only one Session
1164
	 *         can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1165
	 * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1166
	 *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1167
	 *             switch or on the restore.
1168
	 * - $modules
1169
	 * - $shortcodes
1170
	 * - $widgets
1171
	 *
1172
	 * @param boolean $hard whether to reset data in the database too, or just refresh
1173
	 * the Registry to its state at the beginning of the request
1174
	 * @param boolean $reinstantiate whether to create new instances of EE_Registry's singletons too,
1175
	 * or just reset without re-instantiating (handy to set to FALSE if you're not sure if you CAN
1176
	 * currently reinstantiate the singletons at the moment)
1177
	 * @param   bool    $reset_models    Defaults to true.  When false, then the models are not reset.  This is so client
1178
	 *                                  code instead can just change the model context to a different blog id if necessary
1179
	 *
1180
	 * @return EE_Registry
1181
	 */
1182
	public static function reset( $hard = false, $reinstantiate = true, $reset_models = true ) {
1183
		$instance = self::instance();
1184
		EEH_Activation::reset();
1185
1186
		//properties that get reset
1187
		$instance->_cache_on = true;
1188
		$instance->CFG = EE_Config::reset( $hard, $reinstantiate );
1189
		$instance->CART = null;
1190
		$instance->MRM = null;
1191
		$instance->LIB = new stdClass();
1192
1193
		//messages reset
1194
		EED_Messages::reset();
1195
1196
		if ( $reset_models ) {
1197
			foreach ( array_keys( $instance->non_abstract_db_models ) as $model_name ) {
1198
				$instance->reset_model( $model_name );
1199
			}
1200
		}
1201
1202
		return $instance;
1203
	}
1204
1205
1206
1207
	/**
1208
	 * @override magic methods
1209
	 * @return void
1210
	 */
1211
	final function __destruct() {
1212
	}
1213
1214
1215
1216
	/**
1217
	 * @param $a
1218
	 * @param $b
1219
	 */
1220
	final function __call( $a, $b ) {
1221
	}
1222
1223
1224
1225
	/**
1226
	 * @param $a
1227
	 */
1228
	final function __get( $a ) {
0 ignored issues
show
Unused Code introduced by
The parameter $a is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1229
	}
1230
1231
1232
1233
	/**
1234
	 * @param $a
1235
	 * @param $b
1236
	 */
1237
	final function __set( $a, $b ) {
0 ignored issues
show
Unused Code introduced by
The parameter $a is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $b is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1238
	}
1239
1240
1241
1242
	/**
1243
	 * @param $a
1244
	 */
1245
	final function __isset( $a ) {
0 ignored issues
show
Unused Code introduced by
The parameter $a is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1246
	}
1247
1248
1249
1250
	/**
1251
	 * @param $a
1252
	 */
1253
	final function __unset( $a ) {
0 ignored issues
show
Unused Code introduced by
The parameter $a is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1254
	}
1255
1256
1257
1258
	/**
1259
	 * @return array
1260
	 */
1261
	final function __sleep() {
1262
		return array();
1263
	}
1264
1265
1266
1267
	final function __wakeup() {
1268
	}
1269
1270
1271
1272
	/**
1273
	 * @return string
1274
	 */
1275
	final function __toString() {
1276
		return '';
1277
	}
1278
1279
1280
1281
	final function __invoke() {
1282
	}
1283
1284
1285
1286
	final function __set_state() {
1287
	}
1288
1289
1290
1291
	final function __clone() {
1292
	}
1293
1294
1295
1296
	/**
1297
	 * @param $a
1298
	 * @param $b
1299
	 */
1300
	final static function __callStatic( $a, $b ) {
0 ignored issues
show
Unused Code introduced by
The parameter $a is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $b is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1301
	}
1302
1303
	/**
1304
	 * Gets all the custom post type models defined
1305
	 * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1306
	 */
1307
	public function cpt_models() {
1308
		$cpt_models = array();
1309
		foreach( $this->non_abstract_db_models as $short_name => $classname ) {
1310
			if( is_subclass_of(  $classname, 'EEM_CPT_Base' ) ) {
1311
				$cpt_models[ $short_name ] = $classname;
1312
			}
1313
		}
1314
		return $cpt_models;
1315
	}
1316
1317
1318
1319
	/**
1320
	 * @return \EE_Config
1321
	 */
1322
	public static function CFG() {
1323
		return self::instance()->CFG;
1324
	}
1325
1326
1327
}
1328
// End of file EE_Registry.core.php
1329
// Location: ./core/EE_Registry.core.php
1330