Completed
Push — milestone/2_0/react-ui ( 6ff089...f420b0 )
by
unknown
05:40
created

Carbon_Fields::is_booted()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
3
namespace Carbon_Fields;
4
5
use Carbon_Fields\Pimple\Container as PimpleContainer;
6
use Carbon_Fields\Helper\Helper;
7
use Carbon_Fields\Loader\Loader;
8
use Carbon_Fields\Container\Repository as ContainerRepository;
9
use Carbon_Fields\Toolset\Key_Toolset;
10
use Carbon_Fields\Toolset\WP_Toolset;
11
use Carbon_Fields\Service\Meta_Query_Service;
12
use Carbon_Fields\Service\Legacy_Storage_Service_v_1_5;
13
use Carbon_Fields\Service\REST_API_Service;
14
use Carbon_Fields\Libraries\Sidebar_Manager\Sidebar_Manager;
15
16
use Carbon_Fields\REST_API\Router as REST_API_Router;
17
use Carbon_Fields\REST_API\Decorator as REST_API_Decorator;
18
19
use Carbon_Fields\Event\Emitter;
20
use Carbon_Fields\Event\PersistentListener;
21
use Carbon_Fields\Event\SingleEventListener;
22
23
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
24
25
/**
26
 * Holds a static reference to the ioc container
27
 */
