App_Config::meta()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
nc 3
nop 2
dl 0
loc 11
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * Base config object.
6
 *
7
 * @author Glynn Quelch <[email protected]>
8
 * @license http://www.opensource.org/licenses/mit-license.html  MIT License
9
 * @package PinkCrab\Perique
10
 */
11
12
namespace PinkCrab\Perique\Application;
13
14
use OutOfBoundsException;
15
use PinkCrab\Perique\Utils\App_Config_Path_Helper;
16
17
final class App_Config {
18
19
	/**
20
* @ var string
21
*/
22
	public const POST_META = 'post';
23
24
	/**
25
* @ var string
26
*/
27
	public const TERM_META = 'term';
28
29
	/**
30
* @ var string
31
*/
32
	public const USER_META = 'user';
33
34
	/**
35
	 * Holds the current sites paths & urls
36
	 *
37
	 * @var array<string, mixed>
38
	 */
39
	private array $paths = array();
40
41
	/**
42
	 * Holds all the namespaces (rest, cache etc).
43
	 *
44
	 * @var array<string, mixed>
45
	 */
46
	private array $namespaces = array();
47
48
	/**
49
	 * Holds all plugin details.
50
	 *
51
	 * @var array<string, mixed>
52
	 */
53
	private array $plugin = array();
54
55
	/**
56
	 * Holds all taxonomy terms.
57
	 *
58
	 * @var array<string, mixed>
59
	 */
60
	private array $taxonomies = array();
61
62
	/**
63
	 * Holds the CPT slugs and meta keys.
64
	 *
65
	 * @var array<string, mixed>
66
	 */
67
	private array $post_types = array();
68
69
	/**
70
	 * Holds an array of table names.
71
	 *
72
	 * @var array<string, mixed>
73
	 */
74
	private array $db_tables = array();
75
76
	/**
77
	 * Holds all custom settings keys.
78
	 * Accessed using __get()
79
	 *
80
	 * @var array<string, mixed>
81
	 */
82
	private array $additional = array();
83
84
	/**
85
	 * Holds all the meta keys
86
	 *
87
	 * @var array{post:array<string,string>,user:array<string,string>,term:array<string,string>}
88
	 */
89
	private array $meta = array(
90
		self::POST_META => array(),
91
		self::USER_META => array(),
92
		self::TERM_META => array(),
93
	);
94
95
	/**
96
	 * @param array<string, mixed> $settings
97
	 */
98
	public function __construct( array $settings = array() ) {
99
		$settings = $this->set_defaults( $settings );
100
		$this->set_props( $settings );
101
	}
102
103
	/**
104
	 * Overlays the passed details to the predefined fallbacks.
105
	 *
106
	 * @param array<string, mixed> $settings
107
	 * @return array<string, mixed>
108
	 */
109
	private function set_defaults( array $settings ): array {
110
		return array_replace_recursive( $this->settings_defaults(), $settings );
111
	}
112
113
	/**
114
	 * Maps the supplied settings array to inner states.
115
	 *
116
	 * @param array<string, mixed> $settings The settings to map.
117
	 *
118
	 * @return void
119
	 */
120
	private function set_props( array $settings ): void {
121
		$this->paths['url']  = $settings['url'];
122
		$this->paths['path'] = $settings['path'];
123
		$this->namespaces    = $this->filter_key_value_pair( $settings['namespaces'] );
124
		$this->plugin        = $settings['plugin'];
125
		$this->additional    = $settings['additional'];
126
		$this->db_tables     = $this->filter_key_value_pair( $settings['db_tables'] );
127
		$this->post_types    = $this->filter_key_value_pair( $settings['post_types'] );
128
		$this->taxonomies    = $this->filter_key_value_pair( $settings['taxonomies'] );
129
130
		$this->set_meta( $settings['meta'] );
131
	}
132
133
	/**
134
	 * Gets a path with trailing slash.
135
	 *
136
	 * @param string|null $path          The path to return.
137
	 * @param string|null $default_value The default value to return if not set.
138
	 *
139
	 * @return array<string, mixed>|string|null
140
	 */
141
	public function path( ?string $path = null, ?string $default_value = null ) {
142
143
		if ( is_null( $path ) ) {
144
			return $this->paths['path'];
145
		}
146
147
		return \array_key_exists( $path, $this->paths['path'] )
148
			? trailingslashit( $this->paths['path'][ $path ] )
149
			: $default_value;
150
	}
151
152
	/**
153
	 * Gets a path with trailing slash.
154
	 *
155
	 * @param string|null $url           The key for the url.
156
	 * @param string|null $default_value The default value to return if not set.
157
	 *
158
	 * @return array<string, mixed>|string|null
159
	 */
160
	public function url( ?string $url = null, ?string $default_value = null ) {
161
162
		if ( is_null( $url ) ) {
163
			return $this->paths['url'];
164
		}
165
166
		return \array_key_exists( $url, $this->paths['url'] )
167
			? trailingslashit( $this->paths['url'][ $url ] )
168
			: $default_value;
169
	}
170
171
	/**
172
	 * Returns the based namespace for all routes.
173
	 *
174
	 * @return string
175
	 */
176
	public function rest(): string {
177
		return $this->namespaces['rest'];
178
	}
179
180
	/**
181
	 * Returns the cache namespace.
182
	 *
183
	 * @return string
184
	 */
185
	public function cache(): string {
186
		return $this->namespaces['cache'];
187
	}
188
189
	/**
190
	 * Return a namespace by its key.
191
	 *
192
	 * @param string      $key           The key for the namespace.
193
	 * @param string|null $default_value The default value to return if not set.
194
	 *
195
	 * @return string|null
196
	 */
197
	public function namespace( string $key, ?string $default_value = null ): ?string {
198
		return array_key_exists( $key, $this->namespaces )
199
			? $this->namespaces[ $key ] : $default_value;
200
	}
201
202
	/**
203
	 * Return a additional by its key.
204
	 *
205
	 * @param string      $key           The key for the additional.
206
	 * @param string|null $default_value The default value to return if not set.
207
	 *
208
	 * @return mixed
209
	 */
210
	public function additional( string $key, ?string $default_value = null ) {
211
		return array_key_exists( $key, $this->additional )
212
			? $this->additional[ $key ] : $default_value;
213
	}
214
215
	/**
216
	 * Returns the current set plugin version
217
	 *
218
	 * @return string
219
	 */
220
	public function version(): string {
221
		return $this->plugin['version'];
222
	}
223
224
	/**
225
	 * Returns the wpdb prefix
226
	 *
227
	 * @return string
228
	 */
229
	public function wpdb_prefix(): string {
230
		return $this->plugin['wpdb_prefix'];
231
	}
232
233
	/**
234
	 * Returns the key for a post type.
235
	 *
236
	 * @param string $key
237
	 * @return string
238
	 * @throws OutOfBoundsException
239
	 */
240
	public function post_types( string $key ) {
241
		if ( ! array_key_exists( $key, $this->post_types ) ) {
242
			throw new OutOfBoundsException( 'App Config :: "' . esc_html( $key ) . '" is not a defined post type' );
243
		}
244
245
		return $this->post_types[ $key ];
246
	}
247
248
	/**
249
	 * Returns a valid meta key value, for a defined meta type.
250
	 *
251
	 * @param string $key
252
	 * @param string $type defaults to post
253
	 * @return string
254
	 * @throws OutOfBoundsException
255
	 */
256
	public function meta( string $key, string $type = self::POST_META ): string {
257
		// Check meta type.
258
		if ( ! array_key_exists( $type, $this->meta ) ) {
259
			throw new OutOfBoundsException( 'App Config :: "' . esc_html( $type ) . '" is not a valid meta type and cant be fetched' );
260
		}
261
		// Check key.
262
		if ( ! array_key_exists( $key, $this->meta[ $type ] ) ) {
263
			throw new OutOfBoundsException( 'App Config :: "' . esc_html( $key ) . '" is not a defined ' . esc_html( $type ) . 'meta key' );
264
		}
265
266
		return $this->meta[ $type ][ $key ];
267
	}
268
269
	/**
270
	 * Returns the post meta key value
271
	 * Alias for meta() with type as POST_META
272
	 *
273
	 * @param string $key
274
	 * @return string
275
	 */
276
	public function post_meta( string $key ): string {
277
		return $this->meta( $key, self::POST_META );
278
	}
279
280
	/**
281
	 * Returns the user meta key value
282
	 * Alias for meta() with type as USER_META
283
	 *
284
	 * @param string $key
285
	 * @return string
286
	 */
287
	public function user_meta( string $key ): string {
288
		return $this->meta( $key, self::USER_META );
289
	}
290
291
	/**
292
	 * Returns the tern meta key value
293
	 * Alias for meta() with type as TERM_META
294
	 *
295
	 * @param string $key
296
	 * @return string
297
	 */
298
	public function term_meta( string $key ): string {
299
		return $this->meta( $key, self::TERM_META );
300
	}
301
302
	/**
303
	 * Sets the meta data
304
	 *
305
	 * @param array<string, array<string,string>> $meta
306
	 * @return void
307
	 */
308
	public function set_meta( array $meta ): void {
309
		$valid_meta_types = array( self::POST_META, self::USER_META, self::TERM_META );
310
		foreach ( $meta as $meta_type => $pairs ) {
311
			if ( ! in_array( $meta_type, $valid_meta_types, true ) ) {
312
				throw new OutOfBoundsException( 'App Config :: "' . esc_html( $meta_type ) . '" is not a valid meta type and cant be defined' );
313
			}
314
315
			// Set all pairs which have both valid key and values.
316
			$this->meta[ $meta_type ] = $this->filter_key_value_pair( $pairs );
317
		}
318
	}
319
320
	/**
321
	 * Returns the key for a taxonomy.
322
	 *
323
	 * @param string $key
324
	 * @return string
325
	 * @throws OutOfBoundsException
326
	 */
327
	public function taxonomies( string $key ): string {
328
		if ( ! array_key_exists( $key, $this->taxonomies ) ) {
329
			throw new OutOfBoundsException( 'App Config :: "' . esc_html( $key ) . '" is not a defined taxonomy' );
330
		}
331
332
		return $this->taxonomies[ $key ];
333
	}
334
335
336
	/**
337
	 * Returns a table name based on its key.
338
	 *
339
	 * @param string $name
340
	 * @return string
341
	 * @throws OutOfBoundsException
342
	 */
343
	public function db_tables( string $name ): string {
344
		if ( ! array_key_exists( $name, $this->db_tables ) ) {
345
			throw new OutOfBoundsException( 'App Config :: "' . esc_html( $name ) . '" is not a defined DB table' );
346
		}
347
		return $this->db_tables[ $name ];
348
	}
349
350
	/**
351
	 * Magic getter for values in additional
352
	 *
353
	 * @param string $name
354
	 * @return mixed
355
	 */
356
	public function __get( $name ) {
357
		return $this->additional( $name );
358
	}
359
360
	/**
361
	 * Returns a base settings array, to ensure all required values are defined.
362
	 *
363
	 * @return array<string, mixed>
364
	 */
365
	private function settings_defaults(): array {
366
		$base_path  = \dirname( __DIR__, 2 );
367
		$wp_uploads = \wp_upload_dir();
368
369
		$base_path = App_Config_Path_Helper::normalise_path( $base_path );
370
		$view_path = App_Config_Path_Helper::assume_view_path( $base_path );
371
372
		global $wpdb;
373
374
		return array(
375
			'plugin'     => array(
376
				'version'     => '0.1.0',
377
				'wpdb_prefix' => $wpdb->prefix,
378
			),
379
			'path'       => array(
380
				'plugin'         => $base_path,
381
				'view'           => $view_path,
382
				'assets'         => $base_path . \DIRECTORY_SEPARATOR . 'assets',
383
				'upload_root'    => $wp_uploads['basedir'],
384
				'upload_current' => $wp_uploads['path'],
385
			),
386
			'url'        => array(
387
				'plugin'         => App_Config_Path_Helper::assume_base_url( $base_path ),
388
				'view'           => App_Config_Path_Helper::assume_view_url( $base_path, $view_path ),
389
				'assets'         => App_Config_Path_Helper::assume_base_url( $base_path ) . '/assets',
390
				'upload_root'    => $wp_uploads['baseurl'],
391
				'upload_current' => $wp_uploads['url'],
392
			),
393
			'post_types' => array(),
394
			'taxonomies' => array(),
395
			'meta'       => array(),
396
			'db_tables'  => array(),
397
			'namespaces' => array(
398
				'rest'  => 'pinkcrab',
399
				'cache' => 'pc_cache',
400
			),
401
			'additional' => array(),
402
		);
403
	}
404
405
	/**
406
	 * Filters an array to ensure key and value are both valid strings.
407
	 *
408
	 * @param array<int|string, mixed> $pairs
409
	 * @return array<string, string>
410
	 */
411
	private function filter_key_value_pair( array $pairs ): array {
412
		/**
413
		 * @var array<string, string> (as per filter function)
414
		 */
415
		return array_filter(
416
			$pairs,
417
			function ( $value, $key ): bool {
418
				return is_string( $value )
419
				&& \strlen( $value ) > 0
420
				&& is_string( $key )
421
				&& \strlen( $key ) > 0;
422
			},
423
			ARRAY_FILTER_USE_BOTH
424
		);
425
	}
426
427
	/**
428
	 * Exports the internal settings array.
429
	 *
430
	 * @return array<string, string|int|array<mixed>>
431
	 */
432
	public function export_settings(): array {
433
		return array(
434
			'path'       => $this->paths['path'],
435
			'url'        => $this->paths['url'],
436
			'namespaces' => $this->namespaces,
437
			'plugin'     => $this->plugin,
438
			'additional' => $this->additional,
439
			'db_tables'  => $this->db_tables,
440
			'post_types' => $this->post_types,
441
			'taxonomies' => $this->taxonomies,
442
			'meta'       => $this->meta,
443
		);
444
	}
445
446
	/**
447
	 * Get Asset Path.
448
	 *
449
	 * @return string
450
	 */
451
	public function asset_path(): string {
452
		$paths = $this->path( 'assets' );
453
		return is_string( $paths ) ? $paths : '';
454
	}
455
456
	/**
457
	 * Get the View Path.
458
	 *
459
	 * @return string
460
	 */
461
	public function view_path(): string {
462
		$paths = $this->path( 'view' );
463
		return is_string( $paths ) ? $paths : '';
464
	}
465
466
	/**
467
	 * Get the plugin path.
468
	 *
469
	 * @return string
470
	 */
471
	public function plugin_path(): string {
472
		$paths = $this->path( 'plugin' );
473
		return is_string( $paths ) ? $paths : '';
474
	}
475
476
	/**
477
	 * Get the asset URL.
478
	 *
479
	 * @return string
480
	 */
481
	public function asset_url(): string {
482
		$url = $this->url( 'assets' );
483
		return is_string( $url ) ? $url : '';
484
	}
485
486
	/**
487
	 * Get the view URL.
488
	 *
489
	 * @return string
490
	 */
491
	public function view_url(): string {
492
		$url = $this->url( 'view' );
493
		return is_string( $url ) ? $url : '';
494
	}
495
496
	/**
497
	 * Get the plugin URL.
498
	 *
499
	 * @return string
500
	 */
501
	public function plugin_url(): string {
502
		$url = $this->url( 'plugin' );
503
		return is_string( $url ) ? $url : '';
504
	}
505
}
506