Index: search_api.admin.css =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/search_api/Attic/search_api.admin.css,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 search_api.admin.css --- search_api.admin.css 7 Nov 2010 17:24:16 -0000 1.1.2.2 +++ search_api.admin.css 7 Jan 2011 22:23:29 -0000 @@ -34,3 +34,10 @@ input.search-api-cron-limit { text-align: right; } + +/* Workaround for http://drupal.org/node/1015798 */ +.vertical-tabs fieldset div.fieldset-wrapper fieldset legend { + display: block; + margin-bottom: 2em; +} + Index: search_api.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/search_api/search_api.module,v retrieving revision 1.1.2.83 diff -u -r1.1.2.83 search_api.module --- search_api.module 7 Jan 2011 18:58:02 -0000 1.1.2.83 +++ search_api.module 7 Jan 2011 22:23:30 -0000 @@ -625,10 +625,8 @@ 'class' => 'SearchApiAlterAddUrl', ); $callbacks['search_api_alter_add_fulltext'] = array( - 'name' => t('Fulltext field'), - 'description' => t("Adds a fulltext summary field to the data, incorporating all of the item's fulltext data. " . - 'Note that this will aggregate all fields whose type is "@type", not only those configured as indexed.', - array('@type' => t('Fulltext'))), + 'name' => t('Fulltext fields'), + 'description' => t('Gives you the ability to define additional fulltext fields, containing the text data from one or more other fields.'), 'class' => 'SearchApiAlterAddFulltext', ); Index: README.txt =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/search_api/Attic/README.txt,v retrieving revision 1.1.2.6 diff -u -r1.1.2.6 README.txt --- README.txt 17 Dec 2010 12:28:11 -0000 1.1.2.6 +++ README.txt 7 Jan 2011 22:23:29 -0000 @@ -270,8 +270,10 @@ * URL field Provides a field with the URL for displaying the entity. * Fulltext field - Aggregates the contents of all fields set to the "Fulltext" type, for - searching an entity's complete fulltext data in a single field. + Offers the ability to add additional fulltext fields to the entity, + containing the data from one or more other fields. Use this, e.g., to have a + single field containing all data that should be searchable, or to make the + text from a string field, like a taxonomy term, also fulltext-searchable. - Processors Index: includes/callback_add_fulltext.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/search_api/includes/Attic/callback_add_fulltext.inc,v retrieving revision 1.1.2.1 diff -u -r1.1.2.1 callback_add_fulltext.inc --- includes/callback_add_fulltext.inc 4 Jan 2011 22:18:57 -0000 1.1.2.1 +++ includes/callback_add_fulltext.inc 7 Jan 2011 22:23:30 -0000 @@ -6,58 +6,129 @@ */ class SearchApiAlterAddFulltext extends SearchApiAbstractAlterCallback { - public function alterItems(array &$items) { - if (empty($this->index->options['fields'])) { - $fields = FALSE; + public function configurationForm() { + // Workaround for http://drupal.org/node/1015798 + drupal_add_css(drupal_get_path('module', 'search_api') . '/search_api.admin.css'); + + $fields = empty($this->index->options['fields']) ? _search_api_admin_get_fields($this->index, $this->index->entityWrapper()) : $this->index->options; + $fields = $fields['fields']; + $field_options = array(); + foreach ($fields as $name => $field) { + $field_options[$name] = $field['name']; } - else { - $fields = array_intersect_key($this->index->options['fields'], drupal_map_assoc($this->index->getFulltextFields())); + $additional = empty($this->options['fields']) ? array() : $this->options['fields']; + foreach ($additional as $name => $field) { + if (!$field['name']) { + unset($additional[$name]); + if (!isset($first_free_name)) { + $first_free_name = $name; + } + } } - foreach ($items as $id => &$item) { - $wrapper = entity_metadata_wrapper($this->index->entity_type, $item); - $text = ''; - if ($fields) { - foreach (array_keys($fields) as $field) { - try { - $tmp = $wrapper; - foreach (explode(':', $field) as $property) { - if (!isset($tmp->$property)) { - // This can especially happen for fields added by data alter callbacks – e.g., this one. - $tmp = FALSE; - break; - } - $tmp = $tmp->$property; - } - if ($tmp) { - $text .= $tmp->value() . "\n\n"; - } - } - catch (Exception $e) { - // This might happen for entity fields that are NULL, e.g. comments without parent. - // We just ignore the field, then. + $additional[isset($first_free_name) ? $first_free_name : 'search_api_fulltext_' . (count($additional) + 1)] = array( + 'name' => '', + 'fields' => array(), + ); + $form['description'] = array( + '#markup' => '

