Completed
Push — milestone/2.0 ( 00cc11...2fc31a )
by
unknown
06:58
created

Key_Toolset   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 326
Duplicated Lines 2.45 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 83.45%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 8
loc 326
ccs 116
cts 139
cp 0.8345
rs 9.3999
wmc 33
lcom 1
cbo 1

14 Methods

Rating   Name   Duplication   Size   Complexity  
A get_storage_key_root() 0 5 1
A get_sanitized_hierarchy_index() 0 8 2
A get_storage_key_for_simple_root_field() 0 4 1
A get_storage_key_prefix() 0 15 1
A get_storage_key() 0 8 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() 4 17 3
B storage_key_patterns_to_sql() 0 22 4
A storage_key_matches_any_pattern() 0 15 4
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
use \Carbon_Fields\Exception\Incorrect_Syntax_Exception;
7
8
class Key_Toolset {
9
10
	/**
11
	 * Prefix appended to all keys
12
	 */
13
	const KEY_PREFIX = '_';
14
15
	/**
16
	 * Glue characters between segments in keys
17
	 */
18
	const SEGMENT_GLUE = '|';
19
20
	/**
21
	 * Glue characters between segments values in keys
22
	 */
23
	const SEGMENT_VALUE_GLUE = ':';
24
25
	/**
26
	 * Number of segments in a key
27
	 */
28
	const TOTAL_SEGMENTS = 5;
29
30
	/**
31
	 * "Equal" storage key pattern comparison type constant
32
	 */
33
	const PATTERN_COMPARISON_EQUAL = '=';
34
35
	/**
36
	 * "Starts with" storage key pattern comparison type constant
37
	 */
38
	const PATTERN_COMPARISON_STARTS_WITH = '^';
39
40
	/**
41
	 * Get sanitized hierarchy index for hierarchy
42
	 *
43
	 * @param array<string> $full_hierarchy
44
	 * @param array<int> $full_hierarchy_index
45
	 * @return array<int>
46
	 */
47 4
	public function get_sanitized_hierarchy_index( $full_hierarchy, $full_hierarchy_index ) {
48 4
		$full_hierarchy_index = array_slice( $full_hierarchy_index, 0, count( $full_hierarchy ) - 1 );
49 4
		if ( empty( $full_hierarchy_index ) ) {
50 1
			$full_hierarchy_index = array( 0 );
51 1
		}
52 4
		$full_hierarchy_index = array_map( 'intval', $full_hierarchy_index );
53 4
		return $full_hierarchy_index;
54
	}
55
56
	/**
57
	 * Get a storage key for a simple root field
58
	 *
59
	 * @param string $field_base_name
60
	 * @return string
61
	 */
62
	protected function get_storage_key_for_simple_root_field( $field_base_name ) {
63
		$storage_key = static::KEY_PREFIX . $field_base_name;
64
		return $storage_key;
65
	}
66
67
	/**
68
	 * Get a storage key for the root field
69
	 * Suitable for deleting entire trees of values (e.g. Complex_Field)
70
	 *
71
	 * @param array $full_hierarchy
72
	 * @return string
73
	 */
74
	protected function get_storage_key_root( $full_hierarchy ) {
75
		$first_parent = array_shift( $full_hierarchy );
76
		$storage_key = static::KEY_PREFIX . $first_parent . static::SEGMENT_GLUE;
77
		return $storage_key;
78
	}
79
80
	/**
81
	 * Get a storage key up to the hierarchy index segment
82
	 * Suitable for getting and deleting multiple values for a single field
83
	 *
84
	 * @param array<string> $full_hierarchy
85
	 * @param array<int> $full_hierarchy_index
86
	 * @return string
87
	 */
88
	protected function get_storage_key_prefix( $full_hierarchy, $full_hierarchy_index ) {
89
		$full_hierarchy_index = $this->get_sanitized_hierarchy_index( $full_hierarchy, $full_hierarchy_index );
90
		$parents = $full_hierarchy;
91
		$first_parent = array_shift( $parents );
92
93
		$storage_key = static::KEY_PREFIX . 
94
			$first_parent . 
95
			static::SEGMENT_GLUE . 
96
			implode( static::SEGMENT_VALUE_GLUE, $parents ) . 
97
			static::SEGMENT_GLUE . 
98
			implode( static::SEGMENT_VALUE_GLUE, $full_hierarchy_index ) . 
99
			static::SEGMENT_GLUE;
100
101
		return $storage_key;
102
	}
103
104
	/**
105
	 * Get a full storage key for a single field value
106
	 *
107
	 * @param bool $is_simple_root_field
108
	 * @param array<string> $full_hierarchy
109
	 * @param array<int> $full_hierarchy_index
110
	 * @param int $value_group_index
111
	 * @param string $value_key
112
	 * @return string
113
	 */
114 6
	public function get_storage_key( $is_simple_root_field, $full_hierarchy, $full_hierarchy_index, $value_group_index, $value_key ) {
115 6
		$full_hierarchy_index = $this->get_sanitized_hierarchy_index( $full_hierarchy, $full_hierarchy_index );
116 6
		if ( $is_simple_root_field && $value_key === Value_Set::VALUE_PROPERTY ) {
117 2
			return $this->get_storage_key_for_simple_root_field( array_shift( $full_hierarchy ) );
118
		}
119 4
		$storage_key = $this->get_storage_key_prefix( $full_hierarchy, $full_hierarchy_index ) . intval( $value_group_index ) . static::SEGMENT_GLUE . $value_key;
120 4
		return $storage_key;
121
	}
122
123
	/**
124
	 * Get a full storage key with optional wildcards for entry and value indexes
125
	 *
126
	 * @param bool $is_simple_root_field
127
	 * @param array<string> $full_hierarchy
128
	 * @param string $value_key
129
	 * @param string $wildcard
130
	 * @return string
131
	 */
132 3
	public function get_storage_key_with_index_wildcards( $is_simple_root_field, $full_hierarchy, $value_key = Value_Set::VALUE_PROPERTY, $wildcard = '%' ) {
133 3
		if ( $is_simple_root_field && $value_key === Value_Set::VALUE_PROPERTY ) {
134 1
			return $this->get_storage_key_for_simple_root_field( array_shift( $full_hierarchy ) );
135
		}
136
137 2
		$parents = $full_hierarchy;
138 2
		$first_parent = array_shift( $parents );
139 2
		$hierarchy = array_slice( $full_hierarchy, 0, -1 );
140 2
		$hierarchy_index = ! empty( $hierarchy ) ? $wildcard : '0';
141 2
		$value_group_index = $wildcard;
142
143 2
		$storage_key = static::KEY_PREFIX . 
144 2
			$first_parent . 
145 2
			static::SEGMENT_GLUE . 
146 2
			implode( static::SEGMENT_VALUE_GLUE, $parents ) . 
147 2
			static::SEGMENT_GLUE . 
148 2
			$hierarchy_index . 
149 2
			static::SEGMENT_GLUE . 
150 2
			$value_group_index . 
151 2
			static::SEGMENT_GLUE . 
152 2
			$value_key;
153 2
		return $storage_key;
154
	}
155
156
	/**
157
	 * Get an array of storage key patterns for use when getting values from storage
158
	 *
159
	 * @param bool $is_simple_root_field
160
	 * @param array<string> $full_hierarchy
161
	 * @return array
162
	 */
163 3
	public function get_storage_key_getter_patterns( $is_simple_root_field, $full_hierarchy ) {
164 3
		$patterns = array();
165
166 3 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...
167 1
			$key = $this->get_storage_key_for_simple_root_field( $full_hierarchy[ count( $full_hierarchy ) - 1 ] );
168 1
			$patterns[ $key ] = static::PATTERN_COMPARISON_EQUAL;
169 1
		}
170
		
171 3
		$parents = $full_hierarchy;
172 3
		$first_parent = array_shift( $parents );
173
174 3
		$storage_key = static::KEY_PREFIX . $first_parent . static::SEGMENT_GLUE;
175 3
		if ( empty( $parents ) ) {
176 2
			$patterns[ $storage_key ] = static::PATTERN_COMPARISON_STARTS_WITH;
177 2
		} else {
178 1
			$key = $storage_key . implode( static::SEGMENT_VALUE_GLUE, $parents ) . static::SEGMENT_GLUE;
179 1
			$patterns[ $key ] = static::PATTERN_COMPARISON_STARTS_WITH;
180
181 1
			$key = $storage_key . implode( static::SEGMENT_VALUE_GLUE, $parents ) . static::SEGMENT_VALUE_GLUE;
182 1
			$patterns[ $key ] = static::PATTERN_COMPARISON_STARTS_WITH;
183
		}
184
185 3
		return $patterns;
186
	}
