Completed
Branch FET-9046-messages-queue (acf360)
by
unknown
1260:33 queued 1235:57
created

EE_Registry::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 52
Code Lines 39

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 52
rs 9.4929
cc 1
eloc 39
nc 1
nop 0

How to fix   Long Method   

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:

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
	 * @var EE_Registry $_instance
16
	 * @access    private
17
	 */
18
	private static $_instance = null;
19
20
	/**
21
	 * @var array $_class_abbreviations
22
	 * @access    protected
23
	 */
24
	protected $_class_abbreviations = array();
25
26
	/**
27
	 * @var array $_auto_resolve_dependencies
28
	 * @access    protected
29
	 */
30
	protected $_auto_resolve_dependencies = array();
31
32
	/**
33
	 *    EE_Cart Object
34
	 * @access    public
35
	 * @var    EE_Cart $CART
36
	 */
37
	public $CART = null;
38
39
	/**
40
	 *    EE_Config Object
41
	 * @access    public
42
	 * @var    EE_Config $CFG
43
	 */
44
	public $CFG = null;
45
46
	/**
47
	 * EE_Network_Config Object
48
	 * @access public
49
	 * @var EE_Network_Config $NET_CFG
50
	 */
51
	public $NET_CFG = null;
52
53
	/**
54
	 *    StdClass object for storing library classes in
55
	 * @public LIB
56
	 */
57
	public $LIB = null;
58
59
	/**
60
	 *    EE_Request_Handler Object
61
	 * @access    public
62
	 * @var    EE_Request_Handler $REQ
63
	 */
64
	public $REQ = null;
65
66
	/**
67
	 *    EE_Session Object
68
	 * @access    public
69
	 * @var    EE_Session $SSN
70
	 */
71
	public $SSN = null;
72
73
	/**
74
	 * holds the ee capabilities object.
75
	 *
76
	 * @since 4.5.0
77
	 *
78
	 * @var EE_Capabilities
79
	 */
80
	public $CAP = null;
81
82
	/**
83
	 *    $addons - StdClass object for holding addons which have registered themselves to work with EE core
84
	 * @access    public
85
	 * @var    EE_Addon[]
86
	 */
87
	public $addons = null;
88
89
	/**
90
	 *    $models
91
	 * @access    public
92
	 * @var    EEM_Base[] $models keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
93
	 */
94
	public $models = array();
95
96
	/**
97
	 *    $modules
98
	 * @access    public
99
	 * @var    EED_Module[] $modules
100
	 */
101
	public $modules = null;
102
103
	/**
104
	 *    $shortcodes
105
	 * @access    public
106
	 * @var    EES_Shortcode[] $shortcodes
107
	 */
108
	public $shortcodes = null;
109
110
	/**
111
	 *    $widgets
112
	 * @access    public
113
	 * @var    WP_Widget[] $widgets
114
	 */
115
	public $widgets = null;
116
117
	/**
118
	 * $non_abstract_db_models
119
	 * @access public
120
	 * @var array this is an array of all implemented model names (i.e. not the parent abstract models, or models
121
	 * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
122
	 * Keys are model "short names" (eg "Event") as used in model relations, and values are
123
	 * classnames (eg "EEM_Event")
124
	 */
125
	public $non_abstract_db_models = array();
126
127
	/**
128
	 *    $i18n_js_strings - internationalization for JS strings
129
	 *    usage:   EE_Registry::i18n_js_strings['string_key'] = __( 'string to translate.', 'event_espresso' );
130
	 *    in js file:  var translatedString = eei18n.string_key;
131
	 *
132
	 * @access    public
133
	 * @var    array
134
	 */
135
	public static $i18n_js_strings = array();
136
137
	/**
138
	 *    $main_file - path to espresso.php
139
	 *
140
	 * @access    public
141
	 * @var    array
142
	 */
143
	public $main_file;
144
145
	/**
146
	 * array of ReflectionClass objects where the key is the class name
147
	 *
148
	 * @access    public
149
	 * @var ReflectionClass[]
150
	 */
151
	public $_reflectors;
152
153
154
155
	/**
156
	 * @singleton method used to instantiate class object
157
	 * @access public
158
	 * @return EE_Registry instance
159
	 */
160
	public static function instance() {
161
		// check if class object is instantiated
162
		if ( ! self::$_instance instanceof EE_Registry ) {
163
			self::$_instance = new self();
164
		}
165
		return self::$_instance;
166
	}
167
168
169
170
	/**
171
	 *protected constructor to prevent direct creation
172
	 * @Constructor
173
	 * @access protected
174
	 * @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...
175
	 */