28
final class Carbon_Fields {
29
30
	/**
31
	 * An event emitter to facilitate events before the WordPress environment is guaranteed to be loaded
32
	 * 
33
	 * @var Emitter
34
	 */
35
	protected $emitter;
36
37
	/**
38
	 * Flag if Carbon Fields has been booted
39
	 * 
40
	 * @var bool
41
	 */
42
	public $booted = false;
43
44
	/**
45
	 * Inversion of Control container instance
46
	 * 
47
	 * @var PimpleContainer
48
	 */
49
	public $ioc = null;
50
51
	/**
52
	 * Singleton implementation
53
	 *
54
	 * @return Carbon_Fields\Carbon_Fields
55
	 */
56
	public static function instance() {
57
		static $instance = null;
58
		if ( $instance === null ) {
59
			$instance = new static();
60
		}
61
		return $instance;
62
	}
63
64
	/**
65
	 * Constructor
66
	 */
67
	private function __construct() {
68
		$this->install( $this->get_default_ioc() );
69
	}
70
71
	/**
72
	 * Resolve a dependency through IoC
73
	 *
74
	 * @param  string      $key
75
	 * @param  string|null $subcontainer Subcontainer to look into
76
	 * @return mixed
77
	 */
78 View Code Duplication
	public static function resolve( $key, $subcontainer = null ) {
79
		$ioc = static::instance()->ioc;
80
		if ( $subcontainer !== null ) {
81
			if ( ! isset( $ioc[ $subcontainer ] ) ) {
82
				return null;
83
			}
84
			$ioc = $ioc[ $subcontainer ];
85
		}
86
		return $ioc[ $key ];
87
	}
88
89
	/**
90
	 * Resolve a dependency through IoC with arguments
91
	 *
92
	 * @param  string $identifier   Key to resolve from the container
93
	 * @param  array  $arguments    Key-value array of arguments
94
	 * @param  string $subcontainer The container to resolve from
95
	 * @return mixed
96
	 */
97
	public static function resolve_with_arguments( $identifier, $arguments, $subcontainer = null ) {
98
		$supercontainer = $subcontainer ? static::resolve( $subcontainer ) : static::instance()->ioc;
99
		$container = new PimpleContainer();
100
		$container['container'] = $supercontainer;
101
		$container['arguments'] = $arguments;
102
		$container['object'] = $supercontainer->raw( $identifier );
103
		return $container['object'];
104
	}
105
106
	/**
107
	 * Resolve a service through IoC
108
	 *
109
	 * @param string $service_name
110
	 * @return mixed
111
	 */
112
	public static function service( $service_name ) {
113
		return static::resolve( $service_name, 'services' );
114
	}
115
116
	/**
117
	 * Check if a dependency is registered
118
	 *
119
	 * @param  string      $key
120
	 * @param  string|null $subcontainer Subcontainer to look into
121
	 * @return bool
122
	 */
123 View Code Duplication
	public static function has( $key, $subcontainer = null ) {
124
		$ioc = static::instance()->ioc;
125
		if ( $subcontainer !== null ) {
126
			if ( ! isset( $ioc[ $subcontainer ] ) ) {
127
				return false;
128
			}
129
			$ioc = $ioc[ $subcontainer ];
130
		}
131
		return isset( $ioc[ $key ] );
132
	}
133
134
	/**
135
	 * Extend Carbon Fields by adding a new entity (container condition etc.)
136
	 *
137
	 * @param string $class    Extension class name
138
	 * @param string $extender Extending callable
139
	 */
140
	public static function extend( $class, $extender ) {
141
		$type_dictionary = array(
142
			'_Field' => 'fields',
143
			'_Condition' => 'container_conditions',
144
		);
145
146
		$extension_suffix = '';
147
		$extension_subcontainer = '';
148
		foreach ( $type_dictionary as $suffix => $subcontainer ) {
149
			if ( substr( $class, -strlen( $suffix ) ) === $suffix ) {
150
				$extension_suffix = $suffix;
151
				$extension_subcontainer = $subcontainer;
152
			}
153
		}
154
155
		if ( empty( $extension_suffix ) ) {
156
			Incorrect_Syntax_Exception::raise( 'Could not determine "' . $class . '" extension type. Extension classes must have one of the following suffixes: ' . implode( ', ', array_keys( $type_dictionary ) ) );
157
			return;
158
		}
159
160
		$identifier = Helper::class_to_type( $class, $extension_suffix );
161
		$ioc = static::instance()->ioc[ $extension_subcontainer ];
162
		$ioc[ $identifier ] = $ioc->factory( $extender );
163
	}
164
165
	/**
166
	 * Replace the ioc container for Carbon_Fields\Carbon_Fields
167
	 * 
168
	 * @param  PimpleContainer $ioc
169
	 */
170
	public function install( PimpleContainer $ioc ) {
171
		$this->ioc = $ioc;
172
	}
173
174
	/**
175
	 * Boot Carbon Fields with default IoC dependencies
176
	 */
177
	public static function boot() {
178
		if ( static::is_booted() ) {
179
			return;
180
		}
181
182
		if ( defined( __NAMESPACE__ . '\VERSION' ) ) {
183
			return; // Possibly attempting to load multiple versions of Carbon Fields; bail in favor of already loaded version
184
		}
185
186
		static::resolve( 'loader' )->boot();
187
		static::instance()->booted = true;
188
		static::instance()->get_emitter()->emit( 'loaded' );
189
		do_action( 'carbon_fields_loaded' );
190
	}
191
192
	/**
193
	 * Check if Carbon Fields has booted
194
	 */
195
	public static function is_booted() {
196
		return static::instance()->booted;
197
	}
198
199
	/**
200
	 * Throw exception if Carbon Fields has not been booted
201
	 */
202
	public static function verify_boot() {
203
		if ( ! static::is_booted() ) {
204
			throw new \Exception( 'You must call Carbon_Fields\Carbon_Fields::boot() in a suitable WordPress hook before using Carbon Fields.' );
205
		}
206
	}
207
208
	/**
209
	 * Resolve the public url of a directory inside WordPress
210
	 * 
211
	 * @param  string $directory
212
	 * @return string
213
	 */
214
	public static function directory_to_url( $directory ) {
215
		$url = \trailingslashit( $directory );
216
		$count = 0;
217
218
		# Sanitize directory separator on Windows
219
		$url = str_replace( '\\' ,'/', $url );
220
221
		$possible_locations = array(
222
			WP_PLUGIN_DIR => \plugins_url(), # If installed as a plugin
223
			WP_CONTENT_DIR => \content_url(), # If anywhere in wp-content
224
			ABSPATH => \site_url( '/' ), # If anywhere else within the WordPress installation
225
		);
226
227
		foreach ( $possible_locations as $test_dir => $test_url ) {
228
			$test_dir_normalized = str_replace( '\\' ,'/', $test_dir );
229
			$url = str_replace( $test_dir_normalized, $test_url, $url, $count );
230
231
			if ( $count > 0 ) {
232
				break;
233
			}
234
		}
235
236
		return \untrailingslashit( $url );
237
	}
238
239
	/**
240
	 * Get the event emitter
241
	 * 
242
	 * @return Emitter
243
	 */
244
	public function get_emitter() {
245
		if ( $this->emitter === null ) {
246
			$this->emitter = static::resolve( 'event_emitter' );
247
		}
248
		return $this->emitter;
249
	}
250
251
	/**
252
	 * Add a listener to an event
253
	 * 
254
	 * @param string   $event
255
	 * @return Listener $listener
256
	 */
257
	public static function add_listener( $event, $listener ) {
258
		return static::instance()->get_emitter()->add_listener( $event, $listener );
259
	}
260
261
	/**
262
	 * Remove a listener from any event
263
	 * 
264
	 * @param Listener $listener
265
	 */
266
	public static function remove_listener( $listener ) {
267
		static::instance()->get_emitter()->remove_listener( $listener );
268
	}
269
270
	/**
271
	 * Add a persistent listener to an event
272
	 * 
273
	 * @param  string   $event    The event to listen for
274
	 * @param  string   $callable The callable to call when the event is broadcasted
275
	 * @return Listener
276
	 */
277
	public static function on( $event, $callable ) {
278
		return static::instance()->get_emitter()->on( $event, $callable );
279
	}
280
281
	/**
282
	 * Add a one-time listener to an event
283
	 *
284
	 * @param  string   $event    The event to listen for
285
	 * @param  string   $callable The callable to call when the event is broadcasted
286
	 * @return Listener
287
	 */
288
	public static function once( $event, $callable ) {
289
		return static::instance()->get_emitter()->once( $event, $callable );
290
	}
291
292
	/**
293
	 * Get default IoC container dependencies
294
	 * 
295
	 * @return PimpleContainer
296
	 */
297
	protected static function get_default_ioc() {
298
		$ioc = new PimpleContainer();
299
300
		$ioc['loader'] = function( $ioc ) {
301
			return new Loader( $ioc['sidebar_manager'], $ioc['container_repository'] );
302
		};
303
304
		$ioc['container_repository'] = function() {
305
			return new ContainerRepository();
306
		};
307
308
		$ioc['fields'] = function() {
309
			return new PimpleContainer();
310
		};
311
312
		$ioc['key_toolset'] = function() {
313
			return new Key_Toolset();
314
		};
315
316
		$ioc['wp_toolset'] = function() {
317
			return new WP_Toolset();
318
		};
319
320
		$ioc['sidebar_manager'] = function() {
321
			return new Sidebar_Manager();
322
		};
323
324
		$ioc['rest_api_router'] = function( $ioc ) {
325
			return new REST_API_Router( $ioc['container_repository'] );
326
		};
327
328
		$ioc['rest_api_decorator'] = function( $ioc ) {
329
			return new REST_API_Decorator( $ioc['container_repository'] );
330
		};
331
332
		/* Services */
333
		$ioc['services'] = function() {
334
			return new PimpleContainer();
335
		};
336
337
		$ioc['services']['meta_query'] = function() use ( $ioc ) {
338
			return new Meta_Query_Service( $ioc['container_repository'], $ioc['key_toolset'] );
339
		};
340
341
		$ioc['services']['legacy_storage'] = function() use ( $ioc ) {
342
			return new Legacy_Storage_Service_v_1_5( $ioc['container_repository'], $ioc['key_toolset'] );
343
		};
344
345
		$ioc['services']['rest_api'] = function() use ( $ioc ) {
346
			return new REST_API_Service( $ioc['rest_api_router'], $ioc['rest_api_decorator'] );
347
		};
348
349
		/* Events */
350
		$ioc['event_emitter'] = function() {
351
			return new Emitter();
352
		};
353
354
		$ioc['event_persistent_listener'] = function() {
355
			return new PersistentListener();
356
		};
357
358
		$ioc['event_single_event_listener'] = function() {
359
			return new SingleEventListener();
360
		};
361
362
		$ioc->register( new \Carbon_Fields\Provider\Container_Condition_Provider() );
363
364
		return $ioc;
365
	}
366
}