Completed
Branch FET-9795-new-interfaces (ea072c)
by
unknown
51:56 queued 35:16
created

EE_Registry::_load()   C

Complexity

Conditions 15
Paths 28

Size

Total Lines 56
Code Lines 31

Duplication

Lines 7
Ratio 12.5 %

Importance

Changes 0
Metric Value
cc 15
eloc 31
nc 28
nop 8
dl 7
loc 56
rs 6.6357
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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