? test.patch
Index: node_reference/node_reference.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/references/node_reference/node_reference.module,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 node_reference.module
--- node_reference/node_reference.module	24 Jan 2011 14:41:44 -0000	1.1.2.2
+++ node_reference/node_reference.module	4 Feb 2011 21:59:32 -0000
@@ -353,7 +353,7 @@
           $nodes_display[$nid]->referencing_entity = $entity;
           $nodes_display[$nid]->referencing_field = $field['field_name'];
         }
-        $nodes_built = node_view_multiple($nodes_display, $view_mode);
+        $nodes_built = node_view_multiple($nodes_display, $view_mode, 0, $langcode);
       }
 
       // Assemble the render array.
Index: user_reference/user_reference.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/references/user_reference/user_reference.module,v
retrieving revision 1.1.2.3
diff -u -r1.1.2.3 user_reference.module
--- user_reference/user_reference.module	31 Jan 2011 18:28:56 -0000	1.1.2.3
+++ user_reference/user_reference.module	4 Feb 2011 21:59:33 -0000
@@ -129,6 +129,53 @@
 }
 
 /**
+ * Implements hook_field_prepare_view().
+ */
+function user_reference_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
+  // @todo : do we need the static ?
+  $fetched_accounts = &drupal_static(__FUNCTION__, array());
+
+  // Extract uids to check.
+  $ids = array();
+  foreach ($items as $id => $entity_items) {
+    foreach ($entity_items as $delta => $item) {
+      if (is_array($item)) {
+        // Default to 'not accessible'.
+        $items[$id][$delta]['access'] = FALSE;
+        if (!empty($item['uid']) && is_numeric($item['uid'])) {
+          $ids[$item['uid']] = $item['uid'];
+        }
+      }
+    }
+  }
+
+  if ($ids) {
+    // Load information about nids that we haven't already loaded during
+    // this page request.
+    $missing_ids = array_diff($ids, array_keys($fetched_accounts));
+    if (!empty($missing_ids)) {
+      $query = db_select('users', 'u')
+        ->fields('u')
+        ->condition('u.uid', $missing_ids)
+        ->addTag('user_access');
+      if (!user_access('administer users')) {
+        $query->condition('status', 1);
+      }
+      $fetched_accounts = $query->execute()->fetchAllAssoc('uid');
+    }
+
+    foreach ($items as $id => $entity_items) {
+      foreach ($entity_items as $delta => $item) {
+        if (is_array($item) && !empty($item['uid']) && isset($fetched_accounts[$item['uid']])) {
+          $items[$id][$delta]['user'] = $fetched_accounts[$item['uid']];
+          $items[$id][$delta]['access'] = TRUE;
+        }
+      }
+    }
+  }
+}
+
+/**
  * Implements hook_field_is_empty().
  */
 function user_reference_field_is_empty($item, $field) {
@@ -150,7 +197,92 @@
       'description' => t('Display the name of the referenced user as plain text.'),
       'field types' => array('user_reference'),
     ),
+    'user_reference_user' => array(
+      'label'       => t('Rendered user'),
+      'description' => t('Display the referenced user in a specific view mode'),
+      'field types' => array('user_reference'),
+      'settings'    => array('user_reference_view_mode' => 'full'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_prepare_view().
+ *
+ * Preload all user referenced by items using 'full entity' formatters.
+ */
+function user_reference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
+  // Collect uids to load.
+  // @todo : can we make clever use of the recursion queue here ?
+  $uids = array();
+  foreach ($displays as $id => $display) {
+    if ($display['type'] == 'user_reference_user') {
+      foreach ($items[$id] as $delta => $item) {
+        if ($item['access']) {
+          $uids[$item['uid']] = $item['uid'];
+        }
+      }
+    }
+  }
+  $accounts = user_load_multiple($uids);
+
+  // Add the loaded users to the items.
+  foreach ($displays as $id => $display) {
+    if ($display['type'] == 'user_reference_user') {
+      foreach ($items[$id] as $delta => $item) {
+        if ($item['access']) {
+          $items[$id][$delta]['user'] = $accounts[$item['uid']];
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function user_reference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  // Only build this information for user_reference_user displays
+  if ($display['type'] !== 'user_reference_user') {
+    return NULL;
+  }
+
+  $entity_info = entity_get_info('user');
+  $modes = $entity_info['view modes'];
+  $options = array();
+  foreach ($modes as $name => $mode) {
+    $options[$name] = $mode['label'];
+  }
+  $element['user_reference_view_mode'] = array(
+    '#title'   => t('View mode'),
+    '#type'    => 'select',
+    '#options' => $options,
+    '#default_value' => $settings['user_reference_view_mode'],
+    // Never empty, so no #empty_option
   );
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function user_reference_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  if ($display['type'] === 'user_reference_user') {
+    $entity_info = entity_get_info('user');
+    $modes = $entity_info['view modes'];
+    $mode = $modes[$settings['user_reference_view_mode']]['label'];
+    $summary = t('View mode: %mode', array('%mode' => $mode));
+  }
+  else {
+    $summary = NULL;
+  }
+  return $summary;
 }
 
 /**
@@ -187,6 +319,70 @@
         }
       }
       break;
+
+    case 'user_reference_user':
+      $view_mode = $display['settings']['user_reference_view_mode'];
+      // To prevent infinite recursion caused by reference cycles, we store
+      // diplayed accounts in a recursion queue.
+      $recursion_queue = &drupal_static(__FUNCTION__, array());
+
+      // If no 'referencing entity' is set, we are starting a new 'reference
+      // thread' and need to reset the queue.
+      // @todo Bug: $entity->referencing_entity on accounts referenced in a different
+      // thread on the page. E.g: 1 references 1+2 / 2 references 1+2 / visit homepage.
+      // We'd need a more accurate way...
+      if (!isset($entity->referencing_entity)) {
+        $recursion_queue = array();
+      }
+
+      // The recursion queue only needs to track nodes.
+      if ($entity_type == 'user') {
+        list($id) = entity_extract_ids($entity_type, $entity);
+        $recursion_queue[$id] = $id;
+      }
+
+      // Check the recursion queue to determine which accounts should be fully
+      // displayed, and which accounts will only be displayed as a username.
+      $users_display = array();
+      foreach ($items as $delta => $item) {
+        if ($item['access'] && !isset($recursion_queue[$item['uid']])) {
+          $users_display[$item['uid']] = $item['user'];
+        }
+      }
+
+      // Load and build the fully displayed nodes.
+      if ($users_display) {
+        $users_built = array('users' => array('#sorted' => TRUE));
+        foreach ($users_display as $uid => $account) {
+          $users_display[$uid]->referencing_entity = $entity;
+          $users_display[$uid]->referencing_field = $field['field_name'];
+          $users_built['users'][$account->uid] = user_view($account, $view_mode, $langcode);
+        }
+      }
+
+      // Assemble the render array.
+      foreach ($items as $delta => $item) {
+        if ($item['access']) {
+          if (isset($users_display[$item['uid']])) {
+            $result[$delta] = $users_built['users'][$item['uid']];
+          }
+          else {
+            $account = $item['user'];
+            $uri = entity_uri('user', $account);
+            $result[$delta] = array(
+              '#type' => 'link',
+              '#title' => $account->name,
+              '#href' => $uri['path'],
+              '#options' => $uri['options'],
+            );
+            if (!$account->status) {
+              $result[$delta]['#prefix'] = '<span class="user-unpublished">';
+              $result[$delta]['#suffix'] = '</span>';
+            }
+          }
+        }
+      }
+      break;
   }
 
   return $result;