176
	protected function __construct() {
177
		$this->_class_abbreviations = apply_filters(
178
			'FHEE__EE_Registry____construct___class_abbreviations',
179
			array(
180
				'EE_Config'          	=> 'CFG',
181
				'EE_Session'         	=> 'SSN',
182
				'EE_Capabilities'    	=> 'CAP',
183
				'EE_Cart' 				=> 'CART',
184
				'EE_Network_Config'  	=> 'NET_CFG',
185
				'EE_Request_Handler' 	=> 'REQ',
186
			)
187
		);
188
		$this->_auto_resolve_dependencies = apply_filters(
189
			'FHEE__EE_Registry____construct___auto_resolve_dependencies',
190
			array(
191
				'EE_Session'         	=> array(
192
					'EE_Encryption' => 'load_core'
193
				),
194
				'EE_Cart' 				=> array(
195
					null,
196
					'EE_Session' => 'load_core'
197
				),
198
				'EE_Front_Controller' 	=> array(
199
					'EE_Registry' => 'load_core',
200
					'EE_Request_Handler' => 'load_core',
201
					'EE_Module_Request_Router' => 'load_core'
202
				),
203
				'EE_Messenger_Collection_Loader' 	=> array(
204
					'EE_Messenger_Collection' => 'load_lib'
205
				),
206
				'EE_Message_Type_Collection_Loader' 	=> array(
207
					'EE_Message_Type_Collection' => 'load_lib'
208
				),
209
				'EE_Message_Resource_Manager' 	=> array(
210
					'EE_Messenger_Collection_Loader' => 'load_lib',
211
					'EE_Message_Type_Collection_Loader' => 'load_lib',
212
					'EEM_Message_Template_Group' => 'load_lib'
213
				),
214
				'EE_Message_Factory' 	=> array(
215
					'EE_Message_Resource_Manager' => 'load_lib'
216
				),
217
			)
218
		);
219
		// class library
220
		$this->LIB = new StdClass();
221
		$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...
222
		$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...
223
		$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...
224
		$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...
225
		$this->load_core( 'Base', array(), true );
226
		add_action( 'AHEE__EE_System__set_hooks_for_core', array( $this, 'init' ) );
227
	}
228
229
230
231
	/**
232
	 *    init
233
	 *
234
	 * @access    public
235
	 * @return    void
236
	 */
237
	public function init() {
238
		// Get current page protocol
239
		$protocol = isset( $_SERVER[ 'HTTPS' ] ) ? 'https://' : 'http://';
240
		// Output admin-ajax.php URL with same protocol as current page
241
		self::$i18n_js_strings[ 'ajax_url' ] = admin_url( 'admin-ajax.php', $protocol );
242
		self::$i18n_js_strings[ 'wp_debug' ] = defined( 'WP_DEBUG' ) ? WP_DEBUG : false;
243
	}
244
245
246
247
	/**
248
	 * localize_i18n_js_strings
249
	 *
250
	 * @return string
251
	 */
252
	public static function localize_i18n_js_strings() {
253
		$i18n_js_strings = (array)EE_Registry::$i18n_js_strings;
254
		foreach ( $i18n_js_strings as $key => $value ) {
255
			if ( is_scalar( $value ) ) {
256
				$i18n_js_strings[ $key ] = html_entity_decode( (string)$value, ENT_QUOTES, 'UTF-8' );
257
			}
258
		}
259
260
		return "/* <![CDATA[ */ var eei18n = " . wp_json_encode( $i18n_js_strings ) . '; /* ]]> */';
261
	}
262
263
264
265
	/**
266
	 * @param mixed string | EED_Module $module
267
	 */
268
	public function add_module( $module ) {
269
		if ( $module instanceof EED_Module ) {
270
			$module_class = get_class( $module );
271
			$this->modules->{$module_class} = $module;
272
		} else {
273
			if ( ! class_exists( 'EE_Module_Request_Router' ) ) {
274
				$this->load_core( 'Module_Request_Router' );
275
			}
276
			$this->modules->{$module} = EE_Module_Request_Router::module_factory( $module );
277
		}
278
	}
279
280
281
282
	/**
283
	 * @param string $module_name
284
	 * @return mixed EED_Module | NULL
285
	 */
286
	public function get_module( $module_name = '' ) {
287
		return isset( $this->modules->{$module_name} ) ? $this->modules->{$module_name} : null;
288
	}
289
290
291
292
	/**
293
	 *    loads core classes - must be singletons
294
	 *
295
	 * @access    public
296
	 * @param string $class_name - simple class name ie: session
297
	 * @param mixed $arguments
298
	 * @param bool $load_only
299
	 * @param bool $resolve_dependencies
300
	 * @return mixed
301
	 */