187
188
	/**
189
	 * Get an array of storage key patterns for use when deleting values from storage
190
	 *
191
	 * @param bool $is_complex_field
192
	 * @param bool $is_simple_root_field
193
	 * @param array<string> $full_hierarchy
194
	 * @param array<int> $full_hierarchy_index
195
	 * @return array
196
	 */
197 4
	public function get_storage_key_deleter_patterns( $is_complex_field, $is_simple_root_field, $full_hierarchy, $full_hierarchy_index ) {
198 4
		$full_hierarchy_index = $this->get_sanitized_hierarchy_index( $full_hierarchy, $full_hierarchy_index );
199 4
		$patterns = array();
200
		
201 4 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...
202 1
			$key = $this->get_storage_key_for_simple_root_field( $full_hierarchy[ count( $full_hierarchy ) - 1 ] );
203 1
			$patterns[ $key ] = static::PATTERN_COMPARISON_EQUAL;
204 1
		}
205
		
206 4
		if ( $is_complex_field ) {
207 2
			$patterns[ $this->get_storage_key_root( $full_hierarchy ) ] = static::PATTERN_COMPARISON_STARTS_WITH;
208 2
		} else {
209 2
			$patterns[ $this->get_storage_key_prefix( $full_hierarchy, $full_hierarchy_index ) ] = static::PATTERN_COMPARISON_STARTS_WITH;
210
		}
