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

Key_Value_Datastore   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 167
Duplicated Lines 13.17 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 22
loc 167
ccs 0
cts 74
cp 0
rs 10
wmc 21
lcom 1
cbo 5

7 Methods

Rating   Name   Duplication   Size   Complexity  
A get_full_hierarchy_for_field() 0 4 1
A get_full_hierarchy_index_for_field() 0 5 2
C cascading_storage_array_to_raw_value_set_tree() 0 49 11
get_storage_array() 0 1 ?
A load() 0 6 1
save_key_value_pair() 0 1 ?
B save() 22 29 6

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\Datastore;
4
5
use \Carbon_Fields\App;
6
use \Carbon_Fields\Helper\Helper;
7
use \Carbon_Fields\Field\Field;
8
use \Carbon_Fields\Value_Set\Value_Set;
9
use \Carbon_Fields\Exception\Incorrect_Syntax_Exception;
10
11
/**
12
 * Key Value Datastore
13
 * Provides basic functionality to save in a key-value storage
14
 *
15
 * Key schema:
16
 * _[root_field_name]|[parent:field:names:separated:with:colons]|[complex:group:indexes:separated:with:colons]|[value_index]|[value_key/property]
17
 *
18
 * Example:
19
 * _countries|major_cities:name|0:1|0|value
20
 * This key is for a field called "name" inside the complex field "major_cities" with group index 1, which is inside the complex field "countries" with group index 0
21
 */