302
	public function load_core( $class_name, $arguments = array(), $load_only = false, $resolve_dependencies = false ) {
303
		$core_paths = apply_filters(
304
			'FHEE__EE_Registry__load_core__core_paths',
305
			array(
306
				EE_CORE,
307
				EE_ADMIN,
308
				EE_CPTS,
309
				EE_CORE . 'data_migration_scripts' . DS
310
			)
311
		);
312
		// retrieve instantiated class
313
		return $this->_load( $core_paths, 'EE_', $class_name, 'core', $arguments, false, true, $load_only, $resolve_dependencies );
314
	}
315
316
317
318
	/**
319
	 *    loads service classes
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_service( $class_name, $arguments = array(), $load_only = false ) {
328
		$service_paths = apply_filters(
329
			'FHEE__EE_Registry__load_service__service_paths',
330
			array(
331
				EE_CORE . 'services' . DS,
332
			)
333
		);
334
		// retrieve instantiated class
335
		return $this->_load( $service_paths, 'EE_', $class_name, 'class', $arguments, false, true, $load_only, true );
336
	}
337
338
339
340
	/**
341
	 *    loads data_migration_scripts
342
	 *
343
	 * @access    public
344
	 * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
345
	 * @param mixed $arguments
346
	 * @return EE_Data_Migration_Script_Base
347
	 */
348
	public function load_dms( $class_name, $arguments = array() ) {
349
		// retrieve instantiated class
350
		return $this->_load( EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(), 'EE_DMS_', $class_name, 'dms', $arguments, false, false, false );
351
	}
352
353
354
355
	/**
356
	 *    loads object creating classes - must be singletons
357
	 *
358
	 * @param string $class_name - simple class name ie: attendee
359
	 * @param mixed $arguments - an array of arguments to pass to the class
360
	 * @param bool $from_db - some classes are instantiated from the db and thus call a different method to instantiate
361
	 * @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)
362
	 * @param bool $load_only whether or not to just load the file and NOT instantiate, or load AND instantiate (default)
363
	 * @return EE_Base_Class
364
	 */
365
	public function load_class( $class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false ) {
366
		$paths = apply_filters( 'FHEE__EE_Registry__load_class__paths', array(
367
			EE_CORE,
368
			EE_CLASSES,
369
			EE_BUSINESS
370
		) );
371
		// retrieve instantiated class
372
		return $this->_load( $paths, 'EE_', $class_name, 'class', $arguments, $from_db, $cache, $load_only );
373
	}
374
375
376
377
	/**
378
	 *    loads helper classes - must be singletons
379
	 *
380
	 * @param string $class_name - simple class name ie: price
381
	 * @param mixed $arguments
382
	 * @param bool $load_only
383
	 * @return EEH_Base
384
	 */
385
	public function load_helper( $class_name, $arguments = array(), $load_only = true ) {
386
		$helper_paths = apply_filters( 'FHEE__EE_Registry__load_helper__helper_paths', array( EE_HELPERS ) );
387
		// retrieve instantiated class
388
		return $this->_load( $helper_paths, 'EEH_', $class_name, 'helper', $arguments, false, true, $load_only );
389
	}
390
391
392
393
	/**
394
	 *    loads core classes - must be singletons
395
	 *
396
	 * @access    public
397
	 * @param string $class_name - simple class name ie: session
398
	 * @param mixed $arguments
399
	 * @param bool $load_only
400
	 * @return mixed
401
	 */
402
	public function load_lib( $class_name, $arguments = array(), $load_only = false ) {
403
		$paths = array(
404
			EE_LIBRARIES,
405
			EE_LIBRARIES . 'messages' . DS,
406
			EE_LIBRARIES . 'shortcodes' . DS,
407
			EE_LIBRARIES . 'qtips' . DS,
408
			EE_LIBRARIES . 'payment_methods' . DS,
409
		);
410
		// retrieve instantiated class
411
		return $this->_load( $paths, 'EE_', $class_name, 'lib', $arguments, false, true, $load_only );
412
	}
413
414
415
416
	/**
417
	 *    loads model classes - must be singletons
418
	 *
419
	 * @param string $class_name - simple class name ie: price
420
	 * @param mixed $arguments
421
	 * @param bool $load_only
422
	 * @return EEM_Base
423
	 */
424
	public function load_model( $class_name, $arguments = array(), $load_only = false ) {
425
		$paths = apply_filters( 'FHEE__EE_Registry__load_model__paths', array(
426
			EE_MODELS,
427
			EE_CORE
428
		) );
429
		// retrieve instantiated class
430
		return $this->_load( $paths, 'EEM_', $class_name, 'model', $arguments, false, true, $load_only );
431
	}
432
433
434
435
	/**
436
	 *    loads model classes - must be singletons
437
	 *
438
	 * @param string $class_name - simple class name ie: price
439
	 * @param mixed $arguments
440
	 * @param bool $load_only
441
	 * @return mixed
442
	 */
