DependencyManager   C
last analyzed

Complexity

Total Complexity 57

Size/Duplication

Total Lines 472
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 57
lcom 1
cbo 2
dl 0
loc 472
ccs 0
cts 121
cp 0
rs 5.04
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A init_handlers() 0 8 3
A add_handler() 0 10 4
A get_default_handler() 0 10 3
A init_dependencies() 0 8 2
A init_dependency_type() 0 10 3
A register() 0 5 1
A validate_context() 0 6 2
A enqueue() 0 6 1
A enqueue_handle() 0 6 2
A enqueue_internal_handle() 0 26 5
A get_dependency_array() 0 9 3
A enqueue_dependency() 0 14 5
A is_needed() 0 11 4
A maybe_localize() 0 16 4
A maybe_add_inline_script() 0 13 3
A enqueue_fallback_handle() 0 7 3
A enqueue_dependency_type() 0 4 1
A register_dependency_type() 0 4 1
A register_dependency() 0 8 2
A register_enqueue_hooks() 0 10 2
A get_priority() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like DependencyManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DependencyManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Bright Nucleus Dependency Component.
4
 *
5
 * @package   BrightNucleus\Dependency
6
 * @author    Alain Schlesser <[email protected]>
7
 * @license   MIT
8
 * @link      http://www.brightnucleus.com/
9
 * @copyright 2015-2016 Alain Schlesser, Bright Nucleus
10
 */
11
12
namespace BrightNucleus\Dependency;
13
14
use BrightNucleus\Config\ConfigInterface;
15
use BrightNucleus\Config\ConfigTrait;
16
use BrightNucleus\Exception\InvalidArgumentException;
17
use BrightNucleus\Exception\RuntimeException;
18
19
/**
20
 * Class DependencyManager.
21
 *
22
 * Register and enqueue dependencies that are listed in the config file.
23
 *
24
 * @since   0.1.0
25
 *
26
 * @package BrightNucleus\Dependency
27
 * @author  Alain Schlesser <[email protected]>
28
 */