22
abstract class Key_Value_Datastore extends Datastore {
23
24
	/**
25
	 * Value key to use for fields which need to be kept "alive" when they have no values stored (e.g. Set field with 0 checkboxes checked)
26
	 * Required to determine whether a field should use it's default value or stay blank
27
	 *
28
	 * @var string
29
	 **/
30
	const KEEPALIVE_KEY = '_empty';
31
32
	/**
33
	 * Get array of ancestors (ordered top-bottom) with the field name appended to the end
34
	 *
35
	 * @param Field $field
36
	 * @return array<string>
37
	 **/
38
	protected function get_full_hierarchy_for_field( Field $field ) {
39
		$full_hierarchy = array_merge( $field->get_hierarchy(), array( $field->get_base_name() ) );
40
		return $full_hierarchy;
41
	}
42
43
	/**
44
	 * Get array of ancestor entry indexes (ordered top-bottom)
45
	 * Indexes show which entry/group this field belongs to in a Complex_Field
46
	 *
47
	 * @param Field $field
48
	 * @return array<int>
49
	 **/
50
	protected function get_full_hierarchy_index_for_field( Field $field ) {
51
		$hierarchy_index = $field->get_hierarchy_index();
52
		$full_hierarchy_index = ! empty( $hierarchy_index ) ? $hierarchy_index : array( 0 );
53
		return $full_hierarchy_index;
54
	}
55
56
	/**
57
	 * Raw Value Set Tree schema:
58
	 * array(
59
	 *     [field_name] => array(
60
	 *         'value_set'=>[raw_value_set],
61
	 *         'groups'=>array(
62
	 *             array(
63
	 *                 [recursion]
64
	 *             ),
65
	 *             ...
66
	 *         ),
67
	 *     ),
68
	 *     ...
69
	 * )
70
	 *
71
	 * @param array<stdClass> $storage_array
72
	 * @return array
73
	 */
74
	protected function cascading_storage_array_to_raw_value_set_tree( $storage_array ) {
75
		$tree = array();
76
77
		foreach ( $storage_array as $row ) {
78
			$parsed_storage_key = $this->key_toolset->parse_storage_key( $row->key );
79
80
			if ( $parsed_storage_key['property'] === static::KEEPALIVE_KEY ) {
81
				continue;
82
			}
83
84
			$level = &$tree;
85
			foreach ( $parsed_storage_key['full_hierarchy'] as $i => $field_name ) {
86
				$index = isset( $parsed_storage_key['hierarchy_index'][ $i ] ) ? $parsed_storage_key['hierarchy_index'][ $i ] : -1;
87
88
				if ( ! isset( $level[ $field_name ] ) ) {
89
					$level[ $field_name ] = array();
90
				}
91
				$level = &$level[ $field_name ];
92
93
				if ( $i < count( $parsed_storage_key['full_hierarchy'] ) - 1 ) {
94
					if ( ! isset( $level['groups'] ) ) {
95
						$level['groups'] = array();
96
					}
97
					$level = &$level['groups'];
98
99
					if ( ! isset( $level[ $index ] ) ) {
100
						$level[ $index ] = array();
101
					}
102
					$level = &$level[ $index ];
103
				} else  {
104
					if ( ! isset( $level['value_set'] ) ) {
105
						$level['value_set'] = array();
106
					}
107
					$level = &$level['value_set'];
108
109
					if ( ! isset( $level[ $parsed_storage_key['value_index'] ] ) ) {
110
						$level[ $parsed_storage_key['value_index'] ] = array();
111
					}
112
					$level = &$level[ $parsed_storage_key['value_index'] ];
113
114
					$level[ $parsed_storage_key['property'] ] = $row->value;
115
				}
116
			}
117
			$level = &$tree;
118
		}
119
120
		Helper::ksort_recursive( $tree );
121
		return $tree;
122
	}
123
124
	/**
125
	 * Get a raw database query results array for a field
126
	 *
127
	 * @param Field $field The field to retrieve value for.
128
	 * @param array $storage_key_patterns
129
	 * @return array<stdClass> Array of {key, value} objects
130
	 */
131
	abstract protected function get_storage_array( Field $field, $storage_key_patterns );
132
133
	/**
134
	 * Get the field value(s)
135
	 *
136
	 * @param Field $field The field to get value(s) for
137
	 * @return array<array>
138
	 */
139
	public function load( Field $field ) {
140
		$storage_key_patterns = $this->key_toolset->get_storage_key_getter_patterns( $field->is_simple_root_field(), $this->get_full_hierarchy_for_field( $field ) );
141
		$cascading_storage_array = $this->get_storage_array( $field, $storage_key_patterns );
142
		$raw_value_set_tree = $this->cascading_storage_array_to_raw_value_set_tree( $cascading_storage_array );
143
		return $raw_value_set_tree;
144
	}
145
146
	/**
147
	 * Save a single key-value pair to the database
148
	 *
149
	 * @param string $key
150
	 * @param string $value
151
	 */
152
	abstract protected function save_key_value_pair( $key, $value );
153
154
	/**
155
	 * Save the field value(s)
156
	 *
157
	 * @param Field $field The field to save.
158
	 */
159
	public function save( Field $field ) {
160
		$value_set = $field->value()->get_set();
161
		if ( $value_set === null ) {
162
			return;
163
		}
164
165 View Code Duplication
		if ( empty( $value_set ) && $field->value()->keepalive() ) {
166
			$storage_key = $this->key_toolset->get_storage_key(
167
				$field->is_simple_root_field(),
168
				$this->get_full_hierarchy_for_field( $field ),
169
				$this->get_full_hierarchy_index_for_field( $field ),
170
				0,
171
				static::KEEPALIVE_KEY
172
			);
173
			$this->save_key_value_pair( $storage_key, '' );
174
		}
175 View Code Duplication
		foreach ( $value_set as $value_group_index => $values ) {
176
			foreach ( $values as $value_key => $value ) {
177
				$storage_key = $this->key_toolset->get_storage_key(
178
					$field->is_simple_root_field(),
179
					$this->get_full_hierarchy_for_field( $field ),
180
					$this->get_full_hierarchy_index_for_field( $field ),
181
					$value_group_index,
182
					$value_key
183
				);
184
				$this->save_key_value_pair( $storage_key, $value );
185
			}
186
		}
187
	}
188
}
189