source: sipes/modules_contrib/cck/modules/userreference/userreference.module @ a8b1f3f

stableversion-3.0
Last change on this file since a8b1f3f was dafc8d8, checked in by José Gregorio Puentes <jpuentes@…>, 8 años ago

se actualizo el modulo

  • Propiedad mode establecida a 100755
File size: 33.5 KB
Línea 
1<?php
2
3/**
4 * @file
5 * Defines a field type for referencing a user from a node.
6 */
7
8// We do not use hook_init(), since that hook is not fired in update.php, and we
9// need token generation to be active within hook_update_N() (e.g. for
10// node_save() calls.)
11require_once dirname(__FILE__) . '/userreference.token.inc';
12
13/**
14 * Implementation of hook_menu().
15 */
16function userreference_menu() {
17  $items = array();
18  $items['userreference/autocomplete'] = array(
19    'title' => 'Userreference autocomplete',
20    'page callback' => 'userreference_autocomplete',
21    'access arguments' => array('access content'),
22    'type' => MENU_CALLBACK
23  );
24  return $items;
25}
26
27/**
28 * Implementation of hook_theme().
29 */
30function userreference_theme() {
31  return array(
32    'userreference_select' => array(
33      'arguments' => array('element' => NULL),
34    ),
35    'userreference_buttons' => array(
36      'arguments' => array('element' => NULL),
37    ),
38    'userreference_autocomplete' => array(
39      'arguments' => array('element' => NULL),
40    ),
41    'userreference_formatter_default' => array(
42      'arguments' => array('element'),
43    ),
44    'userreference_formatter_plain' => array(
45      'arguments' => array('element'),
46    ),
47  );
48}
49
50/**
51 * Implementaion of hook_ctools_plugin_directory().
52 */
53function userreference_ctools_plugin_directory($module, $plugin) {
54  if ($module == 'ctools' && $plugin == 'relationships') {
55    return 'panels/' . $plugin;
56  }
57}
58
59/**
60 * Implementation of hook_field_info().
61 */
62function userreference_field_info() {
63  return array(
64    'userreference' => array(
65      'label' => t('User reference'),
66      'description' => t('Store the ID of a related user as an integer value.'),
67//      'content_icon' => 'icon_content_noderef.png',
68    ),
69  );
70}
71
72/**
73 * Implementation of hook_field_settings().
74 */
75function userreference_field_settings($op, $field) {
76  switch ($op) {
77    case 'form':
78      $form = array();
79      $form['referenceable_roles'] = array(
80        '#type' => 'checkboxes',
81        '#title' => t('User roles that can be referenced'),
82        '#default_value' => isset($field['referenceable_roles']) && is_array($field['referenceable_roles']) ? array_filter($field['referenceable_roles']) : array(),
83        '#options' => user_roles(1),
84      );
85      $form['referenceable_status'] = array(
86        '#type' => 'radios',
87        '#title' => t('User status that can be referenced'),
88        '#default_value' => isset($field['referenceable_status']) ? $field['referenceable_status'] : '',
89        '#options' => array('' => t('All users'), 1 => t('Active users'), 0 => t('Blocked users')),
90      );
91      if (module_exists('views')) {
92        $views = array('--' => '--');
93        $all_views = views_get_all_views();
94        foreach ($all_views as $view) {
95          // Only 'users' views that have fields will work for our purpose.
96          if ($view->base_table == 'users' && !empty($view->display['default']->display_options['fields'])) {
97            if ($view->type == 'Default') {
98              $views[t('Default Views')][$view->name] = $view->name;
99            }
100            else {
101              $views[t('Existing Views')][$view->name] = $view->name;
102            }
103          }
104        }
105
106        $form['advanced'] = array(
107           '#type' => 'fieldset',
108           '#title' => t('Advanced - Users that can be referenced (View)'),
109           '#collapsible' => TRUE,
110           '#collapsed' => !isset($field['advanced_view']) || $field['advanced_view'] == '--',
111         );
112        if (count($views) > 1) {
113          $form['advanced']['advanced_view'] = array(
114            '#type' => 'select',
115            '#title' => t('View used to select the users'),
116            '#options' => $views,
117            '#default_value' => isset($field['advanced_view']) ? $field['advanced_view'] : '--',
118            '#description' =>  t('<p>Choose the "Views module" view that selects the users that can be referenced.<br />Note:</p>') .
119              t('<ul><li>Only views that have fields will work for this purpose.</li><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>'),
120          );
121          $form['advanced']['advanced_view_args'] = array(
122            '#type' => 'textfield',
123            '#title' => t('View arguments'),
124            '#default_value' => isset($field['advanced_view_args']) ? $field['advanced_view_args'] : '',
125            '#required' => FALSE,
126            '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
127          );
128        }
129        else {
130          $form['advanced']['no_view_help'] = array(
131            '#value' => t('<p>The list of user that can be referenced can be based on a "Views module" view but no appropriate views were found. <br />Note:</p>') .
132              t('<ul><li>Only views that have fields will work for this purpose.</li><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>'),
133          );
134        }
135      }
136      return $form;
137
138    case 'save':
139      $settings = array('referenceable_roles', 'referenceable_status');
140      if (module_exists('views')) {
141        $settings[] = 'advanced_view';
142        $settings[] = 'advanced_view_args';
143      }
144      return $settings;
145
146    case 'database columns':
147      $columns = array(
148        'uid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => FALSE, 'index' => TRUE),
149      );
150      return $columns;
151
152    case 'views data':
153      $data = content_views_field_views_data($field);
154      $db_info = content_database_info($field);
155      $table_alias = content_views_tablename($field);
156
157      // Filter : swap the handler to the 'in' operator.
158      $data[$table_alias][$field['field_name'] .'_uid']['filter']['handler'] = 'content_handler_filter_many_to_one';
159      // Argument: get the user name for summaries.
160      // We need to join a new instance of the users table.
161      $data["users_$table_alias"]['table']['join']['node'] = array(
162        'table' => 'users',
163        'field' => 'uid',
164        'left_table' => $table_alias,
165        'left_field' => $field['field_name'] .'_uid',
166      );
167      $data[$table_alias][$field['field_name'] .'_uid']['argument']['handler'] = 'content_handler_argument_reference';
168      $data[$table_alias][$field['field_name'] .'_uid']['argument']['name table'] = "users_$table_alias";
169      $data[$table_alias][$field['field_name'] .'_uid']['argument']['name field'] = 'name';
170      // Relationship: Add a relationship for related user.
171      $data[$table_alias][$field['field_name'] .'_uid']['relationship'] = array(
172        'base' => 'users',
173        'field' => $db_info['columns']['uid']['column'],
174        'handler' => 'content_handler_relationship',
175        'label' => t($field['widget']['label']),
176        'content_field_name' => $field['field_name'],
177      );
178      return $data;
179
180  }
181}
182
183/**
184 * Implementation of hook_field().
185 */
186function userreference_field($op, &$node, $field, &$items, $teaser, $page) {
187  switch ($op) {
188    case 'validate':
189      // Extract uids to check.
190      $ids = array();
191      foreach ($items as $delta => $item) {
192        if (is_array($item) && !empty($item['uid'])) {
193          if (is_numeric($item['uid'])) {
194            $ids[] = $item['uid'];
195          }
196          else {
197            $error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
198            if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']);
199            form_set_error($error_element, t('%name: invalid input.', array('%name' => t($field['widget']['label']))));
200          }
201        }
202      }
203      // Prevent performance hog if there are no ids to check.
204      if ($ids) {
205        $refs = _userreference_potential_references($field, '', NULL, $ids);
206        foreach ($items as $delta => $item) {
207          if (is_array($item)) {
208            $error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
209            if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']);
210            if (!empty($item['uid']) && !isset($refs[$item['uid']])) {
211              form_set_error($error_element, t('%name: invalid user.', array('%name' => t($field['widget']['label']))));
212            }
213          }
214        }
215      }
216      return $items;
217  }
218}
219
220/**
221 * Implementation of hook_content_is_empty().
222 */
223function userreference_content_is_empty($item, $field) {
224  if (empty($item['uid'])) {
225    return TRUE;
226  }
227  return FALSE;
228}
229
230/**
231 * Implementation of hook_field_formatter_info().
232 */
233function userreference_field_formatter_info() {
234  return array(
235    'default' => array(
236      'label' => t('Default'),
237      'field types' => array('userreference'),
238      'multiple values' => CONTENT_HANDLE_CORE,
239    ),
240    'plain' => array(
241      'label' => t('Plain text'),
242      'field types' => array('userreference'),
243      'multiple values' => CONTENT_HANDLE_CORE,
244    ),
245  );
246}
247
248/**
249 * Theme function for 'default' userreference field formatter.
250 */
251function theme_userreference_formatter_default($element) {
252  $output = '';
253
254  if (isset($element['#item']['uid']) && $account = user_load(array('uid' => $element['#item']['uid']))) {
255    $output = theme('username', $account);
256  }
257  return $output;
258}
259
260/**
261 * Theme function for 'plain' userreference field formatter.
262 */
263function theme_userreference_formatter_plain($element) {
264  $output = '';
265  if (isset($element['#item']['uid']) && $account = user_load(array('uid' => $element['#item']['uid']))) {
266    $output = $account->name;
267  }
268  return $output;
269}
270
271/**
272 * Implementation of hook_widget_info().
273 *
274 * We need custom handling of multiple values for the userreference_select
275 * widget because we need to combine them into a options list rather
276 * than display multiple elements.
277 *
278 * We will use the content module's default handling for default value.
279 *
280 * Callbacks can be omitted if default handing is used.
281 * They're included here just so this module can be used
282 * as an example for custom modules that might do things
283 * differently.
284 */
285function userreference_widget_info() {
286  return array(
287    'userreference_select' => array(
288      'label' => t('Select list'),
289      'field types' => array('userreference'),
290      'multiple values' => CONTENT_HANDLE_MODULE,
291      'callbacks' => array(
292        'default value' => CONTENT_CALLBACK_DEFAULT,
293      ),
294    ),
295    'userreference_buttons' => array(
296      'label' => t('Check boxes/radio buttons'),
297      'field types' => array('userreference'),
298      'multiple values' => CONTENT_HANDLE_MODULE,
299      'callbacks' => array(
300        'default value' => CONTENT_CALLBACK_DEFAULT,
301      ),
302    ),
303    'userreference_autocomplete' => array(
304      'label' => t('Autocomplete text field'),
305      'field types' => array('userreference'),
306      'multiple values' => CONTENT_HANDLE_CORE,
307      'callbacks' => array(
308        'default value' => CONTENT_CALLBACK_DEFAULT,
309      ),
310    ),
311  );
312}
313
314/**
315 * Implementation of FAPI hook_elements().
316 *
317 * Any FAPI callbacks needed for individual widgets can be declared here,
318 * and the element will be passed to those callbacks for processing.
319 *
320 * Drupal will automatically theme the element using a theme with
321 * the same name as the hook_elements key.
322 *
323 * Autocomplete_path is not used by text_widget but other widgets can use it
324 * (see nodereference and userreference).
325 */
326function userreference_elements() {
327  return array(
328    'userreference_select' => array(
329      '#input' => TRUE,
330      '#columns' => array('uid'), '#delta' => 0,
331      '#process' => array('userreference_select_process'),
332    ),
333    'userreference_buttons' => array(
334      '#input' => TRUE,
335      '#columns' => array('uid'), '#delta' => 0,
336      '#process' => array('userreference_buttons_process'),
337    ),
338    'userreference_autocomplete' => array(
339      '#input' => TRUE,
340      '#columns' => array('name'), '#delta' => 0,
341      '#process' => array('userreference_autocomplete_process'),
342      '#autocomplete_path' => FALSE,
343      ),
344    );
345}
346
347/**
348 * Implementation of hook_widget_settings().
349 */
350function userreference_widget_settings($op, $widget) {
351  switch ($op) {
352    case 'form':
353      $form = array();
354      $match = isset($widget['autocomplete_match']) ? $widget['autocomplete_match'] : 'contains';
355      $size = (isset($widget['size']) && is_numeric($widget['size'])) ? $widget['size'] : 60;
356      if ($widget['type'] == 'userreference_autocomplete') {
357        $form['autocomplete_match'] = array(
358          '#type' => 'select',
359          '#title' => t('Autocomplete matching'),
360          '#default_value' => $match,
361          '#options' => array(
362            'starts_with' => t('Starts with'),
363            'contains' => t('Contains'),
364          ),
365          '#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.'),
366        );
367        $form['size'] = array(
368          '#type' => 'textfield',
369          '#title' => t('Size of textfield'),
370          '#default_value' => $size,
371          '#element_validate' => array('_element_validate_integer_positive'),
372          '#required' => TRUE,
373        );
374      }
375      else {
376        $form['autocomplete_match'] = array('#type' => 'hidden', '#value' => $match);
377        $form['size'] = array('#type' => 'hidden', '#value' => $size);
378      }
379      $form['reverse_link'] = array(
380        '#type' => 'checkbox',
381        '#title' => t('Reverse link'),
382        '#default_value' => isset($widget['reverse_link']) ? $widget['reverse_link'] : 0,
383        '#description' => t('If selected, a reverse link back to the referencing node will displayed on the referenced user record.'),
384      );
385      return $form;
386
387    case 'save':
388      return array('autocomplete_match', 'size', 'reverse_link');
389  }
390}
391
392/**
393 * Implementation of hook_widget().
394 *
395 * Attach a single form element to the form. It will be built out and
396 * validated in the callback(s) listed in hook_elements. We build it
397 * out in the callbacks rather than here in hook_widget so it can be
398 * plugged into any module that can provide it with valid
399 * $field information.
400 *
401 * Content module will set the weight, field name and delta values
402 * for each form element. This is a change from earlier CCK versions
403 * where the widget managed its own multiple values.
404 *
405 * If there are multiple values for this field, the content module will
406 * call this function as many times as needed.
407 *
408 * @param $form
409 *   the entire form array, $form['#node'] holds node information
410 * @param $form_state
411 *   the form_state, $form_state['values'][$field['field_name']]
412 *   holds the field's form values.
413 * @param $field
414 *   the field array
415 * @param $items
416 *   array of default values for this field
417 * @param $delta
418 *   the order of this item in the array of subelements (0, 1, 2, etc)
419 *
420 * @return
421 *   the form item for a single element for this field
422 */
423function userreference_widget(&$form, &$form_state, $field, $items, $delta = 0) {
424  switch ($field['widget']['type']) {
425    case 'userreference_select':
426      $element = array(
427        '#type' => 'userreference_select',
428        '#default_value' => $items,
429      );
430      break;
431
432    case 'userreference_buttons':
433      $element = array(
434        '#type' => 'userreference_buttons',
435        '#default_value' => $items,
436      );
437      break;
438
439    case 'userreference_autocomplete':
440      $element = array(
441        '#type' => 'userreference_autocomplete',
442        '#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
443        '#value_callback' => 'userreference_autocomplete_value',
444      );
445      break;
446  }
447  return $element;
448}
449
450/**
451 * Value for a userreference autocomplete element.
452 *
453 * Substitute in the user name for the uid.
454 */
455function userreference_autocomplete_value($element, $edit = FALSE) {
456  $field_key  = $element['#columns'][0];
457  if (!empty($element['#default_value'][$field_key])) {
458    $value = db_result(db_query("SELECT name FROM {users} WHERE uid = '%d'", $element['#default_value'][$field_key]));
459    return array($field_key => $value);
460  }
461  return array($field_key => NULL);
462}
463
464/**
465 * Process an individual element.
466 *
467 * Build the form element. When creating a form using FAPI #process,
468 * note that $element['#value'] is already set.
469 *
470 * The $fields array is in $form['#field_info'][$element['#field_name']].
471 */
472function userreference_select_process($element, $edit, $form_state, $form) {
473  // The userreference_select widget doesn't need to create its own
474  // element, it can wrap around the optionwidgets_select element.
475  // Add a validation step where the value can be unwrapped.
476  $field_key  = $element['#columns'][0];
477  $element[$field_key] = array(
478    '#type' => 'optionwidgets_select',
479    '#default_value' => isset($element['#value']) ? $element['#value'] : '',
480    // The following values were set by the content module and need
481    // to be passed down to the nested element.
482    '#title' => $element['#title'],
483    '#required' => $element['#required'],
484    '#description' => $element['#description'],
485    '#field_name' => $element['#field_name'],
486    '#type_name' => $element['#type_name'],
487    '#delta' => $element['#delta'],
488    '#columns' => $element['#columns'],
489  );
490  if (empty($element[$field_key]['#element_validate'])) {
491    $element[$field_key]['#element_validate'] = array();
492  }
493  array_unshift($element[$field_key]['#element_validate'], 'userreference_optionwidgets_validate');
494  return $element;
495}
496
497/**
498 * Process an individual element.
499 *
500 * Build the form element. When creating a form using FAPI #process,
501 * note that $element['#value'] is already set.
502 *
503 * The $fields array is in $form['#field_info'][$element['#field_name']].
504 */
505function userreference_buttons_process($element, $edit, $form_state, $form) {
506  // The userreference_select widget doesn't need to create its own
507  // element, it can wrap around the optionwidgets_select element.
508  // Add a validation step where the value can be unwrapped.
509  $field_key  = $element['#columns'][0];
510  $element[$field_key] = array(
511    '#type' => 'optionwidgets_buttons',
512    '#default_value' => isset($element['#value']) ? $element['#value'] : '',
513    // The following values were set by the content module and need
514    // to be passed down to the nested element.
515    '#title' => $element['#title'],
516    '#required' => $element['#required'],
517    '#description' => $element['#description'],
518    '#field_name' => $element['#field_name'],
519    '#type_name' => $element['#type_name'],
520    '#delta' => $element['#delta'],
521    '#columns' => $element['#columns'],
522  );
523  if (empty($element[$field_key]['#element_validate'])) {
524    $element[$field_key]['#element_validate'] = array();
525  }
526  array_unshift($element[$field_key]['#element_validate'], 'userreference_optionwidgets_validate');
527  return $element;
528}
529
530/**
531 * Process an individual element.
532 *
533 * Build the form element. When creating a form using FAPI #process,
534 * note that $element['#value'] is already set.
535 *
536 */
537function userreference_autocomplete_process($element, $edit, $form_state, $form) {
538  // The userreference autocomplete widget doesn't need to create its own
539  // element, it can wrap around the text_textfield element and add an autocomplete
540  // path and some extra processing to it.
541  // Add a validation step where the value can be unwrapped.
542  $field_key  = $element['#columns'][0];
543
544  $element[$field_key] = array(
545    '#type' => 'text_textfield',
546    '#default_value' => isset($element['#value']) ? $element['#value'] : '',
547    '#autocomplete_path' => 'userreference/autocomplete/'. $element['#field_name'],
548    // The following values were set by the content module and need
549    // to be passed down to the nested element.
550    '#title' => $element['#title'],
551    '#required' => $element['#required'],
552    '#description' => $element['#description'],
553    '#field_name' => $element['#field_name'],
554    '#type_name' => $element['#type_name'],
555    '#delta' => $element['#delta'],
556    '#columns' => $element['#columns'],
557  );
558  if (empty($element[$field_key]['#element_validate'])) {
559    $element[$field_key]['#element_validate'] = array();
560  }
561  array_unshift($element[$field_key]['#element_validate'], 'userreference_autocomplete_validate');
562
563  // Used so that hook_field('validate') knows where to flag an error.
564  $element['_error_element'] = array(
565    '#type' => 'value',
566    // Wrapping the element around a text_textfield element creates a
567    // nested element, so the final id will look like 'field-name-0-uid-uid'.
568    '#value' => implode('][', array_merge($element['#parents'], array($field_key, $field_key))),
569  );
570  return $element;
571}
572
573/**
574 * Validate a select/buttons element.
575 *
576 * Remove the wrapper layer and set the right element's value.
577 * We don't know exactly where this element is, so we drill down
578 * through the element until we get to our key.
579 *
580 * We use $form_state['values'] instead of $element['#value']
581 * to be sure we have the most accurate value when other modules
582 * like optionwidgets are using #element_validate to alter the value.
583 */
584function userreference_optionwidgets_validate($element, &$form_state) {
585  $field_key  = $element['#columns'][0];
586
587  $value = $form_state['values'];
588  $new_parents = array();
589  foreach ($element['#parents'] as $parent) {
590    $value = $value[$parent];
591    // Use === to be sure we get right results if parent is a zero (delta) value.
592    if ($parent === $field_key) {
593      $element['#parents'] = $new_parents;
594      form_set_value($element, $value, $form_state);
595      break;
596    }
597    $new_parents[] = $parent;
598  }
599}
600
601/**
602 * Validate an autocomplete element.
603 *
604 * Remove the wrapper layer and set the right element's value.
605 * This will move the nested value at 'field-name-0-uid-uid'
606 * back to its original location, 'field-name-0-uid'.
607 */
608function userreference_autocomplete_validate($element, &$form_state) {
609  $field_name = $element['#field_name'];
610  $type_name = $element['#type_name'];
611  $field = content_fields($field_name, $type_name);
612  $field_key = $element['#columns'][0];
613  $value = $element['#value'][$field_key];
614  $uid = NULL;
615  if (!empty($value)) {
616    $reference = _userreference_potential_references($field, $value, 'equals', NULL, 1);
617    if (empty($reference)) {
618      form_error($element[$field_key], t('%name: found no valid user with that name.', array('%name' => t($field['widget']['label']))));
619    }
620    else {
621      $uid = key($reference);
622    }
623  }
624  form_set_value($element, $uid, $form_state);
625}
626
627/**
628 * Implementation of hook_allowed_values().
629 */
630function userreference_allowed_values($field) {
631  $references = _userreference_potential_references($field);
632
633  $options = array();
634  foreach ($references as $key => $value) {
635    $options[$key] = $value['rendered'];
636  }
637
638  return $options;
639}
640
641/**
642 * Fetch an array of all candidate referenced users.
643 *
644 * This info is used in various places (aloowed values, autocomplete results,
645 * input validation...). Some of them only need the uids, others nid + names,
646 * others yet uid + names + rendered row (for display in widgets).
647 * The array we return contains all the potentially needed information, and lets
648 * consumers use the parts they actually need.
649 *
650 * @param $field
651 *   The field description.
652 * @param $string
653 *   Optional string to filter usernames on (used by autocomplete)
654 * @param $match
655 *   Operator to match filtered name against, can be any of:
656 *   'contains', 'equals', 'starts_with'
657 * @param $ids
658 *   Optional user ids to lookup (the $string and $match arguments will be
659 *   ignored).
660 * @param $limit
661 *   If non-zero, limit the size of the result set.
662 *
663 * @return
664 *   An array of valid users in the form:
665 *   array(
666 *     uid => array(
667 *       'title' => The user name,
668 *       'rendered' => The text to display in widgets (can be HTML)
669 *     ),
670 *     ...
671 *   )
672 */
673function _userreference_potential_references($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
674  static $results = array();
675
676  // Create unique id for static cache.
677  $cid = $field['field_name'] .':'. $match .':'. ($string !== '' ? $string : implode('-', $ids)) .':'. $limit;
678  if (!isset($results[$cid])) {
679    $references = FALSE;
680    if (module_exists('views') && !empty($field['advanced_view']) && $field['advanced_view'] != '--') {
681      $references = _userreference_potential_references_views($field, $string, $match, $ids, $limit);
682    }
683    // If the view doesn't exist, we got FALSE, and fallback to the regular 'standard mode'.
684
685    if ($references === FALSE) {
686      $references = _userreference_potential_references_standard($field, $string, $match, $ids, $limit);
687    }
688
689    // Store the results.
690    $results[$cid] = !empty($references) ? $references : array();
691  }
692
693  return $results[$cid];
694}
695
696/**
697 * Helper function for _userreference_potential_references():
698 * case of Views-defined referenceable users.
699 */
700function _userreference_potential_references_views($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
701  $view_name = $field['advanced_view'];
702
703  if ($view = views_get_view($view_name)) {
704    // We add a display, and let it derive from the 'default' display.
705    // TODO: We should let the user pick a display in the fields settings - sort of requires AHAH...
706    $display = $view->add_display('content_references');
707    $view->set_display($display);
708
709    // TODO from merlinofchaos on IRC : arguments using summary view can defeat the style setting.
710    // We might also need to check if there's an argument, and set *its* style_plugin as well.
711    $view->display_handler->set_option('style_plugin', 'content_php_array_autocomplete');
712    $view->display_handler->set_option('row_plugin', 'fields');
713    // Used in content_plugin_style_php_array::render(), to get
714    // the 'field' to be used as title.
715    $view->display_handler->set_option('content_title_field', 'name');
716
717    // Additional options to let content_plugin_display_references::query()
718    // narrow the results.
719    $options = array(
720      'table' => 'users',
721      'field_string' => 'name',
722      'string' => $string,
723      'match' => $match,
724      'field_id' => 'uid',
725      'ids' => $ids,
726    );
727    $view->display_handler->set_option('content_options', $options);
728
729    // TODO : for consistency, a fair amount of what's below
730    // should be moved to content_plugin_display_references
731
732    // Limit result set size.
733    // - Views 3.x uses set_items_per_page(),
734    // - Views 2.x uses set_option('items_per_page').
735    $limit = isset($limit) ? $limit : 0;
736    if (method_exists($view, 'set_items_per_page')) {
737      $view->set_items_per_page($limit);
738    }
739    else {
740      $view->display_handler->set_option('items_per_page', $limit);
741    }
742
743    // Get arguments for the view.
744    if (!empty($field['advanced_view_args'])) {
745      // TODO: Support Tokens using token.module ?
746      $view_args = array_map('trim', explode(',', $field['advanced_view_args']));
747    }
748    else {
749      $view_args = array();
750    }
751
752    // We do need name field, so add it if not present (unlikely, but...)
753    $fields = $view->get_items('field', $display);
754    if (!isset($fields['name'])) {
755      $view->add_item($display, 'field', 'users', 'name');
756    }
757
758    // If not set, make all fields inline and define a separator.
759    $options = $view->display_handler->get_option('row_options');
760    if (empty($options['inline'])) {
761      $options['inline'] = drupal_map_assoc(array_keys($view->get_items('field', $display)));
762    }
763    if (empty($options['separator'])) {
764      $options['separator'] = '-';
765    }
766    $view->display_handler->set_option('row_options', $options);
767
768    // Make sure the query is not cached
769    $view->is_cacheable = FALSE;
770
771    // Get the results.
772    $result = $view->execute_display($display, $view_args);
773  }
774  else {
775    $result = FALSE;
776  }
777
778  return $result;
779}
780
781/**
782 * Helper function for _userreference_potential_references():
783 * referenceable users defined by user role and status
784 */
785function _userreference_potential_references_standard($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
786  $where = array();
787  $args = array();
788  $join = array();
789
790  if ($string !== '') {
791    $like = $GLOBALS["db_type"] == 'pgsql' ? "ILIKE" : "LIKE";
792    $match_clauses = array(
793      'contains' => "$like '%%%s%%'",
794      'equals' => "= '%s'",
795      'starts_with' => "$like '%s%%'",
796    );
797    $where[] = 'u.name '. (isset($match_clauses[$match]) ? $match_clauses[$match] : $match_clauses['contains']);
798    $args[] = $string;
799  }
800  elseif ($ids) {
801    $where[] = 'u.uid IN (' . db_placeholders($ids) . ')';
802    $args = array_merge($args, $ids);
803  }
804  else {
805    $where[] = "u.uid > 0";
806  }
807
808  $roles = array();
809  if (isset($field['referenceable_roles']) && is_array($field['referenceable_roles'])) {
810    // keep only selected checkboxes
811    $roles = array_filter($field['referenceable_roles']);
812    // filter invalid values that seems to get through sometimes ??
813    $roles = array_intersect(array_keys(user_roles(1)), $roles);
814  }
815  if (!empty($roles) && !in_array(DRUPAL_AUTHENTICATED_RID, $roles)) {
816    $where[] = "r.rid IN (". implode($roles, ',') .")";
817    $join[] = 'LEFT JOIN {users_roles} r ON u.uid = r.uid';
818  }
819
820  if (isset($field['referenceable_status']) && is_numeric($field['referenceable_status'])) {
821    $where[] = 'u.status = %d';
822    $args[] = $field['referenceable_status'];
823  }
824
825  $users = array();
826  $where_clause = $where ? 'WHERE ('. implode(') AND (', $where) .')' : '';
827  $result = db_query('SELECT u.name, u.uid FROM {users} u '. implode(' ', $join) ." $where_clause ORDER BY u.name ASC", $args);
828  while ($user = db_fetch_object($result)) {
829    $users[$user->uid] = array(
830      'title' => $user->name,
831      'rendered' => check_plain($user->name),
832    );
833  }
834  return $users;
835}
836
837/**
838 * Menu callback; Retrieve a pipe delimited string of autocomplete suggestions for existing users
839 */
840function userreference_autocomplete($field_name, $string = '') {
841  $fields = content_fields();
842  $field = $fields[$field_name];
843  $match = isset($field['widget']['autocomplete_match']) ? $field['widget']['autocomplete_match'] : 'contains';
844  $matches = array();
845
846  $references = _userreference_potential_references($field, $string, $match, array(), 10);
847  foreach ($references as $id => $row) {
848    // Add a class wrapper for a few required CSS overrides.
849    $matches[$row['title']] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';
850  }
851  drupal_json($matches);
852}
853
854/**
855 * Implementation of hook_user().
856 */
857function userreference_user($type, &$edit, &$account) {
858  switch ($type) {
859    case 'load':
860      // Only add links if we are on the user 'view' page.
861      if (arg(0) != 'user' || arg(2)) {
862        return;
863      }
864      // find CCK userreference field tables
865      // search through them for matching user ids and load those nodes
866      $additions = array();
867      $types = content_types();
868
869      // Find the table and columns to search through, if the same
870      // table comes up in more than one content type, we only need
871      // to search it once.
872      $search_tables = array();
873      foreach ($types as $type_name => $type) {
874        foreach ($type['fields'] as $field) {
875          // Only add tables when reverse link has been selected.
876          if ($field['type'] == 'userreference' && !empty($field['widget']['reverse_link'])) {
877            $db_info = content_database_info($field);
878            $search_tables[$db_info['table']][] = $db_info['columns']['uid']['column'];
879          }
880        }
881      }
882      foreach ($search_tables as $table => $columns) {
883        foreach ($columns as $column) {
884          $ids = db_query(db_rewrite_sql("SELECT DISTINCT(n.nid), n.title, n.type FROM {node} n LEFT JOIN {". $table ."} f ON n.vid = f.vid WHERE f.". $column ."=". $account->uid. " AND n.status = 1"));
885          while ($data = db_fetch_object($ids)) {
886            $additions[$data->type][$data->nid] = $data->title;
887          }
888        }
889      }
890      $account->userreference = $additions;
891      break;
892
893    case 'view':
894      if (!empty($account->userreference)) {
895        $node_types = content_types();
896        $additions = array();
897        $values = array();
898        foreach ($account->userreference as $node_type => $nodes) {
899          foreach ($nodes as $nid => $title) {
900            $values[$node_type][] = l($title, 'node/'. $nid);
901          }
902          if (isset($values[$node_type])) {
903            $additions[] = array(
904              '#type' => 'user_profile_item',
905              '#title' => check_plain($node_types[$node_type]['name']),
906              '#value' => theme('item_list', $values[$node_type]),
907            );
908          }
909        }
910        if ($additions) {
911          $account->content['userreference'] = $additions + array(
912            '#type' => 'user_profile_category',
913            '#attributes' => array('class' => 'user-member'),
914            '#title' => t('Related content'),
915            '#weight' => 10,
916          );
917        }
918      }
919      break;
920  }
921}
922
923/**
924 * FAPI theme for an individual elements.
925 *
926 * The textfield or select is already rendered by the
927 * textfield or select themes and the html output
928 * lives in $element['#children']. Override this theme to
929 * make custom changes to the output.
930 *
931 * $element['#field_name'] contains the field name
932 * $element['#delta]  is the position of this element in the group
933 */
934function theme_userreference_select($element) {
935  return $element['#children'];
936}
937
938function theme_userreference_buttons($element) {
939  return $element['#children'];
940}
941
942function theme_userreference_autocomplete($element) {
943  return $element['#children'];
944}
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.