if ( isset( $legacy_storage_array[ $key . '-' . $first_map_key ] ) ) { $value = array( Value_Set::VALUE_PROPERTY => $value, ); foreach ( $this->map_keys as $map_key ) { $value[ $map_key ] = $legacy_storage_array[ $key . '-' . $map_key ]; } } return $value; } /** * Convert legacy storage rows to array of row descriptors * * @param array $legacy_storage_array * @param array $field_group_permutations * @return array */ protected function legacy_storage_rows_to_row_descriptors( $legacy_storage_array, $field_group_permutations ) { $row_descriptors = array(); foreach ( $legacy_storage_array as $key => $value ) { if ( $this->is_legacy_map_key( $key ) ) { continue; // skip legacy map keys as they are handled separately through values } $value = $this->get_value_for_legacy_key( $key, $legacy_storage_array ); $row_descriptors[] = $this->legacy_storage_row_to_row_descriptor( $key, $value, $field_group_permutations ); } return $row_descriptors; } /** * Get key segmentation regex for a field name * * @param string $field_name * @param string $group_name * @return string */ protected function get_key_segmentation_regex_for_field_name( $field_name, $group_name = '' ) { $legacy_group_name = ( $group_name === '_' ) ? $group_name : '_' . $group_name; $regex = '/\A_?' . preg_quote( $field_name, '/' ) . '(?:_(?P\d+))?\z/'; if ( $group_name !== '' ) { $regex = '/\A_?' . preg_quote( $field_name, '/' ) . '(?:_(?P\d+))?' . preg_quote( $legacy_group_name, '/' ) . '\z/'; } return $regex; } /** * Convert legacy storage row to row descriptor * * @param string $key * @param string $value * @param array $field_group_permutations * @return array */ protected function legacy_storage_row_to_row_descriptor( $key, $value, $field_group_permutations ) { $key_pieces = explode( '-', $key ); $field_group_level = $field_group_permutations; $matched_fields = array(); foreach ( $key_pieces as $piece ) { foreach ( $field_group_level as $permutation ) { $match_regex = $this->get_key_segmentation_regex_for_field_name( $permutation['field'], $permutation['group'] ); $matches = array(); if ( preg_match( $match_regex, $piece, $matches ) ) { $match_data = array( 'field' => $permutation['field'], 'group' => $permutation['group'], 'group_index' => ( isset( $matches['group_index'] ) ? intval( $matches['group_index'] ) : -1 ), ); $previous_match_index = count( $matched_fields ) - 1; if ( isset( $matched_fields[ $previous_match_index ] ) ) { $matched_fields[ $previous_match_index ]['group_index'] = $match_data['group_index']; // indexes are offset in CF 1.5 complex keys $match_data['group_index'] = 0; } $matched_fields[] = $match_data; $field_group_level = $permutation['children']; break; // break so next piece foreaches the new field_group_level } } } return array( 'key' => $matched_fields, 'value' => $value, ); } /** * Convert row descriptor to array of new storage key-values * * @param array $row_descriptor * @return array */ protected function row_descriptor_to_storage_array( $row_descriptor ) { $storage_array = array(); $hierarchy = array_map( function( $match ) { return $match['field']; }, $row_descriptor['key'] ); $hierarchy_index = array_map( function( $match ) { return $match['group_index']; }, array_slice( $row_descriptor['key'], 0, -1 ) ); // last index is not part of the hierarchy index $complex_parents = array_slice( $hierarchy, 0, -1 ); foreach ( $complex_parents as $level => $complex_parent ) { $complex_parent_hierarchy_index = array_slice( $hierarchy_index, 0, $level ); $complex_parent_value_index = $hierarchy_index[ $level ]; $key = $this->key_toolset->get_storage_key( false, array_slice( $hierarchy, 0, $level + 1 ), $complex_parent_hierarchy_index, $complex_parent_value_index, Value_Set::VALUE_PROPERTY ); $group_name = $row_descriptor['key'][ $level ]['group']; $storage_array[ $key ] = $group_name; } $unserialized_value = maybe_unserialize( $row_descriptor['value'] ); if ( is_array( $unserialized_value ) ) { if ( isset( $unserialized_value[ Value_Set::VALUE_PROPERTY ] ) ) { // value is a key=>value array - save each property separately foreach ( $unserialized_value as $property => $value_item ) { $key = $this->key_toolset->get_storage_key( false, $hierarchy, $hierarchy_index, 0, $property ); $storage_array[ $key ] = $value_item; } } else { // value is a simple array - save each value separately $i = 0; foreach ( $unserialized_value as $value_item ) { $key = $this->key_toolset->get_storage_key( false, $hierarchy, $hierarchy_index, $i, Value_Set::VALUE_PROPERTY ); $storage_array[ $key ] = $value_item; $i++; } } } else if ( $unserialized_value === null ) { // no value found - add a keepalive key $key = $this->key_toolset->get_storage_key( false, $hierarchy, $hierarchy_index, 0, '_empty' ); $storage_array[ $key ] = ''; } else { if ( count( $hierarchy ) === 1 ) { // Add a basic key as well as simple root fields will load that instead $key = '_' . $hierarchy[0]; $storage_array[ $key ] = $row_descriptor['value']; } $key = $this->key_toolset->get_storage_key( false, $hierarchy, $hierarchy_index, 0, Value_Set::VALUE_PROPERTY ); $storage_array[ $key ] = $row_descriptor['value']; } return $storage_array; } /** * Get all data saved for a datastore in the new key-value format * * @param Datastore_Interface $datastore * @return array */ public function get_storage_array_for_datastore( Datastore_Interface $datastore ) { $legacy_storage_array = $this->get_legacy_storage_array( $datastore ); if ( empty( $legacy_storage_array ) ) { return array(); // no migration data found } $container = $this->get_container_for_datastore( $datastore ); $field_group_permutations = $this->get_field_group_permutations( $container->get_fields() ); $row_descriptors = $this->legacy_storage_rows_to_row_descriptors( $legacy_storage_array, $field_group_permutations ); $storage_array = array(); foreach ( $row_descriptors as $row_descriptor ) { $storage_array = array_merge( $storage_array, $this->row_descriptor_to_storage_array( $row_descriptor ) ); } return $storage_array; } /** * Get array of new storage key-values matching key patterns * * @param Datastore_Interface $datastore * @param array $storage_key_patterns * @return array */ public function get_storage_array( Datastore_Interface $datastore, $storage_key_patterns ) { $storage_array = $this->get_storage_array_for_datastore( $datastore ); $matched_data = array(); foreach ( $storage_array as $key => $value ) { if ( $this->key_toolset->storage_key_matches_any_pattern( $key, $storage_key_patterns ) ) { $matched_data[] = (object) array( 'key' => $key, 'value' => $value, ); } } return $matched_data; } public function filter_storage_array( $storage_array, $datastore, $storage_key_patterns ) { if ( empty( $storage_array ) ) { $storage_array = $this->get_storage_array( $datastore, $storage_key_patterns ); } return $storage_array; } }