Completed
Branch FET-9046-messages-queue (bdca24)
by
unknown
547:25 queued 529:16
created

EE_Registry::__construct()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 21

Duplication

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