Completed
Push — milestone/2.0 ( debc3a...8685b0 )
by
unknown
03:26
created

Key_Toolset   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 311
Duplicated Lines 2.25 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 7
loc 311
ccs 0
cts 132
cp 0
rs 9.3999
wmc 33
lcom 1
cbo 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A get_storage_key_for_simple_root_field() 0 4 1
A get_storage_key_root() 0 5 1
A get_storage_key_prefix() 0 14 1
A get_storage_key() 0 7 3
B get_storage_key_with_index_wildcards() 0 23 4
B get_storage_key_getter_patterns() 4 24 3
A get_storage_key_deleter_patterns() 3 15 3
B storage_key_patterns_to_sql() 0 22 4
B storage_key_matches_any_pattern() 0 21 6
A is_segments_array_full() 0 3 1
A storage_key_to_segments_array() 0 5 1
A segment_to_segment_values_array() 0 3 1
B parse_storage_key() 0 27 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Carbon_Fields\Key_Toolset;
4
5
use \Carbon_Fields\Value_Set\Value_Set;
6
7
class Key_Toolset {
8
9
	/**
10
	 * Prefix appended to all keys
11
	 */
12
	const KEY_PREFIX = '_';
13
14
	/**
15
	 * Glue characters between segments in keys
16
	 */
17
	const SEGMENT_GLUE = '|';
18
19
	/**
20
	 * Glue characters between segments values in keys
21
	 */
22
	const SEGMENT_VALUE_GLUE = ':';
23
24
	/**
25
	 * Number of segments in a key
26
	 */
27
	const TOTAL_SEGMENTS = 5;
28
29
	/**
30
	 * "Equal" storage key pattern comparison type constant
31
	 */
32
	const PATTERN_COMPARISON_EQUAL = '=';
33
34
	/**
35
	 * "Starts with" storage key pattern comparison type constant
36
	 */
37
	const PATTERN_COMPARISON_STARTS_WITH = '^';
38
39
	/**
40
	 * Get a storage key for a simple root field
41
	 *
42
	 * @param string $field_base_name
43
	 * @return string
44
	 */
45
	protected function get_storage_key_for_simple_root_field( $field_base_name ) {
46
		$storage_key = static::KEY_PREFIX . $field_base_name;
47
		return $storage_key;
48
	}
49
50
	/**
51
	 * Get a storage key for the root field
52
	 * Suitable for deleting entire trees of values (e.g. Complex_Field)
53
	 *
54
	 * @param array $full_hierarchy
55
	 * @return string
56
	 */
57
	protected function get_storage_key_root( $full_hierarchy ) {
58
		$first_parent = array_shift( $full_hierarchy );
59
		$storage_key = static::KEY_PREFIX . $first_parent . static::SEGMENT_GLUE;
60
		return $storage_key;
61
	}
62
63
	/**
64
	 * Get a storage key up to the hierarchy index segment
65
	 * Suitable for getting and deleting multiple values for a single field
66
	 *
67
	 * @param array<string> $full_hierarchy
68
	 * @param array<int> $full_hierarchy_index
69
	 * @return string
70
	 */
71
	protected function get_storage_key_prefix( $full_hierarchy, $full_hierarchy_index ) {
72
		$parents = $full_hierarchy;
73
		$first_parent = array_shift( $parents );
74
75
		$storage_key = static::KEY_PREFIX . 
76
			$first_parent . 
77
			static::SEGMENT_GLUE . 
78
			implode( static::SEGMENT_VALUE_GLUE, $parents ) . 
79
			static::SEGMENT_GLUE . 
80
			implode( static::SEGMENT_VALUE_GLUE, $full_hierarchy_index ) . 
81
			static::SEGMENT_GLUE;
82
83
		return $storage_key;
84
	}
85
86
	/**
87
	 * Get a full storage key for a single field value
88
	 *
89
	 * @param bool $is_simple_root_field
90
	 * @param array<string> $full_hierarchy
91
	 * @param array<int> $full_hierarchy_index
92
	 * @param int $value_group_index
93
	 * @param string $value_key
94
	 * @return string
95
	 */
96
	public function get_storage_key( $is_simple_root_field, $full_hierarchy, $full_hierarchy_index, $value_group_index, $value_key ) {
97
		if ( $is_simple_root_field && $value_key === Value_Set::VALUE_PROPERTY ) {
98
			return $this->get_storage_key_for_simple_root_field( array_pop( $full_hierarchy ) );
99
		}
100
		$storage_key = $this->get_storage_key_prefix( $full_hierarchy, $full_hierarchy_index ) . intval( $value_group_index ) . static::SEGMENT_GLUE . $value_key;
101
		return $storage_key;
102
	}
103
104
	/**
105
	 * Get a full storage key with optional wildcards for entry and value indexes
106
	 *
107
	 * @param bool $is_simple_root_field
108
	 * @param array<string> $full_hierarchy
109
	 * @param string $value_key
110
	 * @param string $wildcard
111
	 * @return string
112
	 */
113
	public function get_storage_key_with_index_wildcards( $is_simple_root_field, $full_hierarchy, $value_key = Value_Set::VALUE_PROPERTY, $wildcard = '%' ) {
114
		if ( $is_simple_root_field && $value_key === Value_Set::VALUE_PROPERTY ) {
115
			return $this->get_storage_key_for_simple_root_field( array_pop( $full_hierarchy ) );
116
		}
117
118
		$parents = $full_hierarchy;
119
		$first_parent = array_shift( $parents );
120
		$hierarchy = array_slice( $full_hierarchy, 0, -1 );
121
		$hierarchy_index = ! empty( $hierarchy ) ? $wildcard : '0';
122
		$value_group_index = $wildcard;
123
124
		$storage_key = static::KEY_PREFIX . 
125
			$first_parent . 
126
			static::SEGMENT_GLUE . 
127
			implode( static::SEGMENT_VALUE_GLUE, $parents ) . 
128
			static::SEGMENT_GLUE . 
129
			$hierarchy_index . 
130
			static::SEGMENT_GLUE . 
131
			$value_group_index . 
132
			static::SEGMENT_GLUE . 
133
			$value_key;
134
		return $storage_key;
135
	}
136
137
	/**
138
	 * Get an array of storage key patterns for use when getting values from storage
139
	 *
140
	 * @param bool $is_simple_root_field
141
	 * @param array<string> $full_hierarchy
142
	 * @return array
143
	 */
144
	public function get_storage_key_getter_patterns( $is_simple_root_field, $full_hierarchy ) {
145
		$patterns = array();
146
147 View Code Duplication
		if ( $is_simple_root_field ) {
1 ignored issue
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...
148
			$key = $this->get_storage_key_for_simple_root_field( $full_hierarchy[ count( $full_hierarchy ) - 1 ] );
149
			$patterns[ $key ] = static::PATTERN_COMPARISON_EQUAL;
150
		}
151
		
152
		$parents = $full_hierarchy;
153
		$first_parent = array_shift( $parents );
154
155
		$storage_key = static::KEY_PREFIX . $first_parent . static::SEGMENT_GLUE;
156
		if ( empty( $parents ) ) {
157
			$patterns[ $storage_key ] = static::PATTERN_COMPARISON_STARTS_WITH;
158
		} else {
159
			$key = $storage_key . implode( static::SEGMENT_VALUE_GLUE, $parents ) . static::SEGMENT_GLUE;
160
			$patterns[ $key ] = static::PATTERN_COMPARISON_STARTS_WITH;
161
162
			$key = $storage_key . implode( static::SEGMENT_VALUE_GLUE, $parents ) . static::SEGMENT_VALUE_GLUE;
163
			$patterns[ $key ] = static::PATTERN_COMPARISON_STARTS_WITH;
164
		}
165
166
		return $patterns;
167
	}
168
169
	/**
170
	 * Get an array of storage key patterns for use when deleting values from storage
171
	 *
172
	 * @param bool $is_simple_root_field
173
	 * @param array<string> $full_hierarchy
174
	 * @param array<int> $full_hierarchy_index
175
	 * @return array
176
	 */
177
	public function get_storage_key_deleter_patterns( $is_simple_root_field, $full_hierarchy, $full_hierarchy_index ) {
178
		$patterns = array();
179
		
180 View Code Duplication
		if ( $is_simple_root_field ) {
1 ignored issue
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...
181
			$patterns[ $this->get_storage_key_for_simple_root_field( $full_hierarchy[ count( $full_hierarchy ) - 1 ] ) ] = static::PATTERN_COMPARISON_EQUAL;
182
		}
183
		
184
		if ( is_a( $field, '\\Carbon_Fields\\Field\\Complex_Field' ) ) {
0 ignored issues
show
Bug introduced by
The variable $field does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
185
			$patterns[ $this->get_storage_key_root( $full_hierarchy ) ] = static::PATTERN_COMPARISON_STARTS_WITH;
186
		} else {
187
			$patterns[ $this->get_storage_key_prefix( $full_hierarchy, $full_hierarchy_index ) ] = static::PATTERN_COMPARISON_STARTS_WITH;
188
		}
189
190
		return $patterns;
191
	}
192
193
	/**
194
	 * Convert an array of storage key patterns to a parentheses-enclosed sql comparison
195
	 *
196
	 * @param string $table_column
197
	 * @param array $patterns
198
	 * @return string
199
	 */
200
	public function storage_key_patterns_to_sql( $table_column, $patterns ) {
201
		$sql = array();
202
203
		foreach ( $patterns as $storage_key => $type ) {
204
			$comparison = '';
205
			switch ( $type ) {
206
				case static::PATTERN_COMPARISON_EQUAL:
207
					$comparison = $table_column . ' = "' . esc_sql( $storage_key ) . '" ';
208
					break;
209
				case static::PATTERN_COMPARISON_STARTS_WITH:
210
					$comparison = $table_column . ' LIKE "' . esc_sql( $storage_key ) . '%" ';
211
					break;
212
				default:
213
					Incorrect_Syntax_Exception::raise( 'Unsupported storage key pattern type used: "' . $type . '"' );
214
					break;
215
			}
216
217
			$sql[] = $comparison;
218
		}
219
220
		return ' ( ' . implode( ' OR ', $sql ) . ' ) ';
221
	}
222
223
	/**
224
	 * Check if a storage key matches any pattern
225
	 * 
226
	 * @param string $storage_key
227
	 * @param array $patterns
228
	 * @return bool
229
	 */
230
	public function storage_key_matches_any_pattern( $storage_key, $patterns ) {
231
		foreach ( $patterns as $key => $type ) {
232
			switch ( $type ) {
233
				case static::PATTERN_COMPARISON_EQUAL:
234
					if ( $storage_key === $key ) {
235
						return true;
236
					}
237
					break;
238
				case static::PATTERN_COMPARISON_STARTS_WITH:
239
					$key_length = strlen( $key );
240
					if ( substr( $storage_key, 0, $key_length ) === $key ) {
241
						return true;
242
					}
243
					break;
244
				default:
245
					Incorrect_Syntax_Exception::raise( 'Unsupported storage key pattern type used: "' . $type . '"' );
246
					break;
247
			}
248
		}
249
		return false;
250
	}
251
252
	/**
253
	 * Check if an array of segments has all of it's segments
254
	 * 
255
	 * @param array<string> $segments_array
256
	 * @return bool
257
	 */
258
	public function is_segments_array_full( $segments_array ) {
259
		return ( count( $segments_array ) === static::TOTAL_SEGMENTS );
260
	}
261
262
	/**
263
	 * Convert a storage key to an array of it's segments
264
	 * 
265
	 * @param string $storage_key
266
	 * @return array<string>
267
	 */
268
	public function storage_key_to_segments_array( $storage_key ) {
269
		$key = substr( $storage_key, 1 ); // drop the key prefix
270
		$segments = explode( static::SEGMENT_GLUE, $key );
271
		return $segments;
272
	}
273
274
	/**
275
	 * Convert a segment to an array of it's values
276
	 * 
277
	 * @param string $segment
278
	 * @return array<mixed>
279
	 */
280
	public function segment_to_segment_values_array( $segment ) {
281
		return explode( static::SEGMENT_VALUE_GLUE , $segment );
282
	}
283
284
	/**
285
	 * Get a parsed array of storage key segments and values
286
	 * 
287
	 * @param string $storage_key
288
	 * @return array
289
	 */
290
	public function parse_storage_key( $storage_key ) {
291
		$parsed = array(
292
			'root'=>'',
0 ignored issues
show
introduced by
Expected 1 space before "=>"; 0 found
Loading history...
introduced by
Expected 1 space after "=>"; 0 found
Loading history...
293
			'hierarchy'=>array(),
0 ignored issues
show
introduced by
Expected 1 space before "=>"; 0 found
Loading history...
introduced by
Expected 1 space after "=>"; 0 found
Loading history...
294
			'hierarchy_index'=>array( 0 ),
0 ignored issues
show
introduced by
Expected 1 space before "=>"; 0 found
Loading history...
introduced by
Expected 1 space after "=>"; 0 found
Loading history...
295
			'value_index'=>0,
0 ignored issues
show
introduced by
Expected 1 space before "=>"; 0 found
Loading history...
introduced by
Expected 1 space after "=>"; 0 found
Loading history...
296
			'property'=>Value_Set::VALUE_PROPERTY,
0 ignored issues
show
introduced by
Expected 1 space before "=>"; 0 found
Loading history...
introduced by
Expected 1 space after "=>"; 0 found
Loading history...
297
		);
298
299
		$segments = $this->storage_key_to_segments_array( $storage_key );
300
		$parsed['root'] = $segments[0];
301
		if ( $this->is_segments_array_full( $segments ) ) {
302
			if ( ! empty( $segments[1] ) ) {
303
				$parsed['hierarchy'] = explode( static::SEGMENT_VALUE_GLUE, $segments[1] );
304
			}
305
			if ( ! empty( $segments[2] ) ) {
306
				$parsed['hierarchy_index'] = array_map( 'intval', explode( static::SEGMENT_VALUE_GLUE, $segments[2] ) );
307
			}
308
			$parsed['value_index'] = intval( $segments[3] );
309
			$parsed['property'] = $segments[4];
310
		}
311
312
		// Add utility values
313
		$parsed['full_hierarchy'] = array_merge( array( $parsed['root'] ), $parsed['hierarchy'] );
314
315
		return $parsed;
316
	}
317
}