Completed
Push — develop ( f519ad...30011c )
by David
03:44
created

ui::load_folder_items()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 3
nop 2
dl 0
loc 14
ccs 5
cts 5
cp 1
crap 4
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * UIX UI Loader
4
 *
5
 * @package   uix
6
 * @author    David Cramer
7
 * @license   GPL-2.0+
8
 * @link
9
 * @copyright 2016 David Cramer
10
 */
11
12
namespace uix;
13
14
/**
15
 * UI loader and handler class. This forms a single instance with UI objects attached
16
 *
17
 * @package uix
18
 * @author  David Cramer
19
 */
20
class ui {
21
22
23
	/**
24
	 * Array of definitions locations
25
	 *
26
	 * @since 1.0.0
27
	 * @access protected
28
	 * @var   array
29
	 */
30
	protected $locations = array();
31
32
	/**
33
	 * Array of object instances
34
	 *
35
	 * @since 1.0.0
36
	 * @access public
37
	 * @var   array
38
	 */
39
	public $ui;
40
41
	/**
42
	 * Array of post and get data
43
	 *
44
	 * @since 1.0.0
45
	 * @access private
46
	 * @var   array
47
	 */
48
	protected $data = array();
49
50
	/**
51
	 * Holds instance
52
	 *
53
	 * @since 1.0.0
54
	 * @access protected
55
	 * @var      object/UI
56
	 */
57
	protected static $instance = null;
58
59
	/**
60
	 * UI structure auto load
61
	 *
62
	 * @since 1.0.0
63
	 * @access public
64 1
	 */
65
	public function auto_load() {
66
		/**
67
		 * do UI loader locations
68
		 *
69
		 * @param ui $this Current instance of this class
70 1
		 */
71
		do_action( 'uix_register', $this );
72 1
		// init the share object
73
		uix_share();
74
75 1
		// go over each locations
76
		foreach ( $this->locations as $type => $paths ) {
77 1
78 1
			if ( $this->is_callable( $type ) ) {
79
				$this->process_paths( $type, $paths );
80
			}
81 1
		}
82
	}
83
84
	/**
85
	 * Add a single structure object
86
	 *
87
	 * @since 1.0.0
88
	 *
89
	 * @param string $type The type of object to add
90
	 * @param array  $paths array of paths to process and add
91 1
	 */
92
	private function process_paths( $type, $paths ) {
93 1
94 1
		foreach ( $paths as $path ) {
95 1
			$has_struct = $this->get_file_structure( $path );
96 1
			if ( is_array( $has_struct ) ) {
97
				$this->add_objects( $type, $has_struct );
98
			}
99 1
		}
100
	}
101
102
	/**
103
	 * Add a single structure object
104
	 *
105
	 * @since 1.0.0
106
	 *
107
	 * @param string $type The type of object to add
108
	 * @param string $slug The objects slug to add
109
	 * @param array  $structure The objects structure
110
	 * @param object $parent object
111
	 *
112
	 * @return object The instance of the object type or null if invalid
113 18
	 */
114 18
	public function add( $type, $slug, $structure, $parent = null ) {
115 18
		$init = $this->get_register_callback( $type );
116 17
		if ( null !== $init ) {
117 17
			$object                     = call_user_func_array( $init, array(
118
				$slug,
119 17
				$structure,
120
				$parent,
121
			) );
122 1
			$this->ui->{$type}[ $slug ] = $object;
123
124
			return $object;
125
		}
126
127
		return null;
128
	}
129
130
	/**
131
	 * Returns a callback for registering the object or null if invalid type
132
	 *
133
	 * @since 1.0.0
134 19
	 *
135 19
	 * @param string $type The type of object to get register callback for
136 19
	 *
137 9
	 * @return array|null Callback array for registering an object or null if invalid
138
	 */
139
	public function get_register_callback( $type ) {
140 18
		$init = array( '\uix\ui\\' . $type, 'register' );
141
		if ( ! is_callable( $init ) ) {
142
			return null;
143
		}
144
145
		return $init;
146
	}
147
148
	/**
149
	 * Checks if the object type is callable
150
	 *
151
	 * @since 1.0.0
152 8
	 *
153 8
	 * @param string $type The type of object to check
154
	 *
155 8
	 * @return bool
156
	 */
157
	public function is_callable( $type ) {
158
		$init = array( '\uix\ui\\' . $type, 'register' );
159
160
		return is_callable( $init );
161
	}
162
163
	/**
164
	 * Registers multiple objects
165
	 *
166
	 * @since 1.0.0
167 1
	 *
168 1
	 * @param string $type The type of object to add
169 1
	 * @param array  $objects The objects structure
170 1
	 * @param object $parent object
171
	 */
172
	public function add_objects( $type, array $objects, $parent = null ) {
173 1
		foreach ( $objects as $slug => $struct ) {
174
			if ( is_array( $struct ) ) {
175
				$this->add( $type, $slug, $struct, $parent );
176
			}
177
		}
178
	}
179
180
181
	/**
182
	 * Return an instance of this class.
183
	 * @codeCoverageIgnore
184
	 * @since 1.0.0
185
	 *
186
	 * @param array $request_data Current REQUEST superglobals
187
	 *
188
	 * @return ui A single instance of this class
189
	 */
190
	public static function get_instance( $request_data ) {
191
192
		// If the single instance hasn't been set, set it now.
193
		if ( isset( self::$instance ) ) {
194
			self::$instance->data = $request_data;
195
		} else {
196
			self::$instance       = new self;
197
			self::$instance->data = $request_data;
198
			self::$instance->auto_load();
199
		}
200
201
		return self::$instance;
202
203
	}
204
205
	/**
206
	 * Register the UIX object paths for autoloading
207 1
	 *
208
	 * @since 1.0.0
209 1
	 *
210
	 * @param array|string $arr path, or array of paths to structures to autoload
211 1
	 */
212 1
	public function register( $arr ) {
213
		// set error handler for catching file location errors
214
		set_error_handler( array( $this, 'silent_warning' ), E_WARNING );
215
		// determine how the structure works.
216 1
		foreach ( (array) $arr as $key => $value ) {
217 1
			$this->locations = array_merge_recursive( $this->locations, $this->get_files_from_folders( trailingslashit( $value ) ) );
218
		}
219
220
		// restore original handler
221
		restore_error_handler();
222
	}
223
224
	/**
225
	 * Handy method to get request vars
226
	 *
227
	 * @since 1.0.0
228 11
	 *
229 11
	 * @param string $type Request type to get
230
	 *
231
	 * @return array Request vars array
232
	 */
233
	public function request_vars( $type ) {
234
		return $this->data[ $type ];
235
	}
236
237
238
	/**
239
	 * Gets the file structures and converts it if needed
240
	 *
241
	 * @since 1.0.0
242
	 * @access private
243 1
	 *
244 1
	 * @param string $path The file path to load
245 1
	 *
246 1
	 * @return array|bool object structure array or false if invalid
247
	 */
248 1
	private function get_file_structure( $path ) {
249 1
		ob_start();
250
		$content    = include $path;
251
		$has_output = ob_get_clean();
252 1
		// did stuff output
253
		if ( ! empty( $has_output ) ) {
254
			$content = json_decode( $has_output, ARRAY_A );
255
		}
256
257
		return $content;
258
	}
259
260
261
	/**
262
	 * Opens a location and gets the folders to check
263
	 *
264
	 * @since 1.0.0
265
	 * @access private
266 1
	 *
267
	 * @param string $path The file patch to examine and to fetch contents from
268 1
	 *
269 1
	 * @return array List of folders
270 1
	 */
271 1
	private function get_folder_contents( $path ) {
272 1
273
		$items = array();
274
		$uid   = opendir( $path );
275 1
		if ( $uid ) {
276
			return $this->load_folder_items( $uid, $path );
277
		}
278 1
279
		return $items;
280
	}
281
282
	/**
283
	 * Load items from a folder
284
	 *
285
	 * @since 1.0.0
286
	 * @access private
287
	 *
288
	 * @param string $uid The folder name.
289
	 * @param string $path The folder path.
290
	 *
291 1
	 * @return array List of items
292
	 */
293 1
	private function load_folder_items( $uid, $path ) {
294
		$items = array();
295 1
		while ( true ) {
296 1
			$item = readdir( $uid );
297 1
			if ( false === $item ) {
298
				break;
299
			}
300 1
			if ( substr( $item, 0, 1 ) !== '.' ) {
301
				$items[ $item ] = $path . $item;
302
			}
303
		}
304
		closedir( $uid );
305
		return $items;
306
	}
307
	/**
308
	 * Opens a location and gets the file to load for each folder
309
	 *
310
	 * @since 1.0.0
311
	 * @access private
312
	 *
313
	 * @param string $path The file patch to examine and to fetch contents from.
314
	 *
315
	 * @return array List of folders and files
316 1
	 */
317 1
	private function get_files_from_folders( $path ) {
318 1
319 1
		$items = $this::get_folder_contents( $path );
320
321 1
		foreach ( $items as $type => &$location ) {
322
			$location = $this::get_folder_contents( trailingslashit( $location ) );
323
			sort( $location );
324
		}
325
326
		return $items;
327
	}
328
329 5
	/**
330
	 * Handles E_WARNING error notices whan the file loader runs.
331 5
	 *
332 5
	 *
333
	 * @since 1.0.0
334 5
	 *
335
	 * @link http://php.net/manual/en/function.set-error-handler.php
336
	 *
337
	 * @param int    $errno Contains the level of the error raised, as an integer.
338
	 * @param string $errstr Contains the error message.
339
	 * @param string $errfile Which contains the filename that the error was raised in.
340
	 * @param int    $errline which contains the line number the error was raised at.
341
	 */
342
	public function silent_warning( $errno, $errstr, $errfile, $errline ) {
343
		$this->add( 'notice', 'notice_' . $errno . '-' . $errline, array(
344
			'description' => '<strong>' . __( 'Warning' ) . '</strong>: ' . $errstr . '<br>on ' . $errfile . ' line ' . $errline,
345 5
			'state'       => 'warning',
346
		) );
347
	}
348 5
349
350 5
	/**
351
	 * Sets assets to be enqueued for this instance.
352 5
	 *
353 1
	 * @param array $assets the asset to enqueue where the key is the type and the value the asset
354 1
	 */
355
	public function set_assets( $assets ) {
356
357 5
		foreach ( $assets as $type => $asset ) {
358 5
			$this->enqueue( $asset, $type );
359
		}
360
	}
361
362 5
	/**
363
	 * enqueue a set of styles and scripts
364
	 *
365
	 * @since 1.0.0
366
	 * @access protected
367
	 *
368
	 * @param array  $set Array of assets to be enqueued
369
	 * @param string $type The type of asset
370
	 */
371
	protected function enqueue( $set, $type ) {
372
		// go over the set to see if it has styles or scripts
373
374
		$enqueue_type = 'wp_enqueue_' . $type;
375 5
376
		foreach ( $set as $key => $item ) {
377
378
			if ( is_int( $key ) ) {
379 5
				$enqueue_type( $item );
380
				continue;
381
			}
382
383
			$args = $this->build_asset_args( $item );
384
			$enqueue_type( $key, $args['src'], $args['deps'], $args['ver'], $args['in_footer'] );
385
386 5
		}
387 4
388
	}
389
390
391 5
	/**
392
	 * Checks the asset type
393 5
	 *
394
	 * @since 1.0.0
395
	 * @access private
396
	 *
397
	 * @param array|string $asset Asset structure, slug or path to build
398
	 *
399
	 * @return array Params for enqueuing the asset
400
	 */
401
	private function build_asset_args( $asset ) {
402
403
		// setup default args for array type includes
404
		$args = array(
405
			'src'       => $asset,
406
			'deps'      => array(),
407
			'ver'       => false,
408
			'in_footer' => false,
409
			'media'     => false,
410
		);
411
412
		if ( is_array( $asset ) ) {
413
			$args = array_merge( $args, $asset );
414
		}
415
416
		// add uix dep
417
		$args['deps'][] = 'uix';
418
419
		return $args;
420
	}
421
}
422