1222 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1222 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * @file
 | |
|  * Defines a field type for referencing a user from a node.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Implements hook_menu().
 | |
|  */
 | |
| function user_reference_menu() {
 | |
|   $items['user_reference/autocomplete/%/%/%'] = array(
 | |
|     'page callback' => 'user_reference_autocomplete',
 | |
|     'page arguments' => array(2, 3, 4),
 | |
|     'access callback' => 'reference_autocomplete_access',
 | |
|     'access arguments' => array(2, 3, 4),
 | |
|     'type' => MENU_CALLBACK,
 | |
|   );
 | |
|   return $items;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_info().
 | |
|  */
 | |
| function user_reference_field_info() {
 | |
|   return array(
 | |
|     'user_reference' => array(
 | |
|       'label' => t('User reference'),
 | |
|       'description' => t('This field stores the ID of a related user as an integer value.'),
 | |
|       'settings' => array(
 | |
|         'referenceable_roles' => array(),
 | |
|         'referenceable_status' => array(),
 | |
|         'view' => array(
 | |
|           'view_name' => '',
 | |
|           'display_name' => '',
 | |
|           'args' => array(),
 | |
|         ),
 | |
|       ),
 | |
|       'default_widget' => 'user_reference_autocomplete',
 | |
|       'default_formatter' => 'user_reference_default',
 | |
|       // Support hook_entity_property_info() from contrib "Entity API".
 | |
|       'property_type' => 'user',
 | |
|       // Support default token formatter for field tokens.
 | |
|       'default_token_formatter' => 'user_reference_plain',
 | |
|     ),
 | |
|   );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_schema();
 | |
|  */
 | |
| function user_reference_field_schema($field) {
 | |
|   $columns = array(
 | |
|     'uid' => array(
 | |
|       'type' => 'int',
 | |
|       'unsigned' => TRUE,
 | |
|       'not null' => FALSE,
 | |
|     ),
 | |
|   );
 | |
|   return array(
 | |
|     'columns' => $columns,
 | |
|     'indexes' => array('uid' => array('uid')),
 | |
|     'foreign keys' => array(
 | |
|       'uid' => array(
 | |
|         'table' => 'users',
 | |
|         'columns' => array('uid' => 'uid'),
 | |
|       ),
 | |
|     ),
 | |
|   );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_settings_form().
 | |
|  */
 | |
| function user_reference_field_settings_form($field, $instance, $has_data) {
 | |
|   $settings = $field['settings'];
 | |
| 
 | |
|   $form = array();
 | |
|   $form['referenceable_roles'] = array(
 | |
|     '#type' => 'checkboxes',
 | |
|     '#title' => t('User roles that can be referenced'),
 | |
|     '#default_value' => is_array($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' => is_array($settings['referenceable_status'])
 | |
|       ? array_filter($settings['referenceable_status'])
 | |
|       : array(1),
 | |
|     '#options' => array(1 => t('Active'), 0 => t('Blocked')),
 | |
|   );
 | |
| 
 | |
|   if (module_exists('views')) {
 | |
|     $view_settings = $settings['view'];
 | |
| 
 | |
|     $description = '<p>' . t('The list of users that can be referenced can provided by a view (Views module) using the "References" display type.') . '</p>';
 | |
| 
 | |
|     // Special note for legacy fields migrated from D6.
 | |
|     if (!empty($view_settings['view_name']) && $view_settings['display_name'] == 'default') {
 | |
|       $description .= '<p><strong><span class="admin-missing">'. t("Important D6 migration note:") . '</span></strong>';
 | |
|       $description .= '<br/>' . t("The field is currently configured to use the 'Master' display of the view %view_name.", array('%view_name' => $view_settings['view_name']));
 | |
|       $description .= '<br/>' . t("It is highly recommended that you: <br/>- edit this view and create a new display using the 'References' display type, <br/>- update the field settings to explicitly select the correct view and display.");
 | |
|       $description .= '<br/>' . t("The field will work correctly until then, but submitting this form might inadvertently change the field settings.") . '</p>';
 | |
|     }
 | |
| 
 | |
|     $form['view'] = array(
 | |
|       '#type' => 'fieldset',
 | |
|       '#title' => t('Views - Users that can be referenced'),
 | |
|       '#collapsible' => TRUE,
 | |
|       '#collapsed' => empty($view_settings['view_name']),
 | |
|       '#description' => $description,
 | |
|     );
 | |
| 
 | |
|     $views_options = references_get_views_options('user');
 | |
|     if ($views_options) {
 | |
|       // The value of the 'view_and_display' select below will need to be split
 | |
|       // into 'view_name' and 'view_display' in the final submitted values, so
 | |
|       // we massage the data at validate time on the wrapping element (not
 | |
|       // ideal).
 | |
|       $form['view']['#element_validate'] = array('_user_reference_view_settings_validate');
 | |
| 
 | |
|       $views_options = array('' => '<' . t('none') . '>') + $views_options;
 | |
|       $default = empty($view_settings['view_name']) ? '' : $view_settings['view_name'] . ':' .$view_settings['display_name'];
 | |
|       $form['view']['view_and_display'] = array(
 | |
|         '#type' => 'select',
 | |
|         '#title' => t('View used to select the users'),
 | |
|         '#options' => $views_options,
 | |
|         '#default_value' => $default,
 | |
|         '#description' => '<p>' . t('Choose the view and display that select the nodes that can be referenced.<br />Only views with a display of type "References" are eligible.') . '</p>' .
 | |
|           t('Note:<ul><li>This will discard the "Referenceable Roles" and "Referenceable Status" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate users on user creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate users will be displayed.</li></ul>'),
 | |
|       );
 | |
| 
 | |
|       $default = implode(', ', $view_settings['args']);
 | |
|       $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.'),
 | |
|       );
 | |
|     }
 | |
|     else {
 | |
|       $form['view']['no_view_help'] = array(
 | |
|         '#markup' => '<p>' . t('No eligible view was found.') .'</p>',
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return $form;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Validate callback for the 'view settings' fieldset.
 | |
|  *
 | |
|  * Puts back the various form values in the expected shape.
 | |
|  */
 | |
| function _user_reference_view_settings_validate($element, &$form_state, $form) {
 | |
|   // Split view name and display name from the 'view_and_display' value.
 | |
|   if (!empty($element['view_and_display']['#value'])) {
 | |
|     list($view, $display) = explode(':', $element['view_and_display']['#value']);
 | |
|   }
 | |
|   else {
 | |
|     $view = '';
 | |
|     $display = '';
 | |
|   }
 | |
| 
 | |
|   // Explode the 'args' string into an actual array. Beware, explode() turns an
 | |
|   // empty string into an array with one empty string. We'll need an empty array
 | |
|   // instead.
 | |
|   $args_string = trim($element['args']['#value']);
 | |
|   $args = ($args_string === '') ? array() : array_map('trim', explode(',', $args_string));
 | |
| 
 | |
|   $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args);
 | |
|   form_set_value($element, $value, $form_state);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_validate().
 | |
|  *
 | |
|  * Possible error codes:
 | |
|  * - 'invalid_uid': uid is not valid for the field (not a valid user id, or the user is not referenceable).
 | |
|  */
 | |
| function user_reference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
 | |
|   // Extract uids to check.
 | |
|   $ids = array();
 | |
| 
 | |
|   // First check non-numeric uid's to avoid losing time with them.
 | |
|   foreach ($items as $delta => $item) {
 | |
|     if (is_array($item) && !empty($item['uid'])) {
 | |
|       if (is_numeric($item['uid'])) {
 | |
|         $ids[] = $item['uid'];
 | |
|       }
 | |
|       else {
 | |
|         $errors[$field['field_name']][$langcode][$delta][] = array(
 | |
|           'error' => 'invalid_uid',
 | |
|           'message' => t('%name: invalid input.',
 | |
|             array('%name' => $instance['label'])),
 | |
|         );
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   // Prevent performance hog if there are no ids to check.
 | |
|   if ($ids) {
 | |
|     $options = array(
 | |
|       'ids' => $ids,
 | |
|     );
 | |
|     $refs = user_reference_potential_references($field, $options);
 | |
|     foreach ($items as $delta => $item) {
 | |
|       if (is_array($item)) {
 | |
|         if (!empty($item['uid']) && !isset($refs[$item['uid']])) {
 | |
|           $errors[$field['field_name']][$langcode][$delta][] = array(
 | |
|             'error' => 'invalid_uid',
 | |
|             'message' => t("%name: this user can't be referenced.",
 | |
|               array('%name' => $instance['label'])),
 | |
|           );
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_prepare_view().
 | |
|  */
 | |
| function user_reference_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
 | |
|   $checked_ids = &drupal_static(__FUNCTION__, array());
 | |
| 
 | |
|   // Set an 'access' property on each item (TRUE if the user exists).
 | |
| 
 | |
|   // Extract ids 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 ids that we haven't already loaded during this
 | |
|     // page request.
 | |
|     $ids_to_check = array_diff($ids, array_keys($checked_ids));
 | |
|     if (!empty($ids_to_check)) {
 | |
|       $query = db_select('users', 'u')
 | |
|         ->fields('u', array('uid'))
 | |
|         ->condition('u.uid', $ids_to_check, 'IN');
 | |
|       $accessible_ids = $query->execute()->fetchAllAssoc('uid');
 | |
| 
 | |
|       // Populate our static list so that we do not query on those ids again.
 | |
|       foreach ($ids_to_check as $id) {
 | |
|         $checked_ids[$id] = isset($accessible_ids[$id]);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     foreach ($items as $id => $entity_items) {
 | |
|       foreach ($entity_items as $delta => $item) {
 | |
|         if (is_array($item) && !empty($item['uid']) && !empty($checked_ids[$item['uid']])) {
 | |
|           $items[$id][$delta]['access'] = TRUE;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_is_empty().
 | |
|  */
 | |
| function user_reference_field_is_empty($item, $field) {
 | |
|   return empty($item['uid']);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_formatter_info().
 | |
|  */
 | |
| function user_reference_field_formatter_info() {
 | |
|   return array(
 | |
|     'user_reference_default' => array(
 | |
|       'label' => t('Default'),
 | |
|       'description' => t("Display the name of the referenced user as a link to the user's profile page."),
 | |
|       'field types' => array('user_reference'),
 | |
|     ),
 | |
|     'user_reference_plain' => array(
 | |
|       'label' => t('Plain text'),
 | |
|       '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'),
 | |
|     ),
 | |
|     'user_reference_uid' => array(
 | |
|       'label' => t('User ID'),
 | |
|       'description' => t('Display the referenced user ID'),
 | |
|       'field types' => array('user_reference'),
 | |
|     ),
 | |
|     'user_reference_path' => array(
 | |
|       'label' => t('URL as plain text'),
 | |
|       'description' => t('Display the URL of the referenced user'),
 | |
|       'field types' => array('user_reference'),
 | |
|       'settings' => array(
 | |
|         'alias' => TRUE,
 | |
|         'absolute' => FALSE
 | |
|       ),
 | |
|     ),
 | |
|   );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * 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'];
 | |
| 
 | |
|   $element = array();
 | |
| 
 | |
|   switch ($display['type']) {
 | |
|     case 'user_reference_user':
 | |
|       $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
 | |
|       );
 | |
|       break;
 | |
| 
 | |
|     case 'user_reference_path':
 | |
|       $element['alias'] = array(
 | |
|         '#type' => 'checkbox',
 | |
|         '#title' => t('Display the aliased path (if exists) instead of the system path'),
 | |
|         '#default_value' => $settings['alias'],
 | |
|       );
 | |
|       $element['absolute'] = array(
 | |
|         '#type' => 'checkbox',
 | |
|         '#title' => t('Display an absolute URL'),
 | |
|         '#default_value' => $settings['absolute'],
 | |
|       );
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   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'];
 | |
|   $summary = array();
 | |
| 
 | |
|   switch ($display['type']) {
 | |
|     case '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));
 | |
|       break;
 | |
| 
 | |
|     case 'user_reference_path':
 | |
|       $summary[] = t('Aliased path: %yes_no', array('%yes_no' => $settings['alias'] ? t('Yes') : t('No')));
 | |
|       $summary[] = t('Absolute URL: %yes_no', array('%yes_no' => $settings['absolute'] ? t('Yes') : t('No')));
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   return implode('<br />', $summary);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * 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) {
 | |
|   // Load the referenced users, except for the 'user_reference_uid' which does
 | |
|   // not need full objects.
 | |
| 
 | |
|   // Collect ids to load.
 | |
|   $ids = array();
 | |
|   foreach ($displays as $id => $display) {
 | |
|     if ($display['type'] != 'user_reference_uid') {
 | |
|       foreach ($items[$id] as $delta => $item) {
 | |
|         if ($item['access']) {
 | |
|           $ids[$item['uid']] = $item['uid'];
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   $entities = user_load_multiple($ids);
 | |
| 
 | |
|   // Add the loaded user objects to the items.
 | |
|   foreach ($displays as $id => $display) {
 | |
|     if ($display['type'] != 'user_reference_uid') {
 | |
|       foreach ($items[$id] as $delta => $item) {
 | |
|         if ($item['access']) {
 | |
|           $items[$id][$delta]['user'] = $entities[$item['uid']];
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } 
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_formatter_view().
 | |
|  */
 | |
| function user_reference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
 | |
|   $settings = $display['settings'];
 | |
|   $result = array();
 | |
| 
 | |
|   // @todo Optimisation: use hook_field_formatter_prepare_view() to load
 | |
|   // user names or full user entities in 'multiple' mode.
 | |
| 
 | |
|   // Collect the list of user ids.
 | |
|   $uids = array();
 | |
|   foreach ($items as $delta => $item) {
 | |
|     $uids[$item['uid']] = $item['uid'];
 | |
|   }
 | |
| 
 | |
|   switch ($display['type']) {
 | |
|     case 'user_reference_default':
 | |
|     case 'user_reference_plain':
 | |
|       foreach ($items as $delta => $item) {
 | |
|         if ($item['access']) {
 | |
|           $user = $item['user'];
 | |
|           $label = entity_label('user', $user);
 | |
|           if ($display['type'] == 'user_reference_default') {
 | |
|             $uri = entity_uri('user', $user);
 | |
|             $result[$delta] = array(
 | |
|               '#type' => 'link',
 | |
|               '#title' => $label,
 | |
|               '#href' => $uri['path'],
 | |
|               '#options' => $uri['options'],
 | |
|             );
 | |
|           }
 | |
|           else {
 | |
|             $result[$delta] = array(
 | |
|               '#markup' => check_plain($label),
 | |
|             );
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       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, $settings['user_reference_view_mode']);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       // 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'];
 | |
|             $label = entity_label('user', $user);
 | |
|             $uri = entity_uri('user', $account);
 | |
|             $result[$delta] = array(
 | |
|               '#type' => 'link',
 | |
|               '#title' => $label,
 | |
|               '#href' => $uri['path'],
 | |
|               '#options' => $uri['options'],
 | |
|             );
 | |
|             if (!$account->status) {
 | |
|               $result[$delta]['#prefix'] = '<span class="user-unpublished">';
 | |
|               $result[$delta]['#suffix'] = '</span>';
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case 'user_reference_uid':
 | |
|       foreach ($items as $delta => $item) {
 | |
|         if ($item['access']) {
 | |
|           $result[$delta] = array(
 | |
|             '#markup' => $item['uid'],
 | |
|           );
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case 'user_reference_path':
 | |
|       foreach ($items as $delta => $item) {
 | |
|         if ($item['access']) {
 | |
|           $uri = entity_uri('user', $item['user']);
 | |
|           $options = array(
 | |
|             'absolute' => $settings['absolute'],
 | |
|             'alias' => !$settings['alias'],
 | |
|           );
 | |
| 
 | |
|           $options += $uri['options'];
 | |
|           $result[$delta] = array(
 | |
|             '#markup' => url($uri['path'], $options),
 | |
|           );
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   return $result;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Helper function for widgets and formatters.
 | |
|  *
 | |
|  * Store user names collected in the curent request.
 | |
|  */
 | |
| function _user_reference_get_user_names($uids, $known_titles = array()) {
 | |
|   $titles = &drupal_static(__FUNCTION__, array());
 | |
| 
 | |
|   // Save titles we receive.
 | |
|   $titles += $known_titles;
 | |
| 
 | |
|   // Collect nids to retrieve from database.
 | |
|   $uids_query = array();
 | |
|   foreach ($uids as $uid) {
 | |
|     if (!isset($titles[$uid])) {
 | |
|       $uids_query[] = $uid;
 | |
|     }
 | |
|   }
 | |
|   if ($uids_query) {
 | |
|     $query = db_select('users', 'u')
 | |
|       ->fields('u', array('uid', 'name'))
 | |
|       ->condition('u.uid', $uids);
 | |
|     $titles += $query->execute()->fetchAllKeyed();
 | |
|   }
 | |
| 
 | |
|   // Build the results array.
 | |
|   $return = array();
 | |
|   foreach ($uids as $uid) {
 | |
|     $return[$uid] = isset($titles[$uid]) ? $titles[$uid] : '';
 | |
|   }
 | |
| 
 | |
|   return $return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_widget_info().
 | |
|  */
 | |
| function user_reference_field_widget_info() {
 | |
|   return array(
 | |
|     'user_reference_autocomplete' => array(
 | |
|       'label' => t('Autocomplete text field'),
 | |
|       'description' => t('Display the list of referenceable users as a textfield with autocomplete behaviour.'),
 | |
|       'field types' => array('user_reference'),
 | |
|       'settings' => array(
 | |
|         'autocomplete_match' => 'contains',
 | |
|         'size' => 60,
 | |
|         'autocomplete_path' => 'user_reference/autocomplete',
 | |
|       ),
 | |
|     ),
 | |
|   );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_widget_info_alter().
 | |
|  */
 | |
| function user_reference_field_widget_info_alter(&$info) {
 | |
|   $info['options_select']['field types'][] = 'user_reference';
 | |
|   $info['options_buttons']['field types'][] = 'user_reference';
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_widget_settings_form().
 | |
|  */
 | |
| function user_reference_field_widget_settings_form($field, $instance) {
 | |
|   $widget   = $instance['widget'];
 | |
|   $defaults = field_info_widget_settings($widget['type']);
 | |
|   $settings = array_merge($defaults, $widget['settings']);
 | |
| 
 | |
|   $form = array();
 | |
|   if ($widget['type'] == 'user_reference_autocomplete') {
 | |
|     $form['autocomplete_match'] = array(
 | |
|       '#type'             => 'select',
 | |
|       '#title'            => t('Autocomplete matching'),
 | |
|       '#default_value'    => $settings['autocomplete_match'],
 | |
|       '#options'          => array(
 | |
|         'starts_with'     => t('Starts with'),
 | |
|         'contains'        => t('Contains'),
 | |
|       ),
 | |
|       '#description'      => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of users.'),
 | |
|     );
 | |
|     $form['size'] = array(
 | |
|       '#type'             => 'textfield',
 | |
|       '#title'            => t('Size of textfield'),
 | |
|       '#default_value'    => $settings['size'],
 | |
|       '#element_validate' => array('_element_validate_integer_positive'),
 | |
|       '#required'         => TRUE,
 | |
|     );
 | |
|   }
 | |
|  return $form;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_widget_form().
 | |
|  */
 | |
| function user_reference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
 | |
|   switch ($instance['widget']['type']) {
 | |
|     case 'user_reference_autocomplete':
 | |
|       $element += array(
 | |
|         '#type' => 'textfield',
 | |
|         '#default_value' => isset($items[$delta]['uid']) ? $items[$delta]['uid'] : NULL,
 | |
|         '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
 | |
|         '#size' => $instance['widget']['settings']['size'],
 | |
|         '#element_validate' => array('user_reference_autocomplete_validate'),
 | |
|         '#value_callback' => 'user_reference_autocomplete_value',
 | |
|       );
 | |
|       break;
 | |
|   }
 | |
|   return array('uid' => $element);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Value callback for a user_reference autocomplete element.
 | |
|  *
 | |
|  * Substitute in the user name for the uid.
 | |
|  */
 | |
| function user_reference_autocomplete_value($element, $input = FALSE, $form_state) {
 | |
|   if ($input === FALSE) {
 | |
|     // We're building the displayed 'default value': expand the raw uid into
 | |
|     // "user name [uid:n]".
 | |
|     $uid = $element['#default_value'];
 | |
|     if (!empty($uid)) {
 | |
|       $q = db_select('users', 'u');
 | |
|       $q->addField('u', 'name');
 | |
| 
 | |
|       $q->condition('u.uid', $uid)
 | |
|         ->range(0, 1);
 | |
|       $result = $q->execute();
 | |
|       // @todo If no result (user doesn't exist).
 | |
|       $value = $result->fetchField();
 | |
|       $value .= ' [uid:' . $uid . ']';
 | |
|       return $value;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Validation callback for a user_reference autocomplete element.
 | |
|  */
 | |
| function user_reference_autocomplete_validate($element, &$form_state, $form) {
 | |
|   $field = field_widget_field($element, $form_state);
 | |
|   $instance = field_widget_instance($element, $form_state);
 | |
| 
 | |
|   $value = $element['#value'];
 | |
|   $uid = NULL;
 | |
| 
 | |
|   if (!empty($value)) {
 | |
|     // Check whether we have an explicit "[uid:n]" input.
 | |
|     preg_match('/^(?:\s*|(.*) )?\[\s*uid\s*:\s*(\d+)\s*\]$/', $value, $matches);
 | |
|     if (!empty($matches)) {
 | |
|       // Explicit uid. Check that the 'name' part matches the actual name for
 | |
|       // the uid.
 | |
|       list(, $name, $uid) = $matches;
 | |
|       if (!empty($name)) {
 | |
|         $names = _user_reference_get_user_names(array($uid));
 | |
|         if ($name != $names[$uid]) {
 | |
|           form_error($element, t('%name: name mismatch. Please check your selection.', array('%name' => $instance['label'])));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     else {
 | |
|       // No explicit uid (the submitted value was not populated by autocomplete
 | |
|       // selection). Get the uid of a referencable user from the entered name.
 | |
|       $options = array(
 | |
|         'string' => $value,
 | |
|         'match' => 'equals',
 | |
|         'limit' => 1,
 | |
|       );
 | |
|       $references = user_reference_potential_references($field, $options);
 | |
|       if ($references) {
 | |
|         // @todo The best thing would be to present the user with an
 | |
|         // additional form, allowing the user to choose between valid
 | |
|         // candidates with the same name. ATM, we pick the first
 | |
|         // matching candidate...
 | |
|         $uid = key($references);
 | |
|       }
 | |
|       else {
 | |
|         form_error($element, t('%name: found no valid user with that name.', array('%name' => $instance['label'])));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Set the element's value as the user id that was extracted from the entered
 | |
|   // input.
 | |
|   form_set_value($element, $uid, $form_state);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_widget_error().
 | |
|  */
 | |
| function user_reference_field_widget_error($element, $error, $form, &$form_state) {
 | |
|   form_error($element['uid'], $error['message']);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Builds a list of referenceable users suitable for the '#option' FAPI property.
 | |
|  *
 | |
|  * Warning: the function does NOT take care of encoding or escaping the user
 | |
|  * names. Proper massaging needs to be performed by the caller, according to
 | |
|  * the destination FAPI '#type' (radios / checkboxes / select).
 | |
|  *
 | |
|  * @param $field
 | |
|  *   The field definition.
 | |
|  *
 | |
|  * @return
 | |
|  *   An array of referenceable user names, keyed by user id.
 | |
|  */
 | |
| function _user_reference_options($field, $flat = TRUE) {
 | |
|   $references = user_reference_potential_references($field);
 | |
| 
 | |
|   $options = array();
 | |
|   foreach ($references as $key => $value) {
 | |
|     if (empty($value['group']) || $flat) {
 | |
|       $options[$key] = $value['rendered'];
 | |
|     }
 | |
|     else {
 | |
|       // The group name, displayed in selects, cannot contain tags, and should
 | |
|       // have HTML entities unencoded.
 | |
|       $group = html_entity_decode(strip_tags($value['group']), ENT_QUOTES);
 | |
|       $options[$group][$key] = $value['rendered'];
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return $options;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves an array of candidate referenceable users.
 | |
|  *
 | |
|  * This info is used in various places (aloowed values, autocomplete results,
 | |
|  * input validation...). Some of them only need the uids, others nid + names,
 | |
|  * others yet uid + names + rendered row (for display in widgets).
 | |
|  * The array we return contains all the potentially needed information, and lets
 | |
|  * consumers use the parts they actually need.
 | |
|  *
 | |
|  * @param $field
 | |
|  *   The field definition.
 | |
|  * @param $options
 | |
|  *   An array of options to limit the scope of the returned list. The following
 | |
|  *   key/value pairs are accepted:
 | |
|  *   - string: string to filter titles on (used by autocomplete).
 | |
|  *   - match: operator to match the above string against, can be any of:
 | |
|  *     'contains', 'equals', 'starts_with'. Defaults to 'contains'.
 | |
|  *   - ids: array of specific node ids to lookup.
 | |
|  *   - limit: maximum size of the the result set. Defaults to 0 (no limit).
 | |
|  *
 | |
|  * @return
 | |
|  *   An array of valid users in the form:
 | |
|  *   array(
 | |
|  *     uid => array(
 | |
|  *       'title' => The user name,
 | |
|  *       'rendered' => The text to display in widgets (can be HTML)
 | |
|  *     ),
 | |
|  *     ...
 | |
|  *   )
 | |
|  */
 | |
| function user_reference_potential_references($field, $options = array()) {
 | |
|   // Fill in default options.
 | |
|   $options += array(
 | |
|     'string' => '',
 | |
|     'match' => 'contains',
 | |
|     'ids' => array(),
 | |
|     'limit' => 0,
 | |
|   );
 | |
| 
 | |
|   $results = &drupal_static(__FUNCTION__, array());
 | |
| 
 | |
|   // Create unique id for static cache.
 | |
|   $cid = $field['field_name'] . ':' . $options['match'] . ':'
 | |
|     . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids']))
 | |
|     . ':' . $options['limit'];
 | |
|   if (!isset($results[$cid])) {
 | |
|     $references = FALSE;
 | |
|     if (module_exists('views') && !empty($field['settings']['view']['view_name'])) {
 | |
|       $references = _user_reference_potential_references_views($field, $options);
 | |
|     }
 | |
| 
 | |
|     if ($references === FALSE) {
 | |
|       $references = _user_reference_potential_references_standard($field, $options);
 | |
|     }
 | |
| 
 | |
|     // Store the results.
 | |
|     $results[$cid] = !empty($references) ? $references : array();
 | |
|   }
 | |
| 
 | |
|   return $results[$cid];
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Helper function for user_reference_potential_references().
 | |
|  *
 | |
|  * Case of Views-defined referenceable users.
 | |
|  */
 | |
| function _user_reference_potential_references_views($field, $options) {
 | |
|   $settings = $field['settings']['view'];
 | |
|   $options['title_field'] = 'name';
 | |
|   return references_potential_references_view('user', $settings['view_name'], $settings['display_name'], $settings['args'], $options);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Helper function for user_reference_potential_references().
 | |
|  *
 | |
|  * List of referenceable users defined by user role and status.
 | |
|  */
 | |
| function _user_reference_potential_references_standard($field, $options) {
 | |
|   // Avoid useless work.
 | |
|   $filter_roles = array_filter($field['settings']['referenceable_roles']);
 | |
|   $filter_status = array_filter($field['settings']['referenceable_status']);
 | |
|   if (!count($filter_status) && !count($filter_roles)) {
 | |
|     return array();
 | |
|   }
 | |
| 
 | |
|   $query = db_select('users', 'u')
 | |
|     // Select the whole record, so that format_username() has enough
 | |
|     // information.
 | |
|     ->fields('u')
 | |
|     ->addMetaData('id', ' _user_reference_potential_references_standard')
 | |
|     ->addMetaData('field', $field)
 | |
|     ->addMetaData('options', $options);
 | |
| 
 | |
|   // Enable this filter only if any statuses checked (and not both).
 | |
|   if (count($filter_status) == 1) {
 | |
|     $query->condition('u.status', array_keys($filter_status), 'IN');
 | |
|   }
 | |
| 
 | |
|   // Skip filter when "authenticated user" choosen.
 | |
|   if ($filter_roles && !isset($filter_roles[DRUPAL_AUTHENTICATED_RID])) {
 | |
|     $query->join('users_roles', 'r', 'u.uid = r.uid');
 | |
|     $query->condition('r.rid', array_keys($filter_roles), 'IN');
 | |
|   }
 | |
| 
 | |
|   if ($options['string'] !== '') {
 | |
|     switch ($options['match']) {
 | |
|       case 'contains':
 | |
|         $query->condition('u.name', '%' . $options['string'] . '%', 'LIKE');
 | |
|         break;
 | |
| 
 | |
|       case 'starts_with':
 | |
|         $query->condition('u.name', $options['string'] . '%', 'LIKE');
 | |
|         break;
 | |
| 
 | |
|       case 'equals':
 | |
|       default: // no match type or incorrect match type: use "="
 | |
|         $query->condition('u.name', $options['string'], '=');
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ($options['ids']) {
 | |
|     $query->condition('u.uid', $options['ids'], 'IN');
 | |
|   }
 | |
| 
 | |
|   // Explicitly exclude the anonymous user.
 | |
|   $query->condition('u.uid', 0, '<>');
 | |
| 
 | |
|   if ($options['limit']) {
 | |
|     $query->range(0, $options['limit']);
 | |
|   }
 | |
|   $query->orderBy('u.name');
 | |
| 
 | |
|   $result = $query->execute()->fetchAll();
 | |
|   $references = array();
 | |
|   foreach ($result as $account) {
 | |
|     $references[$account->uid] = array(
 | |
|       'title'    => $account->name,
 | |
|       'rendered' => check_plain(format_username($account)),
 | |
|     );
 | |
|   }
 | |
|   return $references;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Menu callback; Retrieve a pipe delimited string of autocomplete suggestions for existing users
 | |
|  */
 | |
| function user_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
 | |
|   $field = field_info_field($field_name);
 | |
|   $instance = field_info_instance($entity_type, $field_name, $bundle);
 | |
| 
 | |
|   $options = array(
 | |
|     'string' => $string,
 | |
|     'match' => $instance['widget']['settings']['autocomplete_match'],
 | |
|     'limit' => 10,
 | |
|   );
 | |
|   $references = user_reference_potential_references($field, $options);
 | |
| 
 | |
|   $matches = array();
 | |
|   foreach ($references as $id => $row) {
 | |
|     // Markup is fine in autocompletion results (might happen when rendered
 | |
|     // through Views) but we want to remove hyperlinks.
 | |
|     $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
 | |
|     // Remove link tags Add a class wrapper for a few required CSS overrides.
 | |
|     $matches[$row['title'] . " [uid:$id]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
 | |
|   }
 | |
|   drupal_json_output($matches);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_options_list().
 | |
|  */
 | |
| function user_reference_options_list($field) {
 | |
|   return _user_reference_options($field, FALSE);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implementation of hook_user_load().
 | |
|  */
 | |
| /*function user_reference_user_load($accounts) {
 | |
| 
 | |
|   // Only add links if we are on the user 'view' page.
 | |
|   if (arg(0) != 'user' || arg(2)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   foreach ($accounts as $uid => $account) {
 | |
| 
 | |
|     // find CCK user_reference field tables
 | |
|     // search through them for matching user ids and load those nodes
 | |
|     $additions = array();
 | |
|     $fields = field_info_instances('user');
 | |
| 
 | |
|     // TODO : replace with field_attach_query() + synchronize with latest D6 code.
 | |
| 
 | |
|     // Find the table and columns to search through, if the same
 | |
|     // table comes up in more than one field type, we only need
 | |
|     // to search it once.
 | |
|     $search_tables = array();
 | |
|     $search_links = array();
 | |
|     foreach ($fields as $field) {
 | |
|       if ($field['type'] == 'user_reference' && !empty($field['widget']['reverse_link'])) {
 | |
|         $db_info = content_database_info($field);
 | |
|         $search_tables[$db_info['table']] = $db_info['columns']['uid']['column'];
 | |
|         $search_links[$db_info['table']] = $field['widget']['reverse_link'];
 | |
|       }
 | |
|     }
 | |
|     foreach ($search_tables as $table => $column) {
 | |
|       $ids = db_query(db_rewrite_sql("SELECT DISTINCT(n.nid) FROM {node} n LEFT JOIN {". $table ."} f ON n.vid = f.vid WHERE f.". $column ."=". $account->uid. " AND n.status = 1"));
 | |
|       while ($data = db_fetch_object($ids)) {
 | |
|         // TODO, do we really want a complete node_load() here? We only need the title to create a link.
 | |
|         $node = node_load($data->nid);
 | |
|         $node->reverse_link = $search_links[$table];
 | |
|         $additions[$node->type][] = $node;
 | |
|       }
 | |
|     }
 | |
|     $accounts[$uid]->user_reference = $additions;
 | |
|   }
 | |
|   return;
 | |
| }*/
 | |
| 
 | |
| /**
 | |
|  * Implementation of hook_user_view().
 | |
|  */
 | |
| /*function user_reference_user_view($account, $view_mode, $langcode) {
 | |
|   if (!empty($account->user_reference)) {
 | |
|     $node_types = content_types();
 | |
|     $additions = array();
 | |
|     $values = array();
 | |
|     foreach ($account->user_reference as $node_type => $nodes) {
 | |
|       foreach ($nodes as $node) {
 | |
|         if ($node->reverse_link) {
 | |
|           $values[$node_type][] = l($node->title, 'node/' . $node->nid);
 | |
|         }
 | |
|       }
 | |
|       if (isset($values[$node_type])) {
 | |
|         $additions[] = array(
 | |
|           '#type' => 'user_profile_item',
 | |
|           '#title' => check_plain($node_types[$node_type]['name']),
 | |
|           '#value' => theme('item_list', $values[$node_type]),
 | |
|         );
 | |
|       }
 | |
|     }
 | |
|     if ($additions) {
 | |
|       $account->content['user_reference'] = $additions + array(
 | |
|         '#type' => 'user_profile_category',
 | |
|         '#attributes' => array('class' => array('user-member')),
 | |
|         '#title' => t('Related content'),
 | |
|         '#weight' => 10,
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| }*/
 | |
| 
 | |
| /**
 | |
|  * Implements hook_content_migrate_field_alter().
 | |
|  *
 | |
|  * Use this to tweak the conversion of field settings
 | |
|  * from the D6 style to the D7 style for specific
 | |
|  * situations not handled by basic conversion,
 | |
|  * as when field types or settings are changed.
 | |
|  *
 | |
|  * $field_value['widget_type'] is available to
 | |
|  * see what widget type was originally used.
 | |
|  */
 | |
| function user_reference_content_migrate_field_alter(&$field_value, $instance_value) {
 | |
|   switch ($field_value['module']) {
 | |
|     case 'userreference':
 | |
|       $field_value['module'] = 'user_reference';
 | |
|       $field_value['type'] = 'user_reference';
 | |
| 
 | |
|       // Translate 'view' settings.
 | |
|       $view_name = isset($field_value['settings']['advanced_view']) ? $field_value['settings']['advanced_view'] : '';
 | |
|       $view_args = isset($field_value['settings']['advanced_view_args']) ? $field_value['settings']['advanced_view_args'] : '';
 | |
|       $view_args = array_map('trim', explode(',', $view_args));
 | |
|       $field_value['settings']['view'] = array(
 | |
|         'view_name' => $view_name,
 | |
|         'display_name' => 'default',
 | |
|         'args' => $view_args,
 | |
|       );
 | |
|       if ($view_name) {
 | |
|         $field_value['messages'][] = t("The field uses the view @view_name to determine referenceable users. You will need to manually edit the view and add a display of type 'References'.");
 | |
|       }
 | |
|       unset($field_value['settings']['advanced_view']);
 | |
|       unset($field_value['settings']['advanced_view_args']);
 | |
|       break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_content_migrate_instance_alter().
 | |
|  *
 | |
|  * Use this to tweak the conversion of instance or widget settings
 | |
|  * from the D6 style to the D7 style for specific
 | |
|  * situations not handled by basic conversion, as when
 | |
|  * formatter or widget names or settings are changed.
 | |
|  */
 | |
| function user_reference_content_migrate_instance_alter(&$instance_value, $field_value) {
 | |
|   // The module name for the instance was corrected
 | |
|   // by the change in user_reference_content_migrate_field_alter().
 | |
|   switch ($field_value['type']) {
 | |
|     case 'userreference':
 | |
|       // The formatter names changed, all are prefixed
 | |
|       // with 'user_reference_'.
 | |
|       foreach ($instance_value['display'] as $context => $settings) {
 | |
|         $instance_value['display'][$context]['type'] = 'user_reference_' . $settings['type'];
 | |
|       }
 | |
|       // Massage the widget.
 | |
|       switch ($instance_value['widget']['type']) {
 | |
|         case 'userreference_autocomplete':
 | |
|           $instance_value['widget']['type'] = 'user_reference_autocomplete';
 | |
|           $instance_value['widget']['module'] = 'user_reference';
 | |
|           break;
 | |
|         case 'userreference_select':
 | |
|           $instance_value['widget']['type'] = 'options_select';
 | |
|           $instance_value['widget']['module'] = 'options';
 | |
|           break;
 | |
|         case 'userreference_buttons':
 | |
|           $instance_value['widget']['type'] = 'options_buttons';
 | |
|           $instance_value['widget']['module'] = 'options';
 | |
|       }
 | |
|       break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_views_data().
 | |
|  *
 | |
|  * In addition to the default field information we add the relationship for
 | |
|  * views to connect back to the users table.
 | |
|  */
 | |
| function user_reference_field_views_data($field) {
 | |
|   // No module_load_include(): this hook is invoked from
 | |
|   // views/modules/field.views.inc, which is where that function is defined.
 | |
|   $data = field_views_field_default_views_data($field);
 | |
| 
 | |
|   $storage = $field['storage']['details']['sql'];
 | |
| 
 | |
|   foreach ($storage as $age => $table_data) {
 | |
|     $table = key($table_data);
 | |
|     $columns = current($table_data);
 | |
|     $id_column = $columns['uid'];
 | |
|     if (isset($data[$table])) {
 | |
|       // Filter: swap the handler to the 'in' operator. The callback receives
 | |
|       // the field name instead of the whole $field structure to keep views
 | |
|       // data to a reasonable size.
 | |
|       $data[$table][$id_column]['filter']['handler'] = 'views_handler_filter_in_operator';
 | |
|       $data[$table][$id_column]['filter']['options callback'] = 'user_reference_views_filter_options';
 | |
|       $data[$table][$id_column]['filter']['options arguments'] = array($field['field_name']);
 | |
| 
 | |
|       // Argument: display users.name in argument titles (handled in our custom
 | |
|       // handler) and summary lists (handled by the base views_handler_argument
 | |
|       // handler).
 | |
|       // Both mechanisms rely on the 'name table' and 'name field' information
 | |
|       // below, by joining to a separate copy of the base table from the field
 | |
|       // data table.
 | |
|       $data[$table][$id_column]['argument']['handler'] = 'references_handler_argument';
 | |
|       $data[$table][$id_column]['argument']['name table'] = $table . '_reference';
 | |
|       $data[$table][$id_column]['argument']['name field'] = 'name';
 | |
|       $data[$table . '_reference']['table']['join'][$table] = array(
 | |
|         'left_field' => $id_column,
 | |
|         'table' => 'users',
 | |
|         'field' => 'uid',
 | |
|       );
 | |
| 
 | |
|       // Relationship.
 | |
|       $data[$table][$id_column]['relationship'] = array(
 | |
|         'handler' => 'references_handler_relationship',
 | |
|         'base' => 'users',
 | |
|         'base field' => 'uid',
 | |
|         'field' => $id_column,
 | |
|         'label' => $field['field_name'],
 | |
|         'field_name' => $field['field_name'],
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return $data;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements hook_field_views_data_views_data_alter().
 | |
|  */
 | |
| function user_reference_field_views_data_views_data_alter(&$data, $field) {
 | |
|   foreach ($field['bundles'] as $entity_type => $bundles) {
 | |
|     $entity_info = entity_get_info($entity_type);
 | |
|     $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
 | |
| 
 | |
|     list($label, $all_labels) = field_views_field_label($field['field_name']);
 | |
|     $entity = $entity_info['label'];
 | |
|     if ($entity == t('Node')) {
 | |
|       $entity = t('Content');
 | |
|     }
 | |
| 
 | |
|     // Only specify target entity type if the field is used in more than one.
 | |
|     if (count($field['bundles']) > 1) {
 | |
|       $title = t('@field (@field_name) - reverse (to @entity)', array('@entity' => $entity, '@field' => $label, '@field_name' => $field['field_name']));
 | |
|     }
 | |
|     else {
 | |
|       $title = t('@field (@field_name) - reverse', array('@entity' => $entity, '@field' => $label, '@field_name' => $field['field_name']));
 | |
|     }
 | |
|     $data['users'][$pseudo_field_name]['relationship'] = array(
 | |
|       'title' => $title,
 | |
|       'help' => t('Relate each @entity referencing the user through @field.', array('@entity' => $entity, '@field' => $label)),
 | |
|       'handler' => 'views_handler_relationship_entity_reverse',
 | |
|       'field_name' => $field['field_name'],
 | |
|       'field table' => _field_sql_storage_tablename($field),
 | |
|       'field field' => $field['field_name'] . '_uid',
 | |
|       'base' => $entity_info['base table'],
 | |
|       'base field' => $entity_info['entity keys']['id'],
 | |
|       'label' => t('!field_name', array('!field_name' => $field['field_name'])),
 | |
|     );
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Helper callback for the views_handler_filter_in_operator filter.
 | |
|  *
 | |
|  * @param $field_name
 | |
|  *   The field name.
 | |
|  *
 | |
|  * @return
 | |
|  *   The array of allowed options for the filter.
 | |
|  */
 | |
| function user_reference_views_filter_options($field_name) {
 | |
|   $options = array();
 | |
| 
 | |
|   if ($field = field_info_field($field_name)) {
 | |
|     $options = _user_reference_options($field, TRUE);
 | |
|     // The options will be used as is in checkboxes, and thus need to be
 | |
|     // sanitized first.
 | |
|     foreach ($options as $key => $value) {
 | |
|       $options[$key] = field_filter_xss($value);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return $options;
 | |
| }
 | 