443
	public function load_model_class( $class_name, $arguments = array(), $load_only = true ) {
444
		$paths = array(
445
			EE_MODELS . 'fields' . DS,
446
			EE_MODELS . 'helpers' . DS,
447
			EE_MODELS . 'relations' . DS,
448
			EE_MODELS . 'strategies' . DS
449
		);
450
		// retrieve instantiated class
451
		return $this->_load( $paths, 'EE_', $class_name, '', $arguments, false, true, $load_only );
452
	}
453
454
455
456
	/**
457
	 * Determines if $model_name is the name of an actual EE model.
458
	 * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
459
	 * @return boolean
460
	 */
461
	public function is_model_name( $model_name ) {
462
		return isset( $this->models[ $model_name ] ) ? true : false;
463
	}
464
465
466
467
	/**
468
	 *    generic class loader
469
	 *
470
	 * @param string $path_to_file - directory path to file location, not including filename
471
	 * @param string $file_name - file name  ie:  my_file.php, including extension
472
	 * @param string $type - file type - core? class? helper? model?
473
	 * @param mixed $arguments
474
	 * @param bool $load_only
475
	 * @return mixed
476
	 */
477
	public function load_file( $path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true ) {
478
		// retrieve instantiated class
479
		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...
480
	}
481
482
483
484
	/**
485
	 *    load_addon
486
	 *
487
	 * @param string $path_to_file - directory path to file location, not including filename
488
	 * @param string $class_name - full class name  ie:  My_Class
489
	 * @param string $type - file type - core? class? helper? model?
490
	 * @param mixed $arguments
491
	 * @param bool $load_only
492
	 * @return EE_Addon
493
	 */
494
	public function load_addon( $path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false ) {
495
		// retrieve instantiated class
496
		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...
497
	}
498
499
500
501
	/**
502
	 *    loads and tracks classes
503
	 *
504
	 * @param array $file_paths
505
	 * @param string $class_prefix - EE  or EEM or... ???
506
	 * @param bool|string $class_name - $class name
507
	 * @param string $type - file type - core? class? helper? model?
508
	 * @param mixed $arguments - an argument or array of arguments to pass to the class upon instantiation
509
	 * @param bool $from_db - some classes are instantiated from the db and thus call a different method to instantiate
510
	 * @param bool $cache
511
	 * @param bool $load_only
512
	 * @param bool $resolve_dependencies
513
	 * @return null|object
514
	 * @internal param string $file_path - file path including file name
515
	 */
