diff --git a/README.txt b/README.txt index 2b70246..1da1a85 100644 --- a/README.txt +++ b/README.txt @@ -139,8 +139,19 @@ and any Form API standard properties which use might not be clear: For further information, see the documentation of the fieldCondition() method of the EntityFieldQuery class. - - + + - 'search': Specifies alternate field(s) to search instead of the + label. If more than one field is specified then only + one must match in order for result to be displayed. This + property is an array, with the first element corresponding + to the condition method being called, second field to + the field name. The third field will be 'value', or + if an entity reference it will be 'target_id' + Example of use: + 'search' => array( + array('fieldCondition','field_test_field','value'), + ), + '#default_value': If references to any entities are provided by default, it should be as Entity IDs. For single values, just pass the ID of the referenced entity. For multiple values, an array diff --git a/entityreference_autocomplete.module b/entityreference_autocomplete.module index 253659f..cdac746 100644 --- a/entityreference_autocomplete.module +++ b/entityreference_autocomplete.module @@ -96,14 +96,54 @@ function entityreference_autocomplete_value_callback($element, $edit = FALSE, &$ if (!empty($element['#default_value'])) { // Only one entity referenced. if (is_numeric($element['#default_value'])) { - $references_label = entityreference_autocomplete_label_for_reference($element['#era_entity_type'], $element['#default_value']); + if (!empty($query_settings['search']) && is_array($query_settings['search'])) { + $keys = array(); + foreach($query_settings['search'] as $search_condition) { + // if option is an array, get the value or target_id + if (count($search_condition) > 2) { + $keys[] = $entity->{$search_condition[1]}['und'][0][$search_condition[2]]; + } else { + $keys[] = $entity->{$search_condition[1]}; + } + } + $key = implode('; ', array_filter($keys)); + $key .= ' (' . $element['#default_value'] . ')'; + //Keys containing commas or quotes must be wrapped in quotes. + if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) { + $key = '"' . str_replace('"', '""', $key) . '"'; + } + $references_label = $key; + + } else { + $references_label = entityreference_autocomplete_label_for_reference($element['#era_entity_type'], $element['#default_value']); + } } // Multiple entities referenced. else if (is_array($element['#default_value'])) { $referenced_labels = array(); foreach ($element['#default_value'] as $entity_id) { - $referenced_labels[] = entityreference_autocomplete_label_for_reference($element['#era_entity_type'], $entity_id); - $references_label = implode(', ', array_filter($referenced_labels)); + if (!empty($query_settings['search']) && is_array($query_settings['search'])) { + $keys = array(); + foreach($query_settings['search'] as $search_condition) { + // if option is an array, get the value or target_id + if (count($search_condition) > 2) { + $keys[] = $entity->{$search_condition[1]}['und'][0][$search_condition[2]]; + } else { + $keys[] = $entity->{$search_condition[1]}; + } + } + $key = implode('; ', array_filter($keys)); + $key .= ' (' . $entity_id . ')'; + + //Keys containing commas or quotes must be wrapped in quotes. + if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) { + $key = '"' . str_replace('"', '""', $key) . '"'; + } + $references_labels[] = $key; + } else { + $referenced_labels[] = entityreference_autocomplete_label_for_reference($element['#era_entity_type'], $entity_id); + } + $references_label = implode(', ', array_filter($referenced_labels)); } } @@ -195,9 +235,12 @@ function entityreference_autocomplete_validate_entityreference(&$element, &$form if (isset($element['#era_bundles']) && !empty($entity_info['entity keys']['bundle'])) { $query->entityCondition('bundle', $element['#era_bundles']); } - $label_column = entityreference_autocomplete_resolve_entity_label_column($entity_type); - $query->propertyCondition($label_column, $entity_label); - + // check label if search not specified + // If search is specified, match against it + if (empty($query_settings['search'])) { + $label_column = entityreference_autocomplete_resolve_entity_label_column($entity_type); + $query->propertyCondition($label_column, $entity_label); + } // Add the property conditions declared. if (!empty($query_settings['property_conditions']) && is_array($query_settings['property_conditions'])) { foreach($query_settings['property_conditions'] as $property_condition) { @@ -221,8 +264,8 @@ function entityreference_autocomplete_validate_entityreference(&$element, &$form // Add a tag to the query so modules can alter it. $query->addTag('era_query'); $query->addMetaData('era_search_string', $entity_label); - - $matching_entities = $query->execute(); + + $matching_entities = $query->execute(); // No matches found. if (empty($matching_entities[$entity_type])) { @@ -237,7 +280,21 @@ function entityreference_autocomplete_validate_entityreference(&$element, &$form // Display helpful error if there are several matching entities. $multiples = array(); foreach ($matching_entities as $id => $entity) { - $multiples[] = $entity->{$label_column} . ' (' . $id . ')'; + if (!empty($query_settings['search']) && is_array($query_settings['search'])) { + $keys = array(); + foreach($query_settings['search'] as $search_condition) { + // if option is an array, get the value or target_id + if (count($search_condition) > 2) { + $keys[] = $entity->{$search_condition[1]}['und'][0][$search_condition[2]]; + } else { + $keys[] = $entity->{$search_condition[1]}; + } + } + $key = implode('; ', array_filter($keys)); + $multiples[] = $key . ' (' . $id . ')'; + } else { + $multiples[] = $entity->{$label_column} . ' (' . $id . ')'; + } } form_error($element, t('Multiple entities match this reference; "%multiple". Specify the one you want by appending the id in parentheses, like "@value (@id)"', @@ -268,6 +325,58 @@ function entityreference_autocomplete_validate_entityreference(&$element, &$form $values = ($element['#era_cardinality'] === 1) ? current($values) : $values; form_set_value($element, $values, $form_state); } +/** + * Adds or statements to 'contains' operators + * + * These two function adds or statements to those field and property conditions that use + * the 'contains' operator. It allows searching multiple fields. + * + */ + +function entityreference_autocomplete_query_era_query_alter(QueryAlterableInterface $query) { + $conditions =& $query->conditions(); + $search_condition = db_or(); + $other_condition = db_and(); + $search = FALSE; + foreach ($conditions as $key => $condition) { + if (is_numeric($key) && isset($condition['field']) && is_scalar($condition['field'])) { + if ($condition['operator'] == 'LIKE') { + $search_condition->condition($condition['field'], $condition['value'], $condition['operator']); + $search = TRUE; + } else { + $other_condition->condition($condition['field'], $condition['value'], $condition['operator']); + } + unset($conditions[$key]); + } + + } + if ($search) $other_condition->condition($search_condition); + $query->condition($other_condition); + + +} + +function entityreference_autocomplete_query_entityreference_autocomplete_matches_alter(QueryAlterableInterface $query) { + $conditions =& $query->conditions(); + $search_condition = db_or(); + $other_condition = db_and(); + $search = FALSE; + foreach ($conditions as $key => $condition) { + if (is_numeric($key) && isset($condition['field']) && is_scalar($condition['field'])) { + if ($condition['operator'] == 'LIKE') { + $search_condition->condition($condition['field'], $condition['value'], $condition['operator']); + $search = TRUE; + } else { + $other_condition->condition($condition['field'], $condition['value'], $condition['operator']); + } + unset($conditions[$key]); + } + + } + if ($search) $other_condition->condition($search_condition); + $query->condition($other_condition); +} + /** * Returns the label to be set for a reference field. diff --git a/includes/autocomplete_callback.inc b/includes/autocomplete_callback.inc index 2a74863..d1244a5 100644 --- a/includes/autocomplete_callback.inc +++ b/includes/autocomplete_callback.inc @@ -49,12 +49,18 @@ function entityreference_autocomplete_autocomplete_callback($entity_type, $bundl // key for bundles. if ($bundles && !empty($entity_info['entity keys']['bundle'])) { $query->entityCondition('bundle', $bundles); - } - - // Fetch the column to use as label. - $label_column = entityreference_autocomplete_resolve_entity_label_column($entity_type); - $query->propertyCondition($label_column, $last_label, 'CONTAINS'); - + } + // If search is specified, match against it + if (!empty($query_settings['search']) && is_array($query_settings['search'])) { + foreach($query_settings['search'] as $search_condition) { + $query->$search_condition[0]($search_condition[1], $search_condition[2], $last_label, 'CONTAINS'); + } + } else { + // Else, search by label + // Fetch the column to use as label. + $label_column = entityreference_autocomplete_resolve_entity_label_column($entity_type); + $query->propertyCondition($label_column, $last_label, 'CONTAINS'); + } // Set property conditions, if any. if (!empty($query_settings['property_conditions']) && is_array($query_settings['property_conditions'])) { foreach($query_settings['property_conditions'] as $property_condition) { @@ -98,12 +104,31 @@ function entityreference_autocomplete_autocomplete_callback($entity_type, $bundl // Iterate through all entities retrieved and process the data to return // it as expected by Drupal javascript. foreach ($entities as $entity_id => $entity) { - if (entity_access('view', $entity_type, $entity)) { - // Get the labels for the key and for the option. - $option = entityreference_autocomplete_label_for_reference($entity_type, $entity_id, FALSE); - $key = entityreference_autocomplete_label_for_reference($entity_type, $entity_id); - - // $prefix . $key is the value that will be set in the textfield in + + if (entity_access('view', $entity_type, $entity)) { + // If option is specified, show it + if (!empty($query_settings['search']) && is_array($query_settings['search'])) { + $options = array(); + foreach($query_settings['search'] as $search_condition) { + // if option is an array, get the value or target_id + if (count($search_condition) > 2) { + $options[] = $entity->{$search_condition[1]}['und'][0][$search_condition[2]]; + } else { + $options[] = $entity->{$search_condition[1]}; + } + } + $option = implode('; ', array_filter($options)); + $option .= ' (' . $entity_id . ')'; + $key = $option; + if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) { + $key = '"' . str_replace('"', '""', $key) . '"'; + } + } else { + // Get the labels for the option and key. + $option = entityreference_autocomplete_label_for_reference($entity_type, $entity_id, FALSE); + $key = entityreference_autocomplete_label_for_reference($entity_type, $entity_id); + } + // $prefix . $key is the value that will be set in the textfield in // the browser, whereas $option is the html that is shown to the user // *before* he clicks in one of the options. $matches[$prefix . $key] = check_plain($option);