Browse Source

security update for entity_reference

Bachir Soussi Chiadmi 6 years ago
parent
commit
226561ffd4
18 changed files with 475 additions and 138 deletions
  1. 7 3
      sites/all/modules/contrib/fields/entityreference/entityreference.devel_generate.inc
  2. 9 4
      sites/all/modules/contrib/fields/entityreference/entityreference.feeds.inc
  3. 11 5
      sites/all/modules/contrib/fields/entityreference/entityreference.info
  4. 27 1
      sites/all/modules/contrib/fields/entityreference/entityreference.install
  5. 8 2
      sites/all/modules/contrib/fields/entityreference/entityreference.migrate.inc
  6. 240 49
      sites/all/modules/contrib/fields/entityreference/entityreference.module
  7. 3 3
      sites/all/modules/contrib/fields/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info
  8. 7 5
      sites/all/modules/contrib/fields/entityreference/plugins/behavior/EntityReferenceBehavior_TaxonomyIndex.class.php
  9. 15 42
      sites/all/modules/contrib/fields/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php
  10. 72 6
      sites/all/modules/contrib/fields/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php
  11. 3 2
      sites/all/modules/contrib/fields/entityreference/plugins/selection/abstract.inc
  12. 1 1
      sites/all/modules/contrib/fields/entityreference/tests/entityreference.admin.test
  13. 1 8
      sites/all/modules/contrib/fields/entityreference/tests/entityreference.feeds.test
  14. 16 1
      sites/all/modules/contrib/fields/entityreference/tests/entityreference.handlers.test
  15. 48 0
      sites/all/modules/contrib/fields/entityreference/tests/entityreference.taxonomy.test
  16. 3 3
      sites/all/modules/contrib/fields/entityreference/tests/modules/entityreference_feeds_test/entityreference_feeds_test.info
  17. 3 2
      sites/all/modules/contrib/fields/entityreference/views/entityreference_plugin_display.inc
  18. 1 1
      sites/all/modules/contrib/fields/entityreference/views/entityreference_plugin_style.inc

+ 7 - 3
sites/all/modules/contrib/fields/entityreference/entityreference.devel_generate.inc