516
	private function _load(
517
		$file_paths = array(),
518
		$class_prefix = 'EE_',
519
		$class_name = false,
520
		$type = 'class',
521
		$arguments = array(),
522
		$from_db = false,
523
		$cache = true,
524
		$load_only = false,
525
		$resolve_dependencies = false
526
	) {
527
		// strip php file extension
528
		$class_name = str_replace( '.php', '', trim( $class_name ) );
529
		// does the class have a prefix ?
530
		if ( ! empty( $class_prefix ) && $class_prefix != 'addon' ) {
531
			// make sure $class_prefix is uppercase
532
			$class_prefix = strtoupper( trim( $class_prefix ) );
533
			// add class prefix ONCE!!!
534
			$class_name = $class_prefix . str_replace( $class_prefix, '', $class_name );
535
		}
536
		// return object if it's already cached
537
		$cached_class = $this->_get_cached_class( $class_name, $class_prefix );
538
		if ( $cached_class !== null ) {
539
			return $cached_class;
540
		}
541
		// get full path to file
542
		$path = $this->_resolve_path( $class_name, $type, $file_paths );
543
		// load the file
544
		$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 542 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...
545
		// instantiate the requested object
546
		$class_obj = $this->_create_object( $class_name, $arguments, $type, $from_db, $load_only, $resolve_dependencies );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $class_obj is correct as $this->_create_object($c... $resolve_dependencies) (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...
547
		// save it for later... kinda like gum  { : $
548
		$this->_set_cached_class( $class_obj, $class_name, $class_prefix, $from_db, $cache );
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...
549
		return $class_obj;
550
	}
551
552
553
554
	/**
555
	 * _get_cached_class
556
	 *
557
	 * attempts to find a cached version of the requested class
558
	 * by looking in the following places:
559
	 * 		$this->{$class_abbreviation} 		 	ie:   	$this->CART
560
	 * 		$this->{$class_name}           		 		ie:    $this->Some_Class
561
	 * 		$this->LIB->{$class_name}				ie: 	$this->LIB->Some_Class
562
	 * 		$this->addon->{$class_name}	ie: 	$this->addon->Some_Addon_Class
563
	 *
564
	 * @access protected
565
	 * @param string $class_name
566
	 * @param string $class_prefix
567
	 * @return null|object
568
	 */
569
	protected function _get_cached_class( $class_name, $class_prefix = '' ) {
570
		if ( isset( $this->_class_abbreviations[ $class_name ] ) ) {
571
			$class_abbreviation = $this->_class_abbreviations[ $class_name ];
572
		} else {
573
			// have to specify something, but not anything that will conflict
574
			$class_abbreviation = 'FANCY_BATMAN_PANTS';
575
		}
576
		// check if class has already been loaded, and return it if it has been
577
		if ( isset( $this->{$class_abbreviation} ) && ! is_null( $this->{$class_abbreviation} ) ) {
578
			return $this->{$class_abbreviation};
579
		} else if ( isset ( $this->{$class_name} ) ) {
580
			return $this->{$class_name};
581
		} else if ( isset ( $this->LIB->{$class_name} ) ) {
582
			return $this->LIB->{$class_name};
583
		} else if ( $class_prefix == 'addon' && isset ( $this->addons->{$class_name} ) ) {
584
			return $this->addons->{$class_name};
585
		}
586
		return null;
587
	}
588
589
590
591
	/**
592
	 * _resolve_path
593
	 *
594
	 * attempts to find a full valid filepath for the requested class.
595
	 * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
596
	 * then returns that path if the target file has been found and is readable
597
	 *
598
	 * @access protected
599
	 * @param string $class_name
600
	 * @param string $type
601
	 * @param array $file_paths
602
	 * @return string | bool
603
	 */
604
	protected function _resolve_path( $class_name, $type = '', $file_paths = array() ) {
605
		// make sure $file_paths is an array
606
		$file_paths = is_array( $file_paths ) ? $file_paths : array( $file_paths );
607
		// cycle thru paths
608
		foreach ( $file_paths as $key => $file_path ) {
609
			// convert all separators to proper DS, if no filepath, then use EE_CLASSES
610
			$file_path = $file_path ? str_replace( array( '/', '\\' ), DS, $file_path ) : EE_CLASSES;
611
			// prep file type
612
			$type = ! empty( $type ) ? trim( $type, '.' ) . '.' : '';
613
			// build full file path
614
			$file_paths[ $key ] = rtrim( $file_path, DS ) . DS . $class_name . '.' . $type . 'php';
615
			//does the file exist and can be read ?
616
			if ( is_readable( $file_paths[ $key ] ) ) {
617
				return $file_paths[ $key ];
618
			}
619
		}
620
		return false;
621
	}
622
623
624
625
	/**
626
	 * _require_file
627
	 *
628
	 * basically just performs a require_once()
629
	 * but with some error handling
630
	 *
631
	 * @access protected
632
	 * @param string $path
633
	 * @param string $class_name
634
	 * @param string $type
635
	 * @param array $file_paths
636
	 * @return void
637
	 * @throws \EE_Error
638
	 */
639
	protected function _require_file( $path, $class_name, $type = '', $file_paths = array() ) {
640
		// don't give up! you gotta...
641
		try {
642
			//does the file exist and can it be read ?
643 View Code Duplication
			if ( ! $path ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
644
				// so sorry, can't find the file
645
				throw new EE_Error (
646
					sprintf(
647
						__( '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' ),
648
						trim( $type, '.' ),
649
						$class_name,
650
						'<br />' . implode( ',<br />', $file_paths )
651
					)
652
				);
653
			}
654
			// get the file
655
			require_once( $path );
656
			// if the class isn't already declared somewhere
657 View Code Duplication
			if ( class_exists( $class_name, false ) === false ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
658
				// so sorry, not a class
659
				throw new EE_Error(
660
					sprintf(
661
						__( 'The %s file %s does not appear to contain the %s Class.', 'event_espresso' ),
662
						$type,
663
						$path,
664
						$class_name
665
					)
666
				);
667
			}
668
669
		} catch ( EE_Error $e ) {
670
			$e->get_error();
671
		}
672
	}
673
674
675
676
	/**
677
	 * _create_object
678
	 * Attempts to instantiate the requested class via any of the
679
	 * commonly used instantiation methods employed throughout EE.
680
	 * The priority for instantiation is as follows:
681
	 * 		- abstract classes or any class flagged as "load only" (no instantiation occurs)
682
	 * 	 	- model objects via their 'new_instance_from_db' method
683
	 * 	 	- model objects via their 'new_instance' method
684
	 * 	 	- "singleton" classes" via their 'instance' method
685
	 *  	- standard instantiable classes via their __constructor
686
	 * Prior to instantiation, if the $resolve_dependencies flag is set to true,
687
	 * then the constructor for the requested class will be examined to determine
688
	 * if any dependencies exist, and if they can be injected.
689
	 * If so, then those classes will be added to the array of arguments passed to the constructor
690
	 *
691
	 * @access protected
692
	 * @param string $class_name
693
	 * @param array $arguments
694
	 * @param string $type
695
	 * @param bool $from_db
696
	 * @param bool $load_only
697
	 * @param bool $resolve_dependencies
698
	 * @return null | object
699
	 * @throws \EE_Error
700
	 */
701
	protected function _create_object( $class_name, $arguments = array(), $type = '', $from_db = false, $load_only = false, $resolve_dependencies = true ) {
702
		$class_obj = null;
703
		$resolve_dependencies = isset( $this->_auto_resolve_dependencies[ $class_name ] ) /*&& empty( $arguments )*/ ? true : $resolve_dependencies;
704
		// don't give up! you gotta...
705
		try {
706
			// create reflection
707
			$reflector = $this->get_ReflectionClass( $class_name );
708
			// make sure arguments are an array
709
			$arguments = is_array( $arguments ) ? $arguments : array( $arguments );
710
			// and if arguments array is NOT numerically indexed, then we want it to stay as an array,
711
			// so wrap it in an additional array so that it doesn't get split into multiple parameters
712
			$arguments = isset( $arguments[ 0 ] ) ? $arguments : array( $arguments );
713
			// attempt to inject dependencies ?
714
			if ( $resolve_dependencies && ! $from_db && ! $load_only && ! $reflector->isSubclassOf( 'EE_Base_Class' ) ) {
715
				$arguments = $this->_resolve_dependencies( $reflector, $class_name, $arguments );
716
			}
717
			// instantiate the class and add to the LIB array for tracking
718
			// EE_Base_Classes are instantiated via new_instance by default (models call them via new_instance_from_db)
719
			if ( $reflector->getConstructor() === null || $reflector->isAbstract() || $load_only ) {
720
				// no constructor = static methods only... nothing to instantiate, loading file was enough
721
				//$instantiation_mode = "no constructor";
722
				return true;
723
			} else if ( $from_db && method_exists( $class_name, 'new_instance_from_db' ) ) {
724
				//$instantiation_mode = "new_instance_from_db";
725
				$class_obj = call_user_func_array( array( $class_name, 'new_instance_from_db' ), $arguments );
726
			} else if ( method_exists( $class_name, 'new_instance' ) ) {
727
				//$instantiation_mode = "new_instance";
728
				$class_obj = call_user_func_array( array( $class_name, 'new_instance' ), $arguments );
729
			} else if ( method_exists( $class_name, 'instance' ) ) {
730
				//$instantiation_mode = "instance";
731
				$class_obj = call_user_func_array( array( $class_name, 'instance' ), $arguments );
732
			} else if ( $reflector->isInstantiable() ) {
733
				//$instantiation_mode = "isInstantiable";
734
				$class_obj = $reflector->newInstanceArgs( $arguments );
735
			} else if ( ! $load_only ) {
736
				// heh ? something's not right !
737
				//$instantiation_mode = 'none';
738
				throw new EE_Error(
739
					sprintf(
740
						__( 'The %s file %s could not be instantiated.', 'event_espresso' ),
741
						$type,
742
						$class_name
743
					)
744
				);
745
			}
746
		} catch ( EE_Error $e ) {
747
			$e->get_error();
748
		}
749
		return $class_obj;
750
	}
751
752
753
754
	/**
755
	 * getReflectionClass
756
	 *
757
	 * checks if a ReflectionClass object has already been generated for a class
758
	 * and returns that instead of creating a new one
759
	 *
760
	 * @access public
761
	 * @param string $class_name
762
	 * @return ReflectionClass
763
	 */
764
	public function get_ReflectionClass( $class_name ) {
765
		if (
766
			! isset( $this->_reflectors[ $class_name ] )
767
			|| ! $this->_reflectors[ $class_name ] instanceof ReflectionClass
768
		) {
769
			$this->_reflectors[ $class_name ] = new ReflectionClass( $class_name );
770
		}
771
		return $this->_reflectors[ $class_name ];
772
	}
773
774
775
776
	/**
777
	 * _resolve_dependencies
778
	 *
779
	 * examines the constructor for the requested class to determine
780
	 * if any dependencies exist, and if they can be injected.
781
	 * If so, then those classes will be added to the array of arguments passed to the constructor
782
	 * PLZ NOTE: this is achieved by type hinting the constructor params
783
	 * For example:
784
	 * 		if attempting to load a class "Foo" with the following constructor:
785
	 *        __construct( Bar $bar_class, Fighter $grohl_class )
786
	 * 		then $bar_class and $grohl_class will be added to the $arguments array,
787
	 * 		but only IF they are NOT already present in the incoming arguments array,
788
	 * 		and the correct classes can be loaded
789
	 *
790
	 * @access protected
791
	 * @param ReflectionClass $reflector
792
	 * @param string $class_name
793
	 * @param array $arguments
794
	 * @return array
795
	 */
796
	protected function _resolve_dependencies( ReflectionClass $reflector, $class_name, $arguments = array() ) {
797
		// let's examine the constructor
798
		$constructor = $reflector->getConstructor();
799
		// whu? huh? nothing?
800
		if ( ! $constructor ) {
801
			return $arguments;
802
		}
803
		// get constructor parameters
804
		$params = $constructor->getParameters();
805
		// and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
806
		$argument_keys = array_keys( $arguments );
807
		// now loop thru all of the constructors expected parameters
808
		foreach ( $params as $index => $param ) {
809
			// is this a dependency for a specific class ?
810
			$param_class = $param->getClass() ? $param->getClass()->name : null;
811
			if (
812
				// param is not even a class
813
				$param_class === null ||
814
				(
815
					// something already exists in the incoming arguments for this param
816
					isset( $argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ] )
817
					// AND it's the correct class
818
					&& $arguments[ $argument_keys[ $index ] ] instanceof $param_class
819
				)
820
821
			) {
822
				// so let's skip this argument and move on to the next
823
				continue;
824
			} else if (
825
				isset( $this->_auto_resolve_dependencies[ $class_name ] )
826
				&& isset( $this->_auto_resolve_dependencies[ $class_name ][ $param_class ] )
827
			) {
828
				// we might have a dependency... let's try and find it in our cache
829
				$cached_class = $this->_get_cached_class( $param_class );
830
				$dependency = null;
831
				// and grab it if it exists
832
				if ( $cached_class instanceof $param_class ) {
833
					$dependency = $cached_class;
834
				} else if ( $param_class != $class_name ) {
835
					$loader = $this->_auto_resolve_dependencies[ $class_name ][ $param_class ];
836
					// or if not cached, then let's try and load it directly
837
					$core_class = $this->$loader( $param_class );
838
					// as long as we aren't creating some recursive loading loop
839
					if ( $core_class instanceof $param_class ) {
840
						$dependency = $core_class;
841
					}
842
				}
843
				// did we successfully find the correct dependency ?
844
				if ( $dependency instanceof $param_class ) {
845
					// then let's inject it into the incoming array of arguments at the correct location
846
					array_splice( $arguments, $index, 1, array( $dependency ) );
847
				}
848
			} else {
849
				$arguments[ $index ] = null;
850
			}
851
852
		}
853
		return $arguments;
854
	}