211
212 4
		return $patterns;
213
	}
214
215
	/**
216
	 * Convert an array of storage key patterns to a parentheses-enclosed sql comparison
217
	 *
218
	 * @param string $table_column
219
	 * @param array $patterns
220
	 * @return string
221
	 */
222 2
	public function storage_key_patterns_to_sql( $table_column, $patterns ) {
223 2
		$sql = array();
224
225 2
		foreach ( $patterns as $storage_key => $type ) {
226 2
			$comparison = '';
227
			switch ( $type ) {
228 2
				case static::PATTERN_COMPARISON_EQUAL:
229 1
					$comparison = $table_column . ' = "' . esc_sql( $storage_key ) . '"';
230 1
					break;
231 2
				case static::PATTERN_COMPARISON_STARTS_WITH:
232 1
					$comparison = $table_column . ' LIKE "' . esc_sql( $storage_key ) . '%"';
233 1
					break;
234 1
				default:
235 1
					Incorrect_Syntax_Exception::raise( 'Unsupported storage key pattern type used: "' . $type . '"' );
236
					break;
237 1
			}
238
239 1
			$sql[] = $comparison;
240 1
		}
241
242 1
		return ' ( ' . implode( ' OR ', $sql ) . ' ) ';
243
	}
244
245
	/**
246
	 * Check if a storage key matches any pattern
247
	 * 
248
	 * @param string $storage_key
249
	 * @param array $patterns
250
	 * @return bool
251
	 */
252 7
	public function storage_key_matches_any_pattern( $storage_key, $patterns ) {
253 7
		foreach ( $patterns as $key => $type ) {
254
			switch ( $type ) {
255 7
				case static::PATTERN_COMPARISON_EQUAL:
256 4
					return ( $storage_key === $key );
257 3
				case static::PATTERN_COMPARISON_STARTS_WITH:
258 2
					$key_length = strlen( $key );
259 2
					return ( substr( $storage_key, 0, $key_length ) === $key );
260 1
				default:
261 1
					Incorrect_Syntax_Exception::raise( 'Unsupported storage key pattern type used: "' . $type . '"' );
262
					break;
263 1
			}
264
		}
265
		return false;
266
	}
267
268
	/**
269
	 * Check if an array of segments has all of it's segments
270
	 * 
271
	 * @param array<string> $segments_array
272
	 * @return bool
273
	 */
274 1
	public function is_segments_array_full( $segments_array ) {
275 1
		return ( count( $segments_array ) === static::TOTAL_SEGMENTS );
276
	}
277
278
	/**
279
	 * Convert a storage key to an array of it's segments
280
	 * 
281
	 * @param string $storage_key
282
	 * @return array<string>
283
	 */
284 1
	public function storage_key_to_segments_array( $storage_key ) {
285 1
		$key = substr( $storage_key, 1 ); // drop the key prefix
286 1
		$segments = explode( static::SEGMENT_GLUE, $key );
287 1
		return $segments;
288
	}
289
290
	/**
291
	 * Convert a segment to an array of it's values
292
	 * 
293
	 * @param string $segment
294
	 * @return array<mixed>
295
	 */
296 1
	public function segment_to_segment_values_array( $segment ) {
297 1
		return explode( static::SEGMENT_VALUE_GLUE , $segment );
298
	}
299
300
	/**
301
	 * Get a parsed array of storage key segments and values
302
	 * 
303
	 * @param string $storage_key
304
	 * @return array
305
	 */
306 3
	public function parse_storage_key( $storage_key ) {
307
		$parsed = array(
308 3
			'root' => '',
309 3
			'hierarchy' => array(),
310 3
			'hierarchy_index' => array( 0 ),
311 3
			'value_index' => 0,
312 3
			'property' => Value_Set::VALUE_PROPERTY,
313 3
		);
314
315 3
		$segments = $this->storage_key_to_segments_array( $storage_key );
316 3
		$parsed['root'] = $segments[0];
317 3
		if ( $this->is_segments_array_full( $segments ) ) {
318 2
			if ( ! empty( $segments[1] ) ) {
319 1
				$parsed['hierarchy'] = explode( static::SEGMENT_VALUE_GLUE, $segments[1] );
320 1
			}
321 2
			if ( ! empty( $segments[2] ) ) {
322 2
				$parsed['hierarchy_index'] = array_map( 'intval', explode( static::SEGMENT_VALUE_GLUE, $segments[2] ) );
323 2
			}
324 2
			$parsed['value_index'] = intval( $segments[3] );
325 2
			$parsed['property'] = $segments[4];
326 2
		}
327
328
		// Add utility values
329 3
		$parsed['full_hierarchy'] = array_merge( array( $parsed['root'] ), $parsed['hierarchy'] );
330
331 3
		return $parsed;
332
	}
333
}