@@ -19,9 +19,13 @@ function _entityreference_devel_generate($object, $field, $instance, $bundle) {
   // Get all the entity that are referencable here.
   $referencable_entity = entityreference_get_selection_handler($field, $instance)->getReferencableEntities();
   if (is_array($referencable_entity) && !empty($referencable_entity)) {
-    // Get a random key.
-    foreach ($referencable_entity as $type => $eids) {
-      $object_field['target_id'] = array_rand($eids);
+    // $referencable_entity is keyed by bundle type.
+    $random_bundle = array_rand($referencable_entity);
+    if (!empty($random_bundle)) {
+      $target_id = array_rand($referencable_entity[$random_bundle]);
+      if (!empty($referencable_entity[$random_bundle][$target_id])) {
+        $object_field['target_id'] = $target_id;
+      }
     }
   }
   return $object_field;

+ 9 - 4
sites/all/modules/contrib/fields/entityreference/entityreference.feeds.inc

@@ -125,10 +125,15 @@ function entityreference_feeds_set_target($source, $entity, $target, $value) {
           break;
         case 'label':
           $options = $handler->getReferencableEntities($value, '=');
-          $options = reset($options);
-          $etids = array_keys($options);
-          // Use the first matching entity.
-          $entity_id = reset($etids);
+          if ($options) {
+            $options = reset($options);
+            $etids = array_keys($options);
+            // Use the first matching entity.
+            $entity_id = reset($etids);
+          }
+          else {
+            $entity_id = NULL;
+          }
           break;
       }
       /*

+ 11 - 5
sites/all/modules/contrib/fields/entityreference/entityreference.info

@@ -1,18 +1,23 @@
 name = Entity Reference
 description = Provides a field that can reference other entities.
-core = 7.x
 package = Fields
+core = 7.x
+
 dependencies[] = entity
 dependencies[] = ctools
 
+test_dependencies[] = feeds
+test_dependencies[] = views
+
 ; Migrate handler.
 files[] = entityreference.migrate.inc
 
-; Our plugins interfaces and abstract implementations.
+; Plugins interfaces and abstract implementations.
 files[] = plugins/selection/abstract.inc
 files[] = plugins/selection/views.inc
 files[] = plugins/behavior/abstract.inc
 
+; Views integration.
 files[] = views/entityreference_plugin_display.inc
 files[] = views/entityreference_plugin_style.inc
 files[] = views/entityreference_plugin_row_fields.inc
@@ -22,10 +27,11 @@ files[] = tests/entityreference.handlers.test
 files[] = tests/entityreference.taxonomy.test
 files[] = tests/entityreference.admin.test
 files[] = tests/entityreference.feeds.test
+files[] = tests/entityreference.entity_translation.test
 
-; Information added by  packaging script on 2013-11-20
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2017-08-16
+version = "7.x-1.5"
 core = "7.x"
 project = "entityreference"
-datestamp = "1384973110"
+datestamp = "1502895850"
 

+ 27 - 1
sites/all/modules/contrib/fields/entityreference/entityreference.install

@@ -41,6 +41,7 @@ function entityreference_field_schema($field) {
     }
 
     // Invoke the behaviors to allow them to change the schema.
+    module_load_include('module', 'entityreference');
     foreach (entityreference_get_behavior_handlers($field) as $handler) {
       $handler->schema_alter($schema, $field);
     }
@@ -161,4 +162,29 @@ function entityreference_update_7002() {
       'not null' => TRUE,
     ));
   }
-}
+}
+
+/**
+ * Implements hook_update_N().
+ *
+ * Remove duplicate rows in the taxonomy_index table.
+ */
+function entityreference_update_7100() {
+  if (db_table_exists('taxonomy_index')) {
+    if (db_table_exists('taxonomy_index_tmp')) {
+      db_drop_table('taxonomy_index_tmp');
+    }
+
+    $tx_schema = drupal_get_schema('taxonomy_index');
+    db_create_table('taxonomy_index_tmp', $tx_schema);
+    $select = db_select('taxonomy_index', 'tx');
+    $select->fields('tx', array('nid', 'tid'));
+    $select->groupBy('tx.nid');
+    $select->groupBy('tx.tid');
+    $select->addExpression('MAX(sticky)', 'sticky');
+    $select->addExpression('MAX(created)', 'created');
+    db_insert('taxonomy_index_tmp')->from($select)->execute();
+    db_drop_table('taxonomy_index');
+    db_rename_table('taxonomy_index_tmp', 'taxonomy_index');
+  }
+}

+ 8 - 2
sites/all/modules/contrib/fields/entityreference/entityreference.migrate.inc

@@ -1,12 +1,11 @@
 <?php
-
 /**
  * @file
  * Support for processing entity reference fields in Migrate.
  */
 
 /**
- * Implement hook_migrate_api().
+ * Implements hook_migrate_api().
  */
 function entityreference_migrate_api() {
   return array(
@@ -15,7 +14,14 @@ function entityreference_migrate_api() {
   );
 }
 
+/**
+ * Extended class for handling entityreference fields.
+ */
 class MigrateEntityReferenceFieldHandler extends MigrateSimpleFieldHandler {
+
+  /**
+   * Constructor.
+   */
   public function __construct() {
     parent::__construct(array(
       'value_key' => 'target_id',

+ 240 - 49
sites/all/modules/contrib/fields/entityreference/entityreference.module

@@ -1,5 +1,12 @@
 <?php
 
+define('ENTITYREFERENCE_DENIED', '- Restricted access -');
+
+/**
+ * @file
+ * Entityreference primary module file.
+ */
+
 /**
  * Implements hook_ctools_plugin_directory().
  */
@@ -87,6 +94,20 @@ function entityreference_flush_caches() {
   variable_set('entityreference:base-tables', $base_tables);
 }
 
+/**
+ * Implements hook_theme().
+ */
+function entityreference_theme($existing, $type, $theme, $path) {
+  return array(
+    'entityreference_label' => array(
+      'variables' => array('label' => NULL, 'item' => NULL, 'settings' => NULL, 'uri' => NULL),
+    ),
+    'entityreference_entity_id' => array(
+      'variables' => array('item' => NULL, 'settings' => NULL),
+    ),
+  );
+}
+
 /**
  * Implements hook_menu().
  */
@@ -163,7 +184,7 @@ function entityreference_get_behavior_handlers($field, $instance = NULL) {
 /**
  * Get the behavior handler for a given entityreference field and instance.
  *
- * @param $handler
+ * @param $behavior
  *   The behavior handler name.
  */
 function _entityreference_get_behavior_handler($behavior) {
@@ -220,13 +241,15 @@ function entityreference_field_validate($entity_type, $entity, $field, $instance
   if ($ids) {
     $valid_ids = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->validateReferencableEntities(array_keys($ids));
 
-    $invalid_entities = array_diff_key($ids, array_flip($valid_ids));
-    if ($invalid_entities) {
-      foreach ($invalid_entities as $id => $delta) {
-        $errors[$field['field_name']][$langcode][$delta][] = array(
-          'error' => 'entityreference_invalid_entity',
-          'message' => t('The referenced entity (@type: @id) is invalid.', array('@type' => $field['settings']['target_type'], '@id' => $id)),
-        );
+    if (!empty($valid_ids)) {
+      $invalid_entities = array_diff_key($ids, array_flip($valid_ids));
+      if ($invalid_entities) {
+        foreach ($invalid_entities as $id => $delta) {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'entityreference_invalid_entity',
+            'message' => t('The referenced entity (@type: @id) is invalid.', array('@type' => $field['settings']['target_type'], '@id' => $id)),
+          );
+        }
       }
     }
   }
@@ -398,6 +421,9 @@ function entityreference_field_settings_form($field, $instance, $has_data) {
   return $form;
 }
 
+/**
+ * Callback for custom element processing.
+ */
 function _entityreference_field_settings_process($form, $form_state) {
   $field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
   $instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
@@ -479,11 +505,17 @@ function _entityreference_field_settings_process($form, $form_state) {
   return $form;
 }
 
+/**
+ * Custom callback for ajax processing.
+ */
 function _entityreference_field_settings_ajax_process($form, $form_state) {
   _entityreference_field_settings_ajax_process_element($form, $form);
   return $form;
 }
 
+/**
+ * Helper function for custom ajax processing.
+ */
 function _entityreference_field_settings_ajax_process_element(&$element, $main_form) {
   if (isset($element['#ajax']) && $element['#ajax'] === TRUE) {
     $element['#ajax'] = array(
@@ -498,6 +530,9 @@ function _entityreference_field_settings_ajax_process_element(&$element, $main_f
   }
 }
 
+/**
+ * Custom callback for element processing.
+ */
 function _entityreference_form_process_merge_parent($element) {
   $parents = $element['#parents'];
   array_pop($parents);
@@ -505,11 +540,17 @@ function _entityreference_form_process_merge_parent($element) {
   return $element;
 }
 
+/**
+ * Helper function to remove blank elements.
+ */
 function _entityreference_element_validate_filter(&$element, &$form_state) {
   $element['#value'] = array_filter($element['#value']);
   form_set_value($element, $element['#value'], $form_state);
 }
 
+/**
+ * Implements hook_validate().
+ */
 function _entityreference_field_settings_validate($form, &$form_state) {
   // Store the new values in the form state.
   $field = $form['#field'];
@@ -545,6 +586,9 @@ function entityreference_field_instance_settings_form($field, $instance) {
   return $form;
 }
 
+/**
+ * Implements hook_field_settings_form().
+ */
 function _entityreference_field_instance_settings_form($form, $form_state) {
   $field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
   $instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
@@ -562,6 +606,9 @@ function _entityreference_field_instance_settings_form($form, $form_state) {
   return $form;
 }
 
+/**
+ * Implements hook_validate().
+ */
 function _entityreference_field_instance_settings_validate($form, &$form_state) {
   // Store the new values in the form state.
   $instance = $form['#instance'];
@@ -793,7 +840,7 @@ function entityreference_query_entityreference_alter(QueryAlterableInterface $qu
 function entityreference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
   // Ensure that the entity target type exists before displaying the widget.
   $entity_info = entity_get_info($field['settings']['target_type']);
-  if (empty($entity_info)){
+  if (empty($entity_info)) {
     return;
   }
   $entity_type = $instance['entity_type'];
@@ -818,7 +865,9 @@ function entityreference_field_widget_form(&$form, &$form_state, $field, $instan
 
     // Build an array of entities ID.
     foreach ($items as $item) {
-      $entity_ids[] = $item['target_id'];
+      if (isset($item['target_id'])) {
+        $entity_ids[] = $item['target_id'];
+      }
     }
 
     // Load those entities and loop through them to extract their labels.
@@ -879,6 +928,9 @@ function entityreference_field_widget_form(&$form, &$form_state, $field, $instan
   }
 }
 
+/**
+ * Implements hook_validate().
+ */
 function _entityreference_autocomplete_validate($element, &$form_state, $form) {
   // If a value was entered into the autocomplete...
   $value = '';
@@ -903,6 +955,9 @@ function _entityreference_autocomplete_validate($element, &$form_state, $form) {
   form_set_value($element, $value, $form_state);
 }
 
+/**
+ * Implements hook_validate().
+ */
 function _entityreference_autocomplete_tags_validate($element, &$form_state, $form) {
   $value = array();
   // If a value was entered into the autocomplete...
@@ -949,7 +1004,8 @@ function entityreference_field_widget_error($element, $error) {
  *   The entity type.
  * @param $bundle_name
  *   The bundle name.
- * @return
+ *
+ * @return bool
  *   True if user can access this menu item.
  */
 function entityreference_autocomplete_access_callback($type, $field_name, $entity_type, $bundle_name) {
@@ -981,10 +1037,11 @@ function entityreference_autocomplete_access_callback($type, $field_name, $entit
  */
 function entityreference_autocomplete_callback($type, $field_name, $entity_type, $bundle_name, $entity_id = '', $string = '') {
   // If the request has a '/' in the search text, then the menu system will have
-  // split it into multiple arguments and $string will only be a partial. We want
-  //  to make sure we recover the intended $string.
+  // split it into multiple arguments and $string will only be a partial.
+  // We want to make sure we recover the intended $string.
   $args = func_get_args();
-  // Shift off the $type, $field_name, $entity_type, $bundle_name, and $entity_id args.
+  // Shift off the $type, $field_name, $entity_type,
+  // $bundle_name, and $entity_id args.
   array_shift($args);
   array_shift($args);
   array_shift($args);
@@ -1020,6 +1077,7 @@ function entityreference_autocomplete_callback($type, $field_name, $entity_type,
  */
 function entityreference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id = '', $string = '') {
   $matches = array();
+  $prefix = '';
 
   $entity = NULL;
   if ($entity_id !== 'NULL') {
@@ -1034,7 +1092,8 @@ function entityreference_autocomplete_callback_get_matches($type, $field, $insta
   $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
 
   if ($type == 'tags') {
-    // The user enters a comma-separated list of tags. We only autocomplete the last tag.
+    // The user enters a comma-separated list of tags.
+    // We only autocomplete the last tag.
     $tags_typed = drupal_explode_tags($string);
     $tag_last = drupal_strtolower(array_pop($tags_typed));
     if (!empty($tag_last)) {
@@ -1043,19 +1102,22 @@ function entityreference_autocomplete_callback_get_matches($type, $field, $insta
   }
   else {
     // The user enters a single tag.
-    $prefix = '';
     $tag_last = $string;
   }
 
   if (isset($tag_last)) {
     // Get an array of matching entities.
     $entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator'], 10);
-
+    $denied_label = t(ENTITYREFERENCE_DENIED);
     // Loop through the products and convert them into autocomplete output.
     foreach ($entity_labels as $values) {
       foreach ($values as $entity_id => $label) {
+        // Never autocomplete entities that aren't accessible.
+        if ($label == $denied_label) {
+          continue;
+        }
         $key = "$label ($entity_id)";
-        // Strip things like starting/trailing white spaces, line breaks and tags.
+        // Strip starting/trailing white spaces, line breaks and tags.
         $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key)))));
         // Names containing commas or quotes must be wrapped in quotes.
         if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
@@ -1069,6 +1131,32 @@ function entityreference_autocomplete_callback_get_matches($type, $field, $insta
   drupal_json_output($matches);
 }
 
+ /**
+ * Introspects field and instance settings, and determines the correct settings
+ * for the functioning of the formatter.
+ *
+ * Settings:
+ *   - entity_type - The entity_type being loaded.
+ *   - column - The name of the ref. field column that stores the entity id.
+ */
+function entityreference_field_type_settings($field) {
+  $settings = array(
+    'entity_type' => NULL,
+    'column' => NULL,
+  );
+
+  if ($field['type'] == 'entityreference') {
+    $settings['entity_type'] = $field['settings']['target_type'];
+    $settings['column'] = 'target_id';
+  }
+  elseif ($field['type'] == 'taxonomy_term_reference') {
+    $settings['entity_type'] = 'taxonomy_term';
+    $settings['column'] = 'tid';
+  }
+
+  return $settings;
+}
+
 /**
  * Implements hook_field_formatter_info().
  */
@@ -1080,6 +1168,7 @@ function entityreference_field_formatter_info() {
       'field types' => array('entityreference'),
       'settings' => array(
         'link' => FALSE,
+        'bypass_access' => FALSE,
       ),
     ),
     'entityreference_entity_id' => array(
@@ -1090,10 +1179,11 @@ function entityreference_field_formatter_info() {
     'entityreference_entity_view' => array(
       'label' => t('Rendered entity'),
       'description' => t('Display the referenced entities rendered by entity_view().'),
-      'field types' => array('entityreference'),
+      'field types' => array('entityreference', 'taxonomy_term_reference'),
       'settings' => array(
         'view_mode' => 'default',
         'links' => TRUE,
+        'use_content_language' => TRUE,
       ),
     ),
   );
@@ -1105,8 +1195,17 @@ function entityreference_field_formatter_info() {
 function entityreference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
   $display = $instance['display'][$view_mode];
   $settings = $display['settings'];
+  $field_type_settings = entityreference_field_type_settings($field);
+  $element = array();
 
   if ($display['type'] == 'entityreference_label') {
+    $element['bypass_access'] = array(
+      '#title' => t('Show entity labels regardless of user access'),
+      '#description' => t("All entities in the field will be shown, without checking them for access. If the 'Link' setting is also enabled, an entity which the user does not have access to view will show without a link."),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['bypass_access'],
+    );
+
     $element['link'] = array(
       '#title' => t('Link label to the referenced entity'),
       '#type' => 'checkbox',
@@ -1115,7 +1214,7 @@ function entityreference_field_formatter_settings_form($field, $instance, $view_
   }
 
   if ($display['type'] == 'entityreference_entity_view') {
-    $entity_info = entity_get_info($field['settings']['target_type']);
+    $entity_info = entity_get_info($field_type_settings['entity_type']);
     $options = array('default' => t('Default'));
     if (!empty($entity_info['view modes'])) {
       foreach ($entity_info['view modes'] as $view_mode => $view_mode_settings) {
@@ -1136,6 +1235,12 @@ function entityreference_field_formatter_settings_form($field, $instance, $view_
       '#title' => t('Show links'),
       '#default_value' => $settings['links'],
     );
+
+    $element['use_content_language'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Use current content language'),
+      '#default_value' => $settings['use_content_language'],
+    );
   }
 
   return $element;
@@ -1147,21 +1252,24 @@ function entityreference_field_formatter_settings_form($field, $instance, $view_
 function entityreference_field_formatter_settings_summary($field, $instance, $view_mode) {
   $display = $instance['display'][$view_mode];
   $settings = $display['settings'];
+  $field_type_settings = entityreference_field_type_settings($field);
 
   $summary = array();
 
   if ($display['type'] == 'entityreference_label') {
     $summary[] = $settings['link'] ? t('Link to the referenced entity') : t('No link');
+    $summary[] = $settings['bypass_access'] ? t('Show labels regardless of access') : t('Respect entity access for label visibility');
   }
 
   if ($display['type'] == 'entityreference_entity_view') {
-    $entity_info = entity_get_info($field['settings']['target_type']);
+    $entity_info = entity_get_info($field_type_settings['entity_type']);
     $view_mode_label = $settings['view_mode'] == 'default' ? t('Default') : $settings['view_mode'];
     if (isset($entity_info['view modes'][$settings['view_mode']]['label'])) {
       $view_mode_label = $entity_info['view modes'][$settings['view_mode']]['label'];
     }
     $summary[] = t('Rendered as @mode', array('@mode' => $view_mode_label));
     $summary[] = !empty($settings['links']) ? t('Display links') : t('Do not display links');
+    $summary[] = !empty($settings['use_content_language']) ? t('Use current content language') : t('Use field language');
   }
 
   return implode('<br />', $summary);
@@ -1171,19 +1279,22 @@ function entityreference_field_formatter_settings_summary($field, $instance, $vi
  * Implements hook_field_formatter_prepare_view().
  */
 function entityreference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
+  $field_type_settings = entityreference_field_type_settings($field);
+  $target_type = $field_type_settings['entity_type'];
+  $column = $field_type_settings['column'];
   $target_ids = array();
 
   // Collect every possible entity attached to any of the entities.
   foreach ($entities as $id => $entity) {
     foreach ($items[$id] as $delta => $item) {
-      if (isset($item['target_id'])) {
-        $target_ids[] = $item['target_id'];
+      if (isset($item[$column])) {
+        $target_ids[] = $item[$column];
       }
     }
   }
 
   if ($target_ids) {
-    $target_entities = entity_load($field['settings']['target_type'], $target_ids);
+    $target_entities = entity_load($target_type, $target_ids);
   }
   else {
     $target_entities = array();
@@ -1195,12 +1306,12 @@ function entityreference_field_formatter_prepare_view($entity_type, $entities, $
 
     foreach ($items[$id] as $delta => $item) {
       // Check whether the referenced entity could be loaded.
-      if (isset($target_entities[$item['target_id']])) {
+      if (isset($target_entities[$item[$column]]) && isset($target_entities[$item[$column]])) {
         // Replace the instance value with the term data.
-        $items[$id][$delta]['entity'] = $target_entities[$item['target_id']];
+        $items[$id][$delta]['entity'] = $target_entities[$item[$column]];
         // Check whether the user has access to the referenced entity.
-        $has_view_access = (entity_access('view', $field['settings']['target_type'], $target_entities[$item['target_id']]) !== FALSE);
-        $has_update_access = (entity_access('update', $field['settings']['target_type'], $target_entities[$item['target_id']]) !== FALSE);
+        $has_view_access = (entity_access('view', $target_type, $target_entities[$item[$column]]) !== FALSE);
+        $has_update_access = (entity_access('update', $target_type, $target_entities[$item[$column]]) !== FALSE);
         $items[$id][$delta]['access'] = ($has_view_access || $has_update_access);
       }
       // Otherwise, unset the instance value, since the entity does not exist.
@@ -1223,52 +1334,91 @@ function entityreference_field_formatter_prepare_view($entity_type, $entities, $
 function entityreference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
   $result = array();
   $settings = $display['settings'];
-
-  // Rebuild the items list to contain only those with access.
-  foreach ($items as $key => $item) {
-    if (empty($item['access'])) {
-      unset($items[$key]);
-    }
-  }
+  $field_type_settings = entityreference_field_type_settings($field);
+  $target_type = $field_type_settings['entity_type'];
+  $column = $field_type_settings['column'];
 
   switch ($display['type']) {
     case 'entityreference_label':
       $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
 
       foreach ($items as $delta => $item) {
-        $label = $handler->getLabel($item['entity']);
-        // If the link is to be displayed and the entity has a uri, display a link.
-        // Note the assignment ($url = ) here is intended to be an assignment.
-        if ($display['settings']['link'] && ($uri = entity_uri($field['settings']['target_type'], $item['entity']))) {
-          $result[$delta] = array('#markup' => l($label, $uri['path'], $uri['options']));
+        // Skip an item that is not accessible, unless we're allowing output of
+        // entity labels without considering access.
+        if (empty($item['access']) && !$display['settings']['bypass_access']) {
+          continue;
         }
-        else {
-          $result[$delta] = array('#markup' => check_plain($label));
+
+        // Calling EntityReferenceHandler::getLabel() would make a repeated,
+        // wasteful call to entity_access().
+        $label = entity_label($field['settings']['target_type'], $item['entity']);
+
+        // Check if the settings and access allow a link to be displayed.
+        $display_link = $display['settings']['link'] && $item['access'];
+
+        $uri = NULL;
+
+        // If the link is allowed and the entity has a uri, display a link.
+        if ($display_link) {
+          $uri = entity_uri($target_type, $item['entity']);
         }
+
+        $result[$delta] = array(
+          '#theme' => 'entityreference_label',
+          '#label' => $label,
+          '#item' => $item,
+          '#uri' => $uri,
+          '#settings' => array(
+            'display' => $display['settings'],
+            'field' => $field['settings'],
+          ),
+        );
       }
       break;
 
     case 'entityreference_entity_id':
       foreach ($items as $delta => $item) {
-        $result[$delta] = array('#markup' => check_plain($item['target_id']));
+        // Skip an item that is not accessible.
+        if (empty($item['access'])) {
+          continue;
+        }
+
+        $result[$delta] = array(
+          '#theme' => 'entityreference_entity_id',
+          '#item' => $item,
+          '#settings' => array(
+            'display' => $display['settings'],
+            'field' => $field['settings'],
+          ),
+        );
       }
       break;
 
     case 'entityreference_entity_view':
+      $target_langcode = $langcode;
+      if (!empty($settings['use_content_language']) && !empty($GLOBALS['language_content']->language)) {
+        $target_langcode = $GLOBALS['language_content']->language;
+      }
+
       foreach ($items as $delta => $item) {
+        // Skip an item that is not accessible.
+        if (empty($item['access'])) {
+          continue;
+        }
+
         // Protect ourselves from recursive rendering.
         static $depth = 0;
         $depth++;
         if ($depth > 20) {
-          throw new EntityReferenceRecursiveRenderingException(t('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $entity_type, '@entity_id' => $item['target_id'])));
+          throw new EntityReferenceRecursiveRenderingException(t('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $target_type, '@entity_id' => $item[$column])));
         }
 
-        $entity = clone $item['entity'];
-        unset($entity->content);
-        $result[$delta] = entity_view($field['settings']['target_type'], array($item['target_id'] => $entity), $settings['view_mode'], $langcode, FALSE);
+        $target_entity = clone $item['entity'];
+        unset($target_entity->content);
+        $result[$delta] = entity_view($target_type, array($item[$column] => $target_entity), $settings['view_mode'], $target_langcode, FALSE);
 
-        if (empty($settings['links']) && isset($result[$delta][$field['settings']['target_type']][$item['target_id']]['links'])) {
-          $result[$delta][$field['settings']['target_type']][$item['target_id']]['links']['#access'] = FALSE;
+        if (empty($settings['links']) && isset($result[$delta][$target_type][$column]['links'])) {
+          $result[$delta][$target_type][$item[$column]]['links']['#access'] = FALSE;
         }
         $depth = 0;
       }
@@ -1292,3 +1442,44 @@ function entityreference_views_api() {
     'path' => drupal_get_path('module', 'entityreference') . '/views',
   );
 }
+
+/**
+ * Theme label.
+ *
+ * @ingroup themeable.
+ */
+function theme_entityreference_label($vars) {
+  $label = $vars['label'];
+  $settings = $vars['settings'];
+  $item = $vars['item'];
+  $uri = $vars['uri'];
+
+  $output = '';
+
+  // If the link is to be displayed and the entity has a uri, display a link.
+  // Note the assignment ($url = ) here is intended to be an assignment.
+  if ($settings['display']['link'] && isset($uri['path'])) {
+    $output .= l($label, $uri['path'], $uri['options']);
+  }
+  else {
+    $output .= check_plain($label);
+  }
+
+  return $output;
+}
+
+/**
+ * Theme entity_id
+ *
+ * @ingroup themeable.
+ */
+function theme_entityreference_entity_id($vars) {
+  $settings = $vars['settings'];
+  $item = $vars['item'];
+
+  $output = '';
+
+  $output = check_plain($item['target_id']);
+
+  return $output;
+}

+ 3 - 3
sites/all/modules/contrib/fields/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info

@@ -4,9 +4,9 @@ core = 7.x
 package = Fields
 dependencies[] = entityreference
 
-; Information added by  packaging script on 2013-11-20
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2017-08-16
+version = "7.x-1.5"
 core = "7.x"
 project = "entityreference"
-datestamp = "1384973110"
+datestamp = "1502895850"
 

+ 7 - 5
sites/all/modules/contrib/fields/entityreference/plugins/behavior/EntityReferenceBehavior_TaxonomyIndex.class.php

@@ -144,18 +144,20 @@ class EntityReferenceBehavior_TaxonomyIndex extends EntityReference_BehaviorHand
       // already inserted in taxonomy_build_node_index().
       $tid_all = array_diff($tid_all, $original_tid_all);
 
-      // Insert index entries for all the node's terms.
+      // Insert index entries for all the node's terms, preventing duplicates.
       if (!empty($tid_all)) {
-        $query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created'));
         foreach ($tid_all as $tid) {
-          $query->values(array(
+          $row = array(
             'nid' => $node->nid,
             'tid' => $tid,
             'sticky' => $sticky,
             'created' => $node->created,
-          ));
+          );
+          $query = db_merge('taxonomy_index')
+            ->key($row)
+            ->fields($row);
+          $query->execute();
         }
-        $query->execute();
       }
     }
   }

+ 15 - 42
sites/all/modules/contrib/fields/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php

@@ -208,7 +208,11 @@ class EntityReference_SelectionHandler_Generic implements EntityReference_Select
    * Implements EntityReferenceHandler::validateAutocompleteInput().
    */
   public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
-      $entities = $this->getReferencableEntities($input, '=', 6);
+      $bundled_entities = $this->getReferencableEntities($input, '=', 6);
+      $entities = array();
+      foreach($bundled_entities as $entities_list) {
+        $entities += $entities_list;
+      }
       if (empty($entities)) {
         // Error if there are no entities available for a required field.
         form_error($element, t('There are no entities matching "%value"', array('%value' => $input)));
@@ -305,7 +309,7 @@ class EntityReference_SelectionHandler_Generic implements EntityReference_Select
    */
   public function getLabel($entity) {
     $target_type = $this->field['settings']['target_type'];
-    return entity_access('view', $target_type, $entity) ? entity_label($target_type, $entity) : t('- Restricted access -');
+    return entity_access('view', $target_type, $entity) ? entity_label($target_type, $entity) : t(ENTITYREFERENCE_DENIED);
   }
 
   /**
@@ -339,9 +343,11 @@ class EntityReference_SelectionHandler_Generic implements EntityReference_Select
     // Join the known base-table.
     $target_type = $this->field['settings']['target_type'];
     $entity_info = entity_get_info($target_type);
+    $target_type_base_table = $entity_info['base table'];
     $id = $entity_info['entity keys']['id'];
+
     // Return the alias of the table.
-    return $query->innerJoin($target_type, NULL, "%alias.$id = $alias.entity_id");
+    return $query->innerJoin($target_type_base_table, NULL, "%alias.$id = $alias.entity_id");
   }
 }
 
@@ -370,28 +376,6 @@ class EntityReference_SelectionHandler_Generic_node extends EntityReference_Sele
  * This only exists to workaround core bugs.
  */
 class EntityReference_SelectionHandler_Generic_user extends EntityReference_SelectionHandler_Generic {
-
-  /**
-   * Implements EntityReferenceHandler::settingsForm().
-   */
-  public static function settingsForm($field, $instance) {
-    $settings = $field['settings']['handler_settings'];
-    $form = parent::settingsForm($field, $instance);
-    $form['referenceable_roles'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('User roles that can be referenced'),
-      '#default_value' => isset($settings['referenceable_roles']) ? array_filter($settings['referenceable_roles']) : array(),
-      '#options' => user_roles(TRUE),
-    );
-    $form['referenceable_status'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('User status that can be referenced'),
-      '#default_value' => isset($settings['referenceable_status']) ? array_filter($settings['referenceable_status']) : array('active' => 'active'),
-      '#options' => array('active' => t('Active'), 'blocked' => t('Blocked')),
-    );
-    return $form;
-  }
-
   public function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
     $query = parent::buildEntityFieldQuery($match, $match_operator);
 
@@ -400,22 +384,11 @@ class EntityReference_SelectionHandler_Generic_user extends EntityReference_Sele
       $query->propertyCondition('name', $match, $match_operator);
     }
 
-    $field = $this->field;
-    $settings = $field['settings']['handler_settings'];
-    $referenceable_roles = isset($settings['referenceable_roles']) ? array_filter($settings['referenceable_roles']) : array();
-    $referenceable_status = isset($settings['referenceable_status']) ? array_filter($settings['referenceable_status']) : array('active' => 'active');
-
-    // If this filter is not filled, use the users access permissions.
-    if (empty($referenceable_status)) {
-      // Adding the 'user_access' tag is sadly insufficient for users: core
-      // requires us to also know about the concept of 'blocked' and 'active'.
-      if (!user_access('administer users')) {
-        $query->propertyCondition('status', 1);
-      }
-    }
-    elseif (count($referenceable_status) == 1) {
-      $values = array('active' => 1, 'blocked' => 0);
-      $query->propertyCondition('status', $values[key($referenceable_status)]);
+    // Adding the 'user_access' tag is sadly insufficient for users: core
+    // requires us to also know about the concept of 'blocked' and
+    // 'active'.
+    if (!user_access('administer users')) {
+      $query->propertyCondition('status', 1);
     }
     return $query;
   }
@@ -576,7 +549,7 @@ class EntityReference_SelectionHandler_Generic_taxonomy_term extends EntityRefer
       if ($vocabulary = taxonomy_vocabulary_machine_name_load($bundle)) {
         if ($terms = taxonomy_get_tree($vocabulary->vid, 0, NULL, TRUE)) {
           foreach ($terms as $term) {
-            $options[$vocabulary->machine_name][$term->tid] = str_repeat('-', $term->depth) . check_plain($term->name);
+            $options[$vocabulary->machine_name][$term->tid] = str_repeat('-', $term->depth) . check_plain(entity_label('taxonomy_term', $term));
           }
         }
       }

+ 72 - 6
sites/all/modules/contrib/fields/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php

@@ -9,12 +9,13 @@ class EntityReference_SelectionHandler_Views implements EntityReference_Selectio
    * Implements EntityReferenceHandler::getInstance().
    */
   public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
-    return new EntityReference_SelectionHandler_Views($field, $instance);
+    return new EntityReference_SelectionHandler_Views($field, $instance, $entity);
   }
 
-  protected function __construct($field, $instance) {
+  protected function __construct($field, $instance, $entity) {
     $this->field = $field;
     $this->instance = $instance;
+    $this->entity = $entity;
   }
 
   /**
@@ -52,13 +53,32 @@ class EntityReference_SelectionHandler_Views implements EntityReference_Selectio
       );
 
       $default = !empty($view_settings['args']) ? implode(', ', $view_settings['args']) : '';
+      $description = t('Provide a comma separated list of arguments to pass to the view.') . '<br />' . t('This field supports tokens.');
+
+      if (!module_exists('token')) {
+        $description .= '<br>' . t('Install the <a href="@url">token module</a> to get more tokens and display available once.', array('@url' => 'http://drupal.org/project/token'));
+      }
+
       $form['view']['args'] = array(
         '#type' => 'textfield',
         '#title' => t('View arguments'),
         '#default_value' => $default,
         '#required' => FALSE,
-        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+        '#description' => $description,
+        '#maxlength' => '512',
       );
+      if (module_exists('token')) {
+        // Get the token type for the entity type our field is in (a type 'taxonomy_term' has a 'term' type token).
+        $info = entity_get_info($instance['entity_type']);
+
+        $form['view']['tokens'] = array(
+          '#theme' => 'token_tree',
+          '#token_types' => array($info['token type']),
+          '#global_types' => TRUE,
+          '#click_insert' => TRUE,
+          '#dialog' => TRUE,
+        );
+      }
     }
     else {
       $form['view']['no_view_help'] = array(
@@ -84,6 +104,7 @@ class EntityReference_SelectionHandler_Views implements EntityReference_Selectio
       return FALSE;
     }
     $this->view->set_display($display_name);
+    $this->view->pre_execute();
 
     // Make sure the query is not cached.
     $this->view->is_cacheable = FALSE;
@@ -104,7 +125,7 @@ class EntityReference_SelectionHandler_Views implements EntityReference_Selectio
    */
   public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
     $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
-    $args = $this->field['settings']['handler_settings']['view']['args'];
+    $args = $this->handleArgs($this->field['settings']['handler_settings']['view']['args']);
     $result = array();
     if ($this->initializeView($match, $match_operator, $limit)) {
       // Get the results.
@@ -133,12 +154,14 @@ class EntityReference_SelectionHandler_Views implements EntityReference_Selectio
 
   function validateReferencableEntities(array $ids) {
     $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
-    $args = $this->field['settings']['handler_settings']['view']['args'];
+    $args = $this->handleArgs($this->field['settings']['handler_settings']['view']['args']);
     $result = array();
     if ($this->initializeView(NULL, 'CONTAINS', 0, $ids)) {
       // Get the results.
       $entities = $this->view->execute_display($display_name, $args);
-      $result = array_keys($entities);
+      if (!empty($entities)) {
+        $result = array_keys($entities);
+      }
     }
     return $result;
   }
@@ -164,6 +187,49 @@ class EntityReference_SelectionHandler_Views implements EntityReference_Selectio
 
   }
 
+  /**
+   * Handles arguments for views.
+   *
+   * Replaces tokens using token_replace().
+   *
+   * @param array $args
+   *   Usually $this->field['settings']['handler_settings']['view']['args'].
+   *
+   * @return array
+   *   The arguments to be send to the View.
+   */
+  protected function handleArgs($args) {
+    if (!module_exists('token')) {
+      return $args;
+    }
+
+    // Parameters for token_replace().
+    $data = array();
+    $options = array('clear' => TRUE);
+
+    if ($entity = $this->entity) {
+      // D7 HACK: For new entities, entity and revision id are not set. This leads to
+      // * token replacement emitting PHP warnings
+      // * views choking on empty arguments
+      // We workaround this by filling in '0' for these IDs
+      // and use a clone to leave no traces of our unholy doings.
+      $info = entity_get_info($this->instance['entity_type']);
+      if (!isset($entity->{$info['entity keys']['id']})) {
+        $entity = clone $entity;
+        $entity->{$info['entity keys']['id']} = '0';
+        if (!empty($info['entity keys']['revision'])) {
+          $entity->{$info['entity keys']['revision']} = '0';
+        }
+      }
+
+      $data[$info['token type']] = $entity;
+    }
+    // Replace tokens for each argument.
+    foreach ($args as $key => $arg) {
+      $args[$key] = token_replace($arg, $data, $options);
+    }
+    return $args;
+  }
 }
 
 function entityreference_view_settings_validate($element, &$form_state, $form) {

+ 3 - 2
sites/all/modules/contrib/fields/entityreference/plugins/selection/abstract.inc

@@ -21,8 +21,9 @@ interface EntityReference_SelectionHandler {
    * Return a list of referencable entities.
    *
    * @return
-   *   An array of referencable entities, which keys are entity ids and
-   *   values (safe HTML) labels to be displayed to the user.
+   *   A nested array of entities, the first level is keyed by the
+   *   entity bundle, which contains an array of entity labels (safe HTML),
+   *   keyed by the entity ID.
    */
   public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0);
 

+ 1 - 1
sites/all/modules/contrib/fields/entityreference/tests/entityreference.admin.test

@@ -21,7 +21,7 @@ class EntityReferenceAdminTestCase extends DrupalWebTestCase {
     parent::setUp(array('field_ui', 'entity', 'ctools', 'entityreference'));
 
     // Create test user.
-    $this->admin_user = $this->drupalCreateUser(array('access content', 'administer content types'));
+    $this->admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer fields'));
     $this->drupalLogin($this->admin_user);
 
     // Create content type, with underscores.

+ 1 - 8
sites/all/modules/contrib/fields/entityreference/tests/entityreference.feeds.test

@@ -17,6 +17,7 @@ class FeedsMapperFieldTestCase extends DrupalWebTestCase{
       'name' => 'Feeds integration (field mapper)',
       'description' => 'Test Feeds Mapper support for fields.',
       'group' => 'Entity Reference',
+      'dependencies' => array('feeds'),
     );
   }
 
@@ -28,10 +29,6 @@ class FeedsMapperFieldTestCase extends DrupalWebTestCase{
     module_enable(array('entityreference_feeds_test'), TRUE);
     $this->resetAll();
 
-    if (!module_exists('feeds')) {
-      return;
-    }
-
     $permissions[] = 'access content';
     $permissions[] = 'administer site configuration';
     $permissions[] = 'administer content types';
@@ -157,10 +154,6 @@ class FeedsMapperFieldTestCase extends DrupalWebTestCase{
    * Basic test loading a double entry CSV file.
    */
   public function test() {
-    if (!module_exists('feeds')) {
-      return;
-    }
-
     $this->drupalLogin($this->admin_user);
     $this->drupalGet('admin/structure/types/manage/article/fields');
     $this->assertText('Ref - entity ID', t('Found Entity reference field %field.', array('%field' => 'field_er_id')));

+ 16 - 1
sites/all/modules/contrib/fields/entityreference/tests/entityreference.handlers.test

@@ -194,6 +194,21 @@ class EntityReferenceHandlersTestCase extends DrupalWebTestCase {
       ),
     );
     $this->assertReferencable($field, $referencable_tests, 'Node handler (admin)');
+
+    // Verify autocomplete input validation.
+    $handler = entityreference_get_selection_handler($field);
+    $element = array(
+      '#parents' => array('element_name'),
+    );
+    $form_state = array();
+    $form = array();
+    $value = $handler->validateAutocompleteInput($nodes['published1']->title, $element, $form_state, $form);
+    $this->assertEqual($value, $nodes['published1']->nid);
+
+    $invalid_input = $this->randomName();
+    $value = $handler->validateAutocompleteInput($invalid_input, $element, $form_state, $form);
+    $this->assertNull($value);
+    $this->assertEqual(form_get_error($element), t('There are no entities matching "%value"', array('%value' => $invalid_input)));
   }
 
   /**
@@ -256,7 +271,7 @@ class EntityReferenceHandlersTestCase extends DrupalWebTestCase {
         ),
         'result' => array(
           'user' => array(
-            $users['admin']->uid => '- Restricted access -',
+            $users['admin']->uid => ENTITYREFERENCE_DENIED,
             $users['non_admin']->uid => $user_labels['non_admin'],
           ),
         ),

+ 48 - 0
sites/all/modules/contrib/fields/entityreference/tests/entityreference.taxonomy.test

@@ -112,4 +112,52 @@ class EntityReferenceTaxonomyTestCase extends DrupalWebTestCase {
     $this->assertFalse(taxonomy_select_nodes(1));
   }
 
+  /**
+   * Add a second ER field from node/article to taxonomy.
+   *
+   * This should not cause {taxonomy_index} to receive duplicate entries.
+   */
+  protected function setupForIndexDuplicates() {
+    // Create an entity reference field.
+    $field = array(
+      'entity_types' => array('node'),
+      'settings' => array(
+        'handler' => 'base',
+        'target_type' => 'taxonomy_term',
+        'handler_settings' => array(
+          'target_bundles' => array(),
+        ),
+      ),
+      'field_name' => 'field_entityreference_term2',
+      'type' => 'entityreference',
+    );
+    $field = field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_entityreference_term2',
+      'bundle' => 'article',
+      'entity_type' => 'node',
+    );
+
+    // Enable the taxonomy-index behavior.
+    $instance['settings']['behaviors']['taxonomy-index']['status'] = TRUE;
+    field_create_instance($instance);
+  }
+
+  /**
+   * Make sure the index only contains one entry for a given node->term
+   * reference, even when multiple ER fields link from the node bundle to terms.
+   */
+  public function testIndexDuplicates() {
+    // Extra setup for this test: add another ER field on this content type.
+    $this->setupForIndexDuplicates();
+
+    // Assert node insert with reference to term in first field.
+    $tid = 1;
+    $settings = array();
+    $settings['type'] = 'article';
+    $settings['field_entityreference_term'][LANGUAGE_NONE][0]['target_id'] = $tid;
+    $node = $this->drupalCreateNode($settings);
+
+    $this->assertEqual(taxonomy_select_nodes($tid), array($node->nid));
+  }
 }

+ 3 - 3
sites/all/modules/contrib/fields/entityreference/tests/modules/entityreference_feeds_test/entityreference_feeds_test.info

@@ -8,9 +8,9 @@ dependencies[] = feeds
 dependencies[] = feeds_ui
 dependencies[] = entityreference
 
-; Information added by  packaging script on 2013-11-20
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2017-08-16
+version = "7.x-1.5"
 core = "7.x"
 project = "entityreference"
-datestamp = "1384973110"
+datestamp = "1502895850"
 

+ 3 - 2
sites/all/modules/contrib/fields/entityreference/views/entityreference_plugin_display.inc

@@ -81,8 +81,9 @@ class entityreference_plugin_display extends views_plugin_display {
             $field = $this->view->query->fields[$this->view->field[$field_alias]->field_alias];
           }
           else {
-            $this->view->query->add_field($this->view->field[$field_alias]->options['table'], $this->view->field[$field_alias]->real_field, $this->view->field[$field_alias]->options['field'], array());
-            $field = $this->view->query->fields[$this->view->field[$field_alias]->options['field']];
+            $field_table = $this->view->query->ensure_table($this->view->field[$field_alias]->table, $this->view->field[$field_alias]->relationship);
+            $this->view->query->add_field($field_table, $this->view->field[$field_alias]->real_field, $this->view->field[$field_alias]->field, array());
+            $field = $this->view->query->fields[$this->view->field[$field_alias]->field];
           }
           // Add an OR condition for the field
           $conditions->condition($field['table'] . '.' . $field['field'], $value, 'LIKE');

+ 1 - 1
sites/all/modules/contrib/fields/entityreference/views/entityreference_plugin_style.inc

@@ -26,7 +26,7 @@ class entityreference_plugin_style extends views_plugin_style {
         '#title' => t('Search fields'),
         '#options' => $options,
         '#required' => TRUE,
-        '#default_value' => $this->options['search_fields'],
+        '#default_value' => isset($this->options['search_fields']) ? $this->options['search_fields'] : array(),
         '#description' => t('Select the field(s) that will be searched when using the autocomplete widget.'),
         '#weight' => -3,
       );