diff --git a/includes/index_entity.inc b/includes/index_entity.inc index 35f0769..f910972 100644 --- a/includes/index_entity.inc +++ b/includes/index_entity.inc @@ -111,10 +111,13 @@ class SearchApiIndex extends Entity { * - name: The human-readable name for the field. * - indexed: Boolean indicating whether the field is indexed or not. * - type: The type set for this field. One of the types returned by - * search_api_field_types(). + * search_api_default_field_types(). + * - real_type: (optional) If a custom data type was selected for this + * field, this type will be stored here, and "type" contain the fallback + * default data type. * - boost: A boost value for terms found in this field during searches. * Usually only relevant for fulltext fields. - * - entity_type (optional): If set, the type of this field is really an + * - entity_type: (optional) If set, the type of this field is really an * entity. The "type" key will then contain "integer", meaning that * servers will ignore this and merely index the entity's ID. Components * displaying this field, though, are advised to use the entity label @@ -420,7 +423,16 @@ class SearchApiIndex extends Entity { if (!$info['indexed']) { unset($fields[$field]); } - unset($fields[$field]['indexed']); + else { + if (isset($info['real_type'])) { + $custom_type = search_api_extract_inner_type($info['real_type']); + if ($this->server()->supportsFeature('search_api_data_type_' . $custom_type)) { + $fields[$field]['type'] = $info['real_type']; + $this->options['fields'][$field]['type'] = $info['real_type']; + } + } + unset($fields[$field]['indexed']); + } } if (empty($fields)) { throw new SearchApiException(t("Couldn't index values on '!name' index (no fields selected)", array('!name' => $this->name))); diff --git a/search_api.admin.inc b/search_api.admin.inc index 6854d83..2f25269 100644 --- a/search_api.admin.inc +++ b/search_api.admin.inc @@ -1459,6 +1459,7 @@ function search_api_admin_index_fields(array $form, array &$form_state, SearchAp $types = array(0 => search_api_field_types()); $fulltext_type = array(0 => 'text'); $entity_types = entity_get_info(); + $default_types = search_api_default_field_types(); $boosts = drupal_map_assoc(array('0.1', '0.2', '0.3', '0.5', '0.8', '1.0', '2.0', '3.0', '5.0', '8.0', '13.0', '21.0')); $form_state['index'] = $index; @@ -1493,7 +1494,7 @@ function search_api_admin_index_fields(array $form, array &$form_state, SearchAp '#default_value' => $info['indexed'], ); $inner_type = search_api_extract_inner_type($info['type']); - if (isset($types[0][$inner_type])) { + if (isset($default_types[$inner_type])) { // Determine the correct type options (i.e., with the correct nesting level). $level = search_api_list_nesting_level($info['type']); if (empty($types[$level])) { @@ -1510,7 +1511,7 @@ function search_api_admin_index_fields(array $form, array &$form_state, SearchAp $form['fields'][$key]['type'] = array( '#type' => 'select', '#options' => $types[$level], - '#default_value' => $info['type'], + '#default_value' => isset($info['real_type']) ? $info['real_type'] : $info['type'], '#states' => array( 'visible' => array( $css_key . '-indexed' => array('checked' => TRUE), @@ -1546,7 +1547,7 @@ function search_api_admin_index_fields(array $form, array &$form_state, SearchAp ); $form['fields'][$key]['entity_type'] = array( '#type' => 'value', - '#value' => search_api_extract_inner_type($info['type']), + '#value' => $inner_type, ); $form['fields'][$key]['type_name'] = array( '#markup' => check_plain($entity_types[$inner_type]['label']), @@ -1627,7 +1628,7 @@ function _search_api_admin_get_fields(SearchApiIndex $index, EntityMetadataWrapp // The list nesting level for entities with a certain prefix $nesting_levels = array('' => 0); - $types = search_api_field_types(); + $types = search_api_default_field_types(); $flat = array(); while ($wrappers) { foreach ($wrappers as $prefix => $wrapper) { @@ -1651,7 +1652,7 @@ function _search_api_admin_get_fields(SearchApiIndex $index, EntityMetadataWrapp $type = search_api_extract_inner_type($info['type']); // Treat Entity API type "token" as our "string" type. // Also let text fields with limited options be of type "string" by default. - if ($type == 'token' || ($type == 'text' && $value->optionsList('view'))) { + if ($type == 'token' || ($type == 'text' && !empty($info['options list']))) { // Inner type is changed to "string". $type = 'string'; // Set the field type accordingly. @@ -1672,7 +1673,9 @@ function _search_api_admin_get_fields(SearchApiIndex $index, EntityMetadataWrapp } else { // Else, only update the nesting level. - $flat[$key]['type'] = search_api_nest_type(search_api_extract_inner_type($flat[$key]['type']), $info['type']); + $set_type = search_api_extract_inner_type(isset($flat[$key]['real_type']) ? $flat[$key]['real_type'] : $flat[$key]['type']); + $flat[$key]['type'] = $info['type']; + $flat[$key]['real_type'] = search_api_nest_type($set_type, $info['type']); } } else { @@ -1768,8 +1771,18 @@ function search_api_admin_index_fields_submit(array $form, array &$form_state) { $options = isset($index->options) ? $index->options : array(); if ($form_state['values']['op'] == t('Save changes')) { $fields = $form_state['values']['fields']; + $default_types = search_api_default_field_types(); + $custom_types = search_api_custom_field_types(); foreach ($fields as $name => &$field) { + // Don't store the description. unset($field['description']); + // For non-default types, set type to the fallback and only real_type to + // the custom type. + $inner_type = search_api_extract_inner_type($field['type']); + if (!isset($default_types[$inner_type])) { + $field['real_type'] = $field['type']; + $field['type'] = search_api_nest_type($custom_types[$inner_type]['fallback'], $field['type']); + } } $options['fields'] = $fields; $ret = $index->update(array('options' => $options)); diff --git a/search_api.api.php b/search_api.api.php index e245a4d..331f27b 100644 --- a/search_api.api.php +++ b/search_api.api.php @@ -129,7 +129,6 @@ function hook_search_api_item_type_info() { * @see hook_search_api_item_type_info() */ function hook_search_api_item_type_info_alter(array &$infos) { - hook_entity_info_alter(); // Adds a boolean value is_entity to all type options telling whether the item // type represents an entity type. foreach ($infos as $type => $info) { @@ -138,6 +137,49 @@ function hook_search_api_item_type_info_alter(array &$infos) { } /** + * Define new data types for indexed properties. + * + * New data types will appear as new option for the „Type“ field on indexes' + * „Fields“ tabs. Whether choosing a custom data type will have any effect + * depends on the server on which the data is indexed. + * + * @return array + * An array containing custom data type definitions, keyed by their type + * identifier and containing the following keys: + * - name: The human-readable name of the type. + * - fallback: (optional) One of the default data types (the keys from + * search_api_default_field_types()) which should be used as a fallback if + * the server doesn't support this data type. Defaults to "string". + * + * @see hook_search_api_data_type_info_alter() + * @see search_api_custom_field_types() + */ +function hook_search_api_data_type_info() { + return array( + 'example_type' => array( + 'name' => t('Example type'), + 'fallback' => 'string',// Could be omitted, as "string" is the default. + ), + ); +} + +/** + * Alter the data type info. + * + * Modules may implement this hook to alter the information that defines a data + * type, or to add/remove some entirely. All properties that are available in + * hook_search_api_data_type_info() can be altered here. + * + * @param array $infos + * The data type info array, keyed by type identifier. + * + * @see hook_search_api_data_type_info() + */ +function hook_search_api_data_type_info_alter(array &$infos) { + $infos['example_type']['name'] .= ' 2'; +} + +/** * Registers one or more callbacks that can be called at index time to add * additional data to the indexed items (e.g. comments or attachments to nodes), * alter the data in other forms or remove items from the array. diff --git a/search_api.module b/search_api.module index 0d8d407..cf63416 100644 --- a/search_api.module +++ b/search_api.module @@ -1071,8 +1071,26 @@ function search_api_current_search($search_id = NULL, SearchApiQuery $query = NU * @return array * An associative array with all recognized types as keys, mapped to their * translated display names. + * + * @see search_api_default_field_types() + * @see search_api_custom_field_types() */ function search_api_field_types() { + $types = search_api_default_field_types(); + foreach (search_api_custom_field_types() as $id => $type) { + $types[$id] = $type['name']; + } + return $types; +} + +/** + * Returns the default field types recognized by the Search API framework. + * + * @return array + * An associative array with the default types as keys, mapped to their + * translated display names. + */ +function search_api_default_field_types() { return array( 'text' => t('Fulltext'), 'string' => t('String'), @@ -1086,6 +1104,38 @@ function search_api_field_types() { } /** + * Returns either all custom field type definitions, or a specific one. + * + * @param $type + * If specified, the type whose definition should be returned. + * + * @return array + * If $type was not given, an array containing all custom data types, in the + * format specified by hook_search_api_data_type_info(). + * Otherwise, the definition for the given type, or NULL if it is unknown. + * + * @see hook_search_api_data_type_info() + */ +function search_api_custom_field_types($type = NULL) { + $types = &drupal_static(__FUNCTION__); + if (!isset($types)) { + $default_types = search_api_default_field_types(); + $types = module_invoke_all('search_api_data_type_info'); + $types = $types ? $types : array(); + foreach ($types as &$type_info) { + if (!isset($type_info['fallback']) || !isset($default_types[$type_info['fallback']])) { + $type_info['fallback'] = 'string'; + } + } + drupal_alter('search_api_data_type_info', $types); + } + if (isset($type)) { + return isset($types[$type]) ? $types[$type] : NULL; + } + return $types; +} + +/** * Returns either a list of all available service infos, or a specific one. * * @see hook_search_api_service_info()