855
856
857
858
	/**
859
	 * _set_cached_class
860
	 *
861
	 * attempts to cache the instantiated class locally
862
	 * in one of the following places, in the following order:
863
	 *        $this->{class_abbreviation} 			ie:    $this->CART
864
	 *        $this->{$class_name}                    	ie:    $this->Some_Class
865
	 *        $this->addon->{$$class_name} 	ie:    $this->addon->Some_Addon_Class
866
	 *        $this->LIB->{$class_name} + 		ie:    $this->LIB->Some_Class +
867
	 * 		+ only classes that are NOT model objects with the $cache flag set to true
868
	 * 	 	will be cached under LIB (libraries)
869
	 *
870
	 * @access protected
871
	 * @param object $class_obj
872
	 * @param string $class_name
873
	 * @param string $class_prefix
874
	 * @param bool $from_db
875
	 * @param bool $cache
876
	 * @return void
877
	 */
878
	protected function _set_cached_class( $class_obj, $class_name, $class_prefix = '', $from_db = false, $cache = true ) {
879
		// return newly instantiated class
880
		if ( isset( $this->_class_abbreviations[ $class_name ] ) ) {
881
			$class_abbreviation = $this->_class_abbreviations[ $class_name ];
882
			$this->{$class_abbreviation} = $class_obj;
883
		} else if ( property_exists( $this, $class_name ) ) {
884
			$this->{$class_name} = $class_obj;
885
		} else if ( $class_prefix == 'addon' && $cache ) {
886
			$this->addons->{$class_name} = $class_obj;
887
		} else if ( ! $from_db && $cache ) {
888
			$this->LIB->{$class_name} = $class_obj;
889
		}
890
	}