29
class DependencyManager implements DependencyManagerInterface {
30
31
	use ConfigTrait;
32
33
	/*
34
	 * Default dependency handler implementations.
35
	 */
36
	const DEFAULT_SCRIPT_HANDLER = '\BrightNucleus\Dependency\ScriptHandler';
37
	const DEFAULT_STYLE_HANDLER  = '\BrightNucleus\Dependency\StyleHandler';
38
39
	/*
40
	 * Names of the configuration keys.
41
	 */
42
	const KEY_HANDLERS = 'handlers';
43
	const KEY_SCRIPTS  = 'scripts';
44
	const KEY_STYLES   = 'styles';
45
46
	/**
47
	 * Hold the dependencies, grouped by type.
48
	 *
49
	 * @since 0.1.0
50
	 *
51
	 * @var array;
52
	 */
53
	protected $dependencies = [ ];
54
55
	/**
56
	 * Hold the handlers.
57
	 *
58
	 * @since 0.1.0
59
	 *
60
	 * @var DependencyHandlerInterface[]
61
	 */
62
	protected $handlers = [ ];
63
64
	/**
65
	 * Whether to enqueue immediately upon registration.
66
	 *
67
	 * @since 0.2.2
68
	 *
69
	 * @var bool
70
	 */
71
	protected $enqueue_immediately;
72
73
	/**
74
	 * Instantiate DependencyManager object.
75
	 *
76
	 * @since 0.1.0
77
	 *
78
	 * @param ConfigInterface $config   ConfigInterface object that contains
79
	 *                                  dependency settings.
80
	 * @param bool            $enqueue  Optional. Whether to enqueue
81
	 *                                  immediately. Defaults to true.
82
	 * @throws RuntimeException If the config could not be processed.
83
	 * @throws InvalidArgumentException If no dependency handlers were
84
	 *                                  specified.
85
	 */
86
	public function __construct( ConfigInterface $config, $enqueue = true ) {
87
		$this->processConfig( $config );
88
		$this->enqueue_immediately = $enqueue;
89
		$this->init_handlers();
90
		$this->init_dependencies();
91
	}
92
93
	/**
94
	 * Initialize the dependency handlers.
95
	 *
96
	 * @since 0.1.0
97
	 */
98
	protected function init_handlers() {
99
		$keys = [ self::KEY_SCRIPTS, self::KEY_STYLES ];
100
		foreach ( $keys as $key ) {
101
			if ( $this->hasConfigKey( $key ) ) {
102
				$this->add_handler( $key );
103
			}
104
		}
105
	}
106
107
	/**
108
	 * Add a single dependency handler.
109
	 *
110
	 * @since 0.1.0
111
	 *
112
	 * @param string $dependency The dependency type for which to add a handler.
113
	 */
114
	protected function add_handler( $dependency ) {
115
		if ( $this->hasConfigKey( $dependency ) ) {
116
			$handler = $this->hasConfigKey( self::KEY_HANDLERS, $dependency )
117
				? $this->getConfigKey( self::KEY_HANDLERS, $dependency )
118
				: $this->get_default_handler( $dependency );
119
			if ( $handler ) {
120
				$this->handlers[ $dependency ] = new $handler;
121
			}
122
		}
123
	}
124
125
	/**
126
	 * Get the default handler class for a given type of dependency.
127
	 *
128
	 * @since 0.1.0
129
	 *
130
	 * @param string $dependency The dependency that needs a handler.
131
	 * @return string|null Class name of the handler. Null if none.
132
	 */
133
	protected function get_default_handler( $dependency ) {
134
		switch ( $dependency ) {
135
			case self::KEY_STYLES:
136
				return self::DEFAULT_STYLE_HANDLER;
137
			case self::KEY_SCRIPTS:
138
				return self::DEFAULT_SCRIPT_HANDLER;
139
			default:
140
				return null;
141
		}
142
	}
143
144
	/**
145
	 * Initialize the actual dependencies.
146
	 *
147
	 * @since 0.1.0
148
	 */
149
	protected function init_dependencies() {
150
		array_walk( $this->handlers,
151
			function ( $handler, $dependency_type ) {
152
				if ( $this->hasConfigKey( $dependency_type ) ) {
153
					$this->dependencies[ $dependency_type ] = $this->init_dependency_type( $dependency_type );
154
				}
155
			} );
156
	}
157
158
	/**
159
	 * Initialize the dependencies of a given type.
160
	 *
161
	 * @since 0.2.2
162
	 *
163
	 * @param string $type The type of dependency to initialize.
164
	 * @return array Array of dependency configurations.
165
	 */
166
	protected function init_dependency_type( $type ) {
167
		$array = [ ];
168
		$data  = $this->getConfigKey( $type );
169
		foreach ( $data as $dependency ) {
170
			$handle           = array_key_exists( 'handle',
171
				$dependency ) ? $dependency['handle'] : '';
172
			$array[ $handle ] = $dependency;
173
		}
174
		return $array;
175
	}
176
177
	/**
178
	 * Register all dependencies.
179
	 *
180
	 * @since 0.1.0
181
	 *
182
	 * @param mixed $context Optional. The context to pass to the dependencies.
183
	 */
184
	public function register( $context = null ) {
185
		$context = $this->validate_context( $context );
186
		array_walk( $this->dependencies,
187
			[ $this, 'register_dependency_type' ], $context );
188
	}
189
190
	/**
191
	 * Validate the context to make sure it is an array.
192
	 *
193
	 * @since 0.2.1
194
	 *
195
	 * @param mixed $context The context as passed in by WordPress.
196
	 * @return array Validated context.
197
	 */
198
	protected function validate_context( $context ) {
199
		if ( is_string( $context ) ) {
200
			return [ 'wp_context' => $context ];
201
		}
202
		return (array) $context;
203
	}
204
205
	/**
206
	 * Enqueue all dependencies.
207
	 *
208
	 * @since 0.1.0
209
	 *
210
	 * @param mixed $context  Optional. The context to pass to the
211
	 *                        dependencies.
212
	 */
213
	public function enqueue( $context = null ) {
214
		$context = $this->validate_context( $context );
215
216
		array_walk( $this->dependencies,
217
			[ $this, 'enqueue_dependency_type' ], $context );
218
	}
219
220
	/**
221
	 * Enqueue a single dependency retrieved by its handle.
222
	 *
223
	 * @since 0.2.2
224
	 *
225
	 * @param string $handle   The dependency handle to enqueue.
226
	 * @param mixed  $context  Optional. The context to pass to the
227
	 *                         dependencies.
228
	 * @param bool   $fallback Whether to fall back to dependencies registered
229
	 *                         outside of DependencyManager. Defaults to false.
230
	 * @return bool Returns whether the handle was found or not.
231
	 */
232
	public function enqueue_handle( $handle, $context = null, $fallback = false ) {
233
		if ( ! $this->enqueue_internal_handle( $handle, $context ) ) {
234
			return $this->enqueue_fallback_handle( $handle );
235
		}
236
		return true;
237
	}
238
239
	/**
240
	 * Enqueue a single dependency from the internal dependencies, retrieved by
241
	 * its handle.
242
	 *
243
	 * @since 0.2.4
244
	 *
245
	 * @param string $handle   The dependency handle to enqueue.
246
	 * @param mixed  $context  Optional. The context to pass to the
247
	 *                         dependencies.
248
	 * @return bool Returns whether the handle was found or not.
249
	 */
250
	protected function enqueue_internal_handle( $handle, $context = null ) {
251
		list( $dependency_type, $dependency ) = $this->get_dependency_array( $handle );
252
		$context['dependency_type'] = $dependency_type;
253
254
		if ( ! $dependency ) {
255
			return false;
256
		}
257
258
		$handler = array_key_exists( $dependency_type, $this->handlers )
259
			? $this->handlers[ $dependency_type ]
260
			: null;
261
		if ( $handler && $handler->is_enqueued( $handle ) ) {
262
			return true;
263
		}
264
265
		$this->enqueue_dependency(
266
			$dependency,
267
			$handle,
268
			$context
269
		);
270
271
		$this->maybe_localize( $dependency, $context );
272
		$this->maybe_add_inline_script( $dependency, $context );
273
274
		return true;
275
	}
276
277
	/**
278
	 * Get the matching dependency for a given handle.
279
	 *
280
	 * @since 0.2.2
281
	 *
282
	 * @param string $handle The dependency handle to search for.
283
	 * @return array Array containing the dependency key as well as the
284
	 *                       dependency array itself.
285
	 */
286
	protected function get_dependency_array( $handle ) {
287
		foreach ( $this->dependencies as $type => $dependencies ) {
288
			if ( array_key_exists( $handle, $dependencies ) ) {
289
				return [ $type, $dependencies[ $handle ] ];
290
			}
291
		}
292
		// Handle not found, return an empty array.
293
		return [ '', null ];
294
	}
295
296
	/**
297
	 * Enqueue a single dependency.
298
	 *
299
	 * @since 0.1.0
300
	 *
301
	 * @param array  $dependency     Configuration data of the dependency.
302
	 * @param string $dependency_key Config key of the dependency.
303
	 * @param mixed  $context        Optional. Context to pass to the
304
	 *                               dependencies. Contains the type of the
305
	 *                               dependency at key
306
	 *                               'dependency_type'.
307
	 */
308
	protected function enqueue_dependency( $dependency, $dependency_key, $context = null ) {
309
		$handler = $this->handlers[ $context['dependency_type'] ];
310
		$handle  = array_key_exists( 'handle', $dependency ) ? $dependency['handle'] : '';
311
312
		if ( $handle && $handler->is_enqueued( $handle ) ) {
313
			return;
314
		}
315
316
		if ( ! $this->is_needed( $dependency, $context ) ) {
317
			return;
318
		}
319
320
		$handler->enqueue( $dependency );
321
	}
322
323
	/**
324
	 * Check whether a specific dependency is needed.
325
	 *
326
	 * @since 0.1.0
327
	 *
328
	 * @param array $dependency Configuration of the dependency to check.
329
	 * @param mixed $context    Context to pass to the dependencies.
330
	 *                          Contains the type of the dependency at key
331
	 *                          'dependency_type'.
332
	 * @return bool Whether it is needed or not.
333
	 */
334
	protected function is_needed( $dependency, $context ) {
335
		$is_needed = array_key_exists( 'is_needed', $dependency )
336
			? $dependency['is_needed']
337
			: null;
338
339
		if ( null === $is_needed ) {
340
			return true;
341
		}
342
343
		return is_callable( $is_needed ) && $is_needed( $context );
344
	}
345
346
	/**
347
	 * Localize the script of a given dependency.
348
	 *
349
	 * @since 0.1.0
350
	 *
351
	 * @param array $dependency The dependency to localize the script of.
352
	 * @param mixed $context    Contextual data to pass to the callback.
353
	 *                          Contains the type of the dependency at key
354
	 *                          'dependency_type'.
355
	 */
356
	protected function maybe_localize( $dependency, $context ) {
357
		static $already_localized = [];
358
		if ( ! array_key_exists( 'localize', $dependency )
359
		     || array_key_exists( $dependency['handle'], $already_localized ) ) {
360
			return;
361
		}
362
363
		$localize = $dependency['localize'];
364
		$data     = $localize['data'];
365
		if ( is_callable( $data ) ) {
366
			$data = $data( $context );
367
		}
368
369
		wp_localize_script( $dependency['handle'], $localize['name'], $data );
370
		$already_localized[ $dependency['handle'] ] = true;
371
	}
372
373
	/**
374
	 * Add an inline script snippet to a given dependency.
375
	 *
376
	 * @since 0.1.0
377
	 *
378
	 * @param array $dependency The dependency to add the inline script to.
379
	 * @param mixed $context    Contextual data to pass to the callback.
380
	 *                          Contains the type of the dependency at key
381
	 *                          'dependency_type'.
382
	 */
383
	protected function maybe_add_inline_script( $dependency, $context ) {
384
		if ( ! array_key_exists( 'add_inline', $dependency ) ) {
385
			return;
386
		}
387
388
		$inline_script = $dependency['add_inline'];
389
390
		if ( is_callable( $inline_script ) ) {
391
			$inline_script = $inline_script( $context );
392
		}
393
394
		wp_add_inline_script( $dependency['handle'], $inline_script );
395
	}
396
397
	/**
398
	 * Enqueue a single dependency from the WP-registered dependencies,
399
	 * retrieved by its handle.
400
	 *
401
	 * @since 0.2.4
402
	 *
403
	 * @param string $handle The dependency handle to enqueue.
404
	 * @return bool Returns whether the handle was found or not.
405
	 */
406
	protected function enqueue_fallback_handle( $handle ) {
407
		$result = false;
408
		foreach ( $this->handlers as $handler ) {
409
			$result = $result || $handler->maybe_enqueue( $handle );
410
		}
411
		return $result;
412
	}
413
414
	/**
415
	 * Enqueue all dependencies of a specific type.
416
	 *
417
	 * @since 0.1.0
418
	 *
419
	 * @param array  $dependencies    The dependencies to enqueue.
420
	 * @param string $dependency_type The type of the dependencies.
421
	 * @param mixed  $context         Optional. The context to pass to the
422
	 *                                dependencies.
423
	 */
424
	protected function enqueue_dependency_type( $dependencies, $dependency_type, $context = null ) {
425
		$context['dependency_type'] = $dependency_type;
426
		array_walk( $dependencies, [ $this, 'enqueue_dependency' ], $context );
427
	}
428
429
	/**
430
	 * Register all dependencies of a specific type.
431
	 *
432
	 * @since 0.1.0
433
	 *
434
	 * @param array  $dependencies    The dependencies to register.
435
	 * @param string $dependency_type The type of the dependencies.
436
	 * @param mixed  $context         Optional. The context to pass to the
437
	 *                                dependencies.
438
	 */
439
	protected function register_dependency_type( $dependencies, $dependency_type, $context = null ) {
440
		$context['dependency_type'] = $dependency_type;
441
		array_walk( $dependencies, [ $this, 'register_dependency' ], $context );
442
	}
443
444
	/**
445
	 * Register a single dependency.
446
	 *
447
	 * @since 0.1.0
448
	 *
449
	 * @param array  $dependency     Configuration data of the dependency.
450
	 * @param string $dependency_key Config key of the dependency.
451
	 * @param mixed  $context        Optional. Context to pass to the
452
	 *                               dependencies. Contains the type of the
453
	 *                               dependency at key
454
	 *                               'dependency_type'.
455
	 */
456
	protected function register_dependency( $dependency, $dependency_key, $context = null ) {
457
		$handler = $this->handlers[ $context['dependency_type'] ];
458
		$handler->register( $dependency );
459
460
		if ( $this->enqueue_immediately ) {
461
			$this->register_enqueue_hooks( $dependency, $context );
462
		}
463
	}
464
465
	/**
466
	 * Register the enqueueing to WordPress hooks.
467
	 *
468
	 * @since 0.2.2
469
	 *
470
	 * @param array $dependency Configuration data of the dependency.
471
	 * @param mixed $context    Optional. Context to pass to the dependencies.
472
	 *                          Contains the type of the dependency at key
473
	 *                          'dependency_type'.
474
	 */
475
	protected function register_enqueue_hooks( $dependency, $context = null ) {
476
		$priority = $this->get_priority( $dependency );
477
478
		foreach ( [ 'wp_enqueue_scripts', 'admin_enqueue_scripts' ] as $hook ) {
479
			add_action( $hook, [ $this, 'enqueue' ], $priority, 1 );
480
		}
481
482
		$this->maybe_localize( $dependency, $context );
483
		$this->maybe_add_inline_script( $dependency, $context );
484
	}
485
486
	/**
487
	 * Get the priority of a dependency.
488
	 *
489
	 * @since 0.2.2
490
	 *
491
	 * @param array $dependency Configuration data of the dependency.
492
	 * @return int Priority to use.
493
	 */
494
	protected function get_priority( $dependency ) {
495
		if ( array_key_exists( 'priority', $dependency ) ) {
496
			return intval( $dependency['priority'] );
497
		}
498
		return 10;
499
	}
500
}
501