' . t('Change the name or aggregated fields of one of the additional fulltext fields below, or add a new one by filling out the "New field" form. By deleting a name, you can remove previously added fields.') . '

', + ); + foreach ($additional as $name => $field) { + $form['fields'][$name] = array( + '#type' => 'fieldset', + '#title' => $field['name'] ? $field['name'] : t('New field'), + '#collapsible' => TRUE, + '#collapsed' => (boolean) $field['name'], + ); + $form['fields'][$name]['name'] = array( + '#type' => 'textfield', + '#title' => t('Field name'), + '#default_value' => $field['name'], + ); + $form['fields'][$name]['fields'] = array( + '#type' => 'select', + '#title' => t('Contained fields'), + '#options' => $field_options, + '#size' => min(count($field_options), 5), + '#multiple' => TRUE, + '#default_value' => $field['fields'], + ); + } + return $form; + } + + public function alterItems(array &$items) { + if (!$items) { + return; + } + $required_fields = array(); + foreach ($this->options['fields'] as $name => $field) { + if ($field['name']) { + foreach ($field['fields'] as $f) { + if (!isset($required_fields[$f])) { + $required_fields[$f]['type'] = 'fulltext'; } } } - else { - foreach ($wrapper as $key => $field) { - $info = $field->info(); - if ($info['type'] == 'text') { - $text .= $field->value() . "\n\n"; + } + foreach ($items as $item) { + $wrapper = $this->index->entityWrapper($item); + $fields = search_api_extract_fields($wrapper, $required_fields); + foreach ($this->options['fields'] as $name => $field) { + if ($field['name']) { + $item->$name = ''; + foreach ($field['fields'] as $f) { + if (isset($fields[$f]['value'])) { + $item->$name .= ($item->$name ? "\n\n" : '') . $this->collapseArray($fields[$f]['value']); + } } } } - $item->search_api_fulltext = $text; } } + /** + * Helper method for collapsing array values into a string. + */ + protected function collapseArray($data) { + if (!is_array($data)) { + return $data; + } + if (!$data) { + return ''; + } + $ret = array(); + foreach ($data as $item) { + $item = $this->collapseArray($item); + if ($item) { + $ret[] = $item; + } + } + return implode("\n", $ret); + } + public function propertyInfo() { - return array( - 'search_api_fulltext' => array( - 'label' => t('Fulltext'), - 'description' => t('The aggregated content of all fulltext fields.'), - 'type' => 'text', - ), - ); + $ret = array(); + foreach ($this->options['fields'] as $name => $field) { + if ($field['name']) { + $ret[$name] = array( + 'label' => $field['name'], + 'description' => $this->fieldDescription($field), + 'type' => 'text', + ); + } + } + return $ret; + } + + /** + * Helper method for creating a field description. + */ + protected function fieldDescription(array $field) { + $fields = array(); + foreach ($field['fields'] as $f) { + $fields[] = isset($this->index->options['fields'][$f]) ? $this->index->options['fields'][$f]['name'] : $f; + } + return t('A fulltext aggregation of the following fields: @fields.', array('@fields' => implode(', ', $fields))); } }