891
892
893
894
	/**
895
	 * Gets the addon by its name/slug (not classname. For that, just
896
	 * use the classname as the property name on EE_Config::instance()->addons)
897
	 * @param string $name
898
	 * @return EE_Addon
899
	 */
900
	public function get_addon_by_name( $name ) {
901
		foreach ( $this->addons as $addon ) {
902
			if ( $addon->name() == $name ) {
903
				return $addon;
904
			}
905
		}
906
		return null;
907
	}
908
909
910
911
	/**
912
	 * 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}
913
	 *
914
	 * @return EE_Addon[] where the KEYS are the addon's name()
915
	 */
916
	public function get_addons_by_name() {
917
		$addons = array();
918
		foreach ( $this->addons as $addon ) {
919
			$addons[ $addon->name() ] = $addon;
920
		}
921
		return $addons;
922
	}
923
924
925
926
	/**
927
	 * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
928
	 * a stale copy of it around
929
	 *
930
	 * @param string $model_name
931
	 * @return \EEM_Base
932
	 * @throws \EE_Error
933
	 */
934
	public function reset_model( $model_name ) {
935
		$model = $this->load_model( $model_name );
936
		$model_class_name = get_class( $model );
937
		//get that model reset it and make sure we nuke the old reference to it
938
		if ( $model instanceof $model_class_name && is_callable( array( $model_class_name, 'reset' ))) {
939
			$this->LIB->$model_class_name = $model::reset();
940
		} else {
941
			throw new EE_Error( sprintf( __( 'Model %s does not have a method "reset"', 'event_espresso' ), $model_name ) );
942
		}
943
		return $this->LIB->$model_class_name;
944
	}
945
946
947
948
	/**
949
	 * Resets the registry and everything in it (eventually, getting it to properly
950
	 * reset absolutely everything will probably be tricky. right now it just resets
951
	 * the config, data migration manager, and the models)
952
	 * @param boolean $hard whether to reset data in the database too, or just refresh
953
	 * the Registry to its state at the beginning of the request
954
	 * @param boolean $reinstantiate whether to create new instances of EE_Registry's singletons too,
955
	 * or just reset without re-instantiating (handy to set to FALSE if you're not sure if you CAN
956
	 * currently reinstantiate the singletons at the moment)
957
	 * @return EE_Registry
958
	 */
959
	public static function reset( $hard = false, $reinstantiate = true ) {
960
		$instance = self::instance();
961
		$instance->load_helper( 'Activation' );
962
		EEH_Activation::reset();
963
		$instance->CFG = EE_Config::reset( $hard, $reinstantiate );
964
		$instance->LIB->EE_Data_Migration_Manager = EE_Data_Migration_Manager::reset();
965
		$instance->LIB = new stdClass();
966
		foreach ( array_keys( $instance->non_abstract_db_models ) as $model_name ) {
967
			$instance->reset_model( $model_name );
968
		}
969
		return $instance;
970
	}
971
972
973
974
	/**
975
	 * @override magic methods
976
	 * @return void
977
	 */
978
	final function __destruct() {
979
	}
980
981
982
983
	/**
984
	 * @param $a
985
	 * @param $b
986
	 */
987
	final function __call( $a, $b ) {
988
	}
989
990
991
992
	/**
993
	 * @param $a
994
	 */
995
	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...
996
	}
997
998
999
1000
	/**
1001
	 * @param $a
1002
	 * @param $b
1003
	 */
1004
	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...
1005
	}
1006
1007
1008
1009
	/**
1010
	 * @param $a
1011
	 */
1012
	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...
1013
	}
1014
1015
1016
1017
	/**
1018
	 * @param $a
1019
	 */
1020
	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...
1021
	}
1022
1023
1024
1025
	/**
1026
	 * @return array
1027
	 */
1028
	final function __sleep() {
1029
		return array();
1030
	}
1031
1032
1033
1034
	final function __wakeup() {
1035
	}
1036
1037
1038
1039
	/**
1040
	 * @return string
1041
	 */
1042
	final function __toString() {
1043
		return '';
1044
	}
1045
1046
1047
1048
	final function __invoke() {
1049
	}
1050
1051
1052
1053
	final function __set_state() {
1054
	}
1055
1056
1057
1058
	final function __clone() {
1059
	}
1060
1061
1062
1063
	/**
1064
	 * @param $a
1065
	 * @param $b
1066
	 */
1067
	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...
1068
	}
1069
1070
	/**
1071
	 * Gets all the custom post type models defined
1072
	 * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1073
	 */
1074
	public function cpt_models() {
1075
		$cpt_models = array();
1076
		foreach( $this->non_abstract_db_models as $short_name => $classname ) {
1077
			if( is_subclass_of(  $classname, 'EEM_CPT_Base' ) ) {
1078
				$cpt_models[ $short_name ] = $classname;
1079
			}
1080
		}
1081
		return $cpt_models;
1082
	}
1083
1084
1085
1086
}
1087
// End of file EE_Registry.core.php
1088
// Location: ./core/EE_Registry.core.php
1089