/[drupal]/contributions/modules/multireference/multireference.module
ViewVC logotype

Contents of /contributions/modules/multireference/multireference.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Mon Mar 31 21:34:44 2008 UTC (19 months, 3 weeks ago) by stevem
Branch: MAIN
CVS Tags: DRUPAL-5--1-1, HEAD
Branch point for: DRUPAL-5
Changes since 1.1: +6 -9 lines
File MIME type: text/x-php
fix autocomplete  bug
1 <?php
2 // $Id: multireference.module,v 1.1 2008/03/31 21:12:52 stevem Exp $
3
4 /**
5 * @file
6 * multireference module
7 *
8 * This CCK module allows you to create a field containing a list
9 * of items comprising 1) a description field, 2) a user or node
10 * reference, and 3) an optional 2nd description field
11 *
12 */
13
14 /*---- Drupal core API ---- */
15
16 /**
17 * Implementation of hook_help
18 */
19 function multireference_help($section = '') {
20 $output = '';
21 switch ($section) {
22 case "admin/help#multireference":
23 $output = '<p>'. t("Allows creation of multiple node or user reference fields with descriptions."). '</p>';
24 break;
25 }
26 return $output;
27 }
28
29 /**
30 * Implementation of hook_menu
31 */
32 function multireference_menu($may_cache) {
33 // register our autocomplete callback
34 $items = array();
35 $items[] = array(
36 'path' => 'multireference/autocomplete_nodereference',
37 'title' => '',
38 'callback' => 'multireference_autocomplete_node',
39 'type' => MENU_CALLBACK,
40 'access' => user_access('access content'),
41 );
42 $items[] = array(
43 'path' => 'multireference/autocomplete_userreference',
44 'title' => '',
45 'callback' => 'multireference_autocomplete_user',
46 'type' => MENU_CALLBACK,
47 'access' => user_access('access content'),
48 );
49 return $items;
50 }
51
52 /**
53 * Implementation of hook_nodeapi
54 */
55 function multireference_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
56 switch ($op) {
57 case 'update' :
58 $sql = "UPDATE {node_field_multireference_data} SET r_text='%s' WHERE r_id=%d AND reference='nodereference';";
59 db_query($sql, $node->title, $node->nid);
60 break;
61
62 case 'delete' :
63 $sql = "UPDATE {node_field_multireference_data} SET r_id=0 WHERE r_id=%d AND reference='nodereference';";
64 db_query($sql, $node->nid);
65 break;
66 }
67 }
68
69
70 /**
71 * Implementation of hook_user
72 */
73 function multireference_user($op, &$edit, &$account, $category = NULL) {
74 switch ($op) {
75 case 'after_update' :
76 $sql = "UPDATE {node_field_multireference_data} SET r_text='%s' WHERE r_id=%d AND reference='userreference';";
77 db_query($sql, $account->name, $account->uid);
78 break;
79
80 case 'delete' :
81 $sql = "UPDATE {node_field_multireference_data} SET r_id=0 WHERE r_id=%d AND reference='userreference';";
82 db_query($sql, $account->uid);
83 break;
84 }
85 }
86
87
88 /*------ CCK field API ------*/
89
90
91 /**
92 * Implementation of hook_field_info().
93 */
94 function multireference_field_info() {
95 return array(
96 'multireference' => array('label' => 'Multi-Reference Field'),
97 );
98 }
99
100 /**
101 * Implementation of hook_field_settings().
102 */
103 function multireference_field_settings($op, $field) {
104
105 $reference = _multireference_filter_reference_type($field['r_type']);
106
107 switch ($op) {
108 case 'form':
109 $form = array();
110
111 // type of reference
112 $options = array(
113 'nodereference' => 'Node',
114 'userreference' => 'User',
115 );
116 $form['r_type'] = array(
117 '#type' => 'radios',
118 '#title' => t('Type of reference'),
119 '#description' => t('This field can hold either node or user references. Please choose one, and configure the appropriate settings below.'),
120 '#options' => $options,
121 '#default_value' => isset($field['r_type']) ? $field['r_type'] : '',
122 '#required' => TRUE,
123 );
124
125 // max number of line items
126 $form['r_num'] = array(
127 '#type' => 'textfield',
128 '#size' => 4,
129 '#title' => t('What is the maximum number of lines that this field should provide?'),
130 '#default_value' => isset($field['r_num']) ? $field['r_num'] : 20,
131 );
132
133 // autocomplete or select list?
134 $options = array(
135 'select' => 'Select list',
136 'autocomplete' => 'Auto-complete field',
137 );
138 $form['r_field_type'] = array(
139 '#type' => 'radios',
140 '#title' => t('Type of form element'),
141 '#options' => $options,
142 '#default_value' => isset($field['r_field_type']) ? $field['r_field_type'] : 'select',
143 '#required' => TRUE,
144 );
145
146 // alternates to select list/autocomplete?
147 $options = array(
148 'nothing' => 'Nothing',
149 'text' => 'Text input box',
150 //'addnode' => 'AddNode form (node references only)',
151 );
152 $form['r_action'] = array(
153 '#type' => 'radios',
154 '#title' => t('Reference options'),
155 '#description' => t('What option do you want available in addition to choosing a reference?'),
156 '#options' => $options,
157 '#default_value' => isset($field['r_action']) ? $field['r_action'] : 'nothing',
158 '#required' => TRUE,
159 );
160
161 // field titles
162 $form['field_titles'] = array(
163 '#type' => 'fieldset',
164 '#title' => t('Field titles'),
165 '#collapsible' => TRUE,
166 '#collapsed' => TRUE,
167 );
168 $form['field_titles']['t_desc'] = array(
169 '#type' => 'textfield',
170 '#title' => t('Description'),
171 '#default_value' => isset($field['t_desc']) ? $field['t_desc'] : '',
172 );
173 $form['field_titles']['t_ref'] = array(
174 '#type' => 'textfield',
175 '#title' => t('Reference'),
176 '#default_value' => isset($field['t_ref']) ? $field['t_ref'] : '',
177 );
178 $form['field_titles']['t_desc2'] = array(
179 '#type' => 'textfield',
180 '#title' => t('Additional description'),
181 '#default_value' => isset($field['t_desc2']) ? $field['t_desc2'] : '',
182 );
183
184 // description
185 $form['description'] = array(
186 '#type' => 'fieldset',
187 '#title' => t('Description settings'),
188 '#collapsible' => TRUE,
189 '#collapsed' => TRUE,
190 );
191 $form['description']['desc_values'] = array(
192 '#type' => 'textarea',
193 '#title' => t('Allowed values for description (leave blank for free-form text entry)'),
194 '#default_value' => isset($field['desc_values']) ? $field['desc_values'] : '',
195 );
196 $options = array(
197 'false' => 'Optional',
198 'true' => 'Required',
199 );
200 $form['description']['desc_required'] = array(
201 '#type' => 'radios',
202 '#title' => t('Description required?'),
203 '#description' => t('Do you want the description to be mandatory?'),
204 '#options' => $options,
205 '#default_value' => isset($field['desc_required']) ? $field['desc_required'] : 'false',
206 '#required' => TRUE,
207 );
208
209 // additional description field?
210 $form['description2'] = array(
211 '#type' => 'fieldset',
212 '#title' => t('Additional description settings'),
213 '#collapsible' => TRUE,
214 '#collapsed' => TRUE,
215 );
216 $form['description2']['desc2_provide'] = array(
217 '#type' => 'checkbox',
218 '#title' => t('Provide a second description field'),
219 '#default_value' => isset($field['desc2_provide']) ? $field['desc2_provide'] : 0,
220 );
221 $form['description2']['desc2_values'] = array(
222 '#type' => 'textarea',
223 '#title' => t('Allowed values for the additional description (leave blank for free-form text entry)'),
224 '#default_value' => isset($field['desc2_values']) ? $field['des2c_values'] : '',
225 );
226 $options = array(
227 'false' => 'Optional',
228 'true' => 'Required',
229 );
230 $form['description2']['desc2_required'] = array(
231 '#type' => 'radios',
232 '#title' => t('Additional description required?'),
233 '#description' => t('Do you want the additional description to be mandatory?'),
234 '#options' => $options,
235 '#default_value' => isset($field['desc2_required']) ? $field['desc2_required'] : 'false',
236 '#required' => TRUE,
237 );
238
239 // node reference settings
240 $form['node_ref'] = array(
241 '#type' => 'fieldset',
242 '#title' => t('Node reference settings'),
243 '#collapsible' => TRUE,
244 '#collapsed' => TRUE,
245 );
246 $subform = nodereference_field_settings($op, $field);
247 foreach ($subform as $key => $array) {
248 $form['node_ref'][$key] = $array;
249 }
250
251 // user reference settings
252 $form['user_ref'] = array(
253 '#type' => 'fieldset',
254 '#title' => t('User reference settings'),
255 '#collapsible' => TRUE,
256 '#collapsed' => TRUE,
257 );
258 $subform = userreference_field_settings($op, $field);
259 foreach ($subform as $key => $array) {
260 $form['user_ref'][$key] = $array;
261 }
262
263 return $form;
264
265 case 'validate' :
266 // select the correct config field to test
267 switch ($field['r_type']) {
268 case 'nodereference' :
269 $required_config = 'referenceable_types';
270 break;
271 case 'userreference' :
272 $required_config = 'referenceable_roles';
273 break;
274 default : // this shouldn't happen ...
275 form_set_error('r_type', t('Please select a reference type.'));
276 return;
277 }
278
279 // make sure the config field has a value
280 $has_values = FALSE;
281 foreach ($field[$required_config] as $key => $val) {
282 if (!empty($val)) {
283 $has_values = TRUE;
284 continue;
285 }
286 }
287 if (!$has_values) {
288 $err_name = substr($field['r_type'], 0, 4);
289 form_set_error('', t("The '$err_name reference settings' section of the form must be filled out."));
290 }
291
292 // no ridiculous r_num values
293 if (!is_numeric($field['r_num']) || $field['r_num'] < 1 || $field['r_num'] > 50) {
294 form_set_error('r_num', t("Invalid entry for maximum # of items (the range is 1 to 50)."));
295 }
296
297 /*
298 // cannot use addnode for userreference
299 if ( $field['r_type'] == 'userreference' && $field['r_action'] == 'addnode' ) {
300 form_set_error( 'r_type', t("You cannot provide addnode functionality for a user reference field.") );
301 }
302 */
303
304 break;
305
306 case 'save':
307 global $form_values;
308 if (!$reference) {
309 // _content_admin_field_submit() doesn't call this op with any of
310 // the form values included in the $field object (on initial creation)
311 $reference = _multireference_filter_reference_type($form_values['r_type']);
312 if (!$reference) {
313 die('Bad reference.');
314 }
315 }
316 $my_columns = array(
317 'r_type',
318 'r_num',
319 'r_action',
320 'r_field_type',
321 'desc_values',
322 'desc_required',
323 'desc2_provide',
324 'desc2_values',
325 'desc2_required',
326 't_desc',
327 't_ref',
328 't_desc2',
329 );
330 eval('$ref_columns = '. $reference .'_field_settings(\'save\', $field);');
331 $all_columns = array_merge($my_columns, $ref_columns);
332 return $all_columns;
333
334 /* Views support */
335 case 'tables':
336 $tables = _multireference_views_field_table($field);
337 return $tables;
338 }
339 }
340
341 /**
342 * Implementation of hook_field().
343 */
344 function multireference_field($op, &$node, $field, &$items, $teaser, $page) {
345 switch ($op) {
346 case 'load':
347 $values = _multireference_load_values($node->nid, $field['field_name']);
348 return array($field['field_name'] => $values);
349
350 case 'update':
351 db_query("DELETE FROM {node_field_multireference_data} WHERE vid = %d and field_name= '%s'", $node->vid, $field['field_name']);
352 // fall through to insert updated values
353
354 case 'insert':
355 $weight = 0;
356 foreach ($items as $delta => $data) {
357 $desc = empty($data['desc']) ? '' : $data['desc'];
358 $desc2 = empty($data['desc2']) ? '' : $data['desc2'];
359 $ref = _multireference_get_reference_info($field, $data['r_data']);
360 if (!empty($data['r_text'])) { // new input from text entry field
361 $ref['id'] = 0;
362 $ref['text'] = $data['r_text'];
363 }
364 if (!empty($ref['text'])) {
365 db_query("INSERT INTO {node_field_multireference_data}
366 SET nid = %d, vid = %d, field_name = '%s', reference = '%s', r_id = %s, r_text = '%s', description = '%s', description2 = '%s', weight = %d",
367 $node->nid, $node->vid, $field['field_name'], $field['r_type'], $ref['id'], $ref['text'], $desc, $desc2, $weight++);
368 }
369 }
370 break;
371
372 case 'delete':
373 db_query("DELETE FROM {node_field_multireference_data} WHERE vid = %d and field_name= '%s'", $node->vid, $field['field_name']);
374 break;
375 }
376 }
377
378 /**
379 * Implementation of hook_field_formatter_info().
380 */
381 function multireference_field_formatter_info() {
382 return array(
383 'default' => array(
384 'label' => 'list',
385 'field types' => array('multireference'),
386 ),
387 'table' => array(
388 'label' => 'table',
389 'field types' => array('multireference'),
390 ),
391 );
392 }
393
394 /**
395 * Implemenation of hook_field_formatter
396 */
397 function multireference_field_formatter($field, $item, $formatter, $node) {
398 static $run_only_once = array();
399 if (!isset($run_only_once[$field['field_name']])) {
400 $run_only_once[$field['field_name']] = TRUE;
401 switch ($formatter) { // being careful for eval()
402 case 'table' :
403 break;
404 default :
405 $formatter = 'default';
406 break;
407 }
408 eval('$output = multireference_display_'. $formatter .'( $node->$field[\'field_name\'], $field );');
409 return $output;
410 }
411 }
412
413
414 /*------ CCK widget API ------*/
415
416
417 /**
418 * Implementation of hook_widget_info
419 */
420 function multireference_widget_info() {
421 return array(
422 'multireference' => array(
423 'label' => 'Multi-reference List',
424 'field types' => array('multireference'),
425 ),
426 );
427 }
428
429 /**
430 * Implementation of hook_widget
431 */
432 function multireference_widget($op, &$node, $field, &$items) {
433 $fieldname = $field['field_name'];
434 $reference = _multireference_filter_reference_type($field['r_type']);
435
436 /*
437 * determine how many items to prepare form elements for
438 */
439 static $num_lines = array();
440 // defaults
441 if (!isset($num_lines[$fieldname])) {
442 $num_lines[$fieldname] = count($items) ? count($items) : 3;
443 }
444 // use the number returned from the form, if extant
445 // (handles creating new elements with javascript)
446 if (isset($_POST[$fieldname])) {
447 $num_lines[$fieldname] = count($_POST[$fieldname]);
448 }
449
450 switch ($op) {
451 case 'form':
452 // cap # of lines at desired maximum
453 if ($num_lines[$fieldname] > $field['r_num']) {
454 $num_lines[$fieldname] = $field['r_num'];
455 }
456
457 $path = drupal_get_path('module', 'multireference');
458 drupal_add_js($path .'/multireference.js');
459 drupal_add_css($path .'/multireference.css');
460
461 // select / text entry for descriptions
462 $desc_options = _multireference_get_desc_options($field['desc_values']);
463 $desc_type = (empty($desc_options)) ? 'textfield' : 'select';
464 $desc2_options = _multireference_get_desc_options($field['desc2_values']);
465 $desc2_type = (empty($desc2_options)) ? 'textfield' : 'select';
466
467 $form = array();
468 $form[$fieldname] = array(
469 '#tree' => true,
470 '#prefix' => '<table><tr><td><a name="multireference_anchor_'. $fieldname .'">'. t($field['widget']['label']) .'</a></td><td></td></tr>',
471 '#suffix' => '</table>',
472 );
473
474 // the 'form' op has to return something (for 'default value') when the
475 // field is being created (and, thus, before r_type is defined).
476 if (!$reference) {
477 $reference = 'nodereference';
478 }
479
480 /*
481 * get reference options
482 */
483 $options = _multireference_get_options($field);
484 if ($reference == 'nodereference') {
485 foreach ($options as $key => $value) {
486 $options[$key] = _nodereference_item($field, $value);
487 }
488 }
489 $options[0] = '';
490 asort($options);
491
492 // add description fields
493 $header = '<td>'. $field['t_desc'] .'</td><td>'. $field['t_ref'] .'<td></td>';
494 if ($field['desc2_provide']) {
495 $header .= '<td>'. $field['t_desc2'] .'</td>';
496 }
497 $form[$fieldname]['header'] = array(
498 '#prefix' => '<tr>',
499 '#suffix' => '</tr>',
500 '#value' => $header,
501 );
502
503 for ($tbl_i = 0; $tbl_i < $num_lines[$fieldname]; $tbl_i++) {
504 $form[$fieldname]["item_$tbl_i"] = array(
505 '#tree' => true,
506 '#prefix' => '<tr class="multireference" id="'. $fieldname .'_'. $tbl_i .'">',
507 '#suffix' => '</tr>',
508 );
509
510 /*
511 * description
512 */
513 $form[$fieldname]["item_$tbl_i"]['desc'] = array(
514 '#type' => $desc_type,
515 '#title' => '',
516 '#prefix' => '<td>',
517 '#suffix' => '</td>',
518 );
519 // select
520 if ($desc_type == 'select') {
521 $form[$fieldname]["item_$tbl_i"]['desc']['#options'] = $desc_options;
522 $form[$fieldname]["item_$tbl_i"]['desc']['#default_value'] = isset($items[$tbl_i]['desc']) ? $items[$tbl_i]['desc'] : '';
523 // textfield
524 }
525 else {
526 $form[$fieldname]["item_$tbl_i"]['desc']['#size'] = 10;
527 $form[$fieldname]["item_$tbl_i"]['desc']['#default_value'] = isset($items[$tbl_i]['desc']) ? $items[$tbl_i]['desc'] : '';
528 }
529
530 /*
531 * reference
532 */
533 $default_value['id'] = isset($items[$tbl_i]['r_id']) ? $items[$tbl_i]['r_id'] : 0;
534 $default_value['text'] = isset($items[$tbl_i]['r_text']) ? $items[$tbl_i]['r_text'] : '';
535
536 $form[$fieldname]["item_$tbl_i"]['r_data'] = array(
537 '#title' => '',
538 '#prefix' => '<td>',
539 '#suffix' => '</td>',
540 );
541
542 // select
543 if ($field['r_field_type'] == 'select') {
544 $form[$fieldname]["item_$tbl_i"]['r_data']['#type'] = 'select';
545 $form[$fieldname]["item_$tbl_i"]['r_data']['#options'] = $options;
546 $form[$fieldname]["item_$tbl_i"]['r_data']['#default_value'] = $default_value['id'];
547
548 // alternates to select
549 // TODO: creating a target via addnode or something similar
550 if ($field['r_action'] == 'text') {
551 $form[$fieldname]["item_$tbl_i"]['r_data']['#suffix'] = '';
552 $form[$fieldname]["item_$tbl_i"]['r_data']['#description'] = t('Choose from this list or enter some text below.');
553 $form[$fieldname]["item_$tbl_i"]['r_text'] = array(
554 '#type' => 'textfield',
555 '#size' => 10,
556 '#title' => '',
557 '#suffix' => '</td>',
558 '#default_value' => $default_value['id'] ? '' : $default_value['text'],
559 );
560 }
561
562 // autocomplete
563 }
564 else {
565 $form[$fieldname]["item_$tbl_i"]['r_data']['#type'] = 'textfield';
566 $form[$fieldname]["item_$tbl_i"]['r_data']['#autocomplete_path'] = '/multireference/autocomplete_'. $field['r_type'] .'/'. $fieldname;
567 $form[$fieldname]["item_$tbl_i"]['r_data']['#default_value'] = $default_value['text'];
568 }
569
570 /*
571 * additional description
572 */
573 if ($field['desc2_provide']) {
574 $form[$fieldname]["item_$tbl_i"]['desc2'] = array(
575 '#type' => $desc2_type,
576 '#title' => '',
577 '#prefix' => '<td>',
578 '#suffix' => '</td>',
579 );
580 // select
581 if ($desc2_type == 'select') {
582 $form[$fieldname]["item_$tbl_i"]['desc2']['#options'] = $desc2_options;
583 $form[$fieldname]["item_$tbl_i"]['desc2']['#default_value'] = isset($items[$tbl_i]['desc2']) ? $items[$tbl_i]['desc2'] : '';
584 // textfield
585 }
586 else {
587 $form[$fieldname]["item_$tbl_i"]['desc2']['#size'] = 10;
588 $form[$fieldname]["item_$tbl_i"]['desc2']['#default_value'] = isset($items[$tbl_i]['desc2']) ? $items[$tbl_i]['desc2'] : '';
589 }
590 }
591 }
592
593 // JS UI element
594 // TODO: client-side validation of max no. of items
595 $form[$fieldname]['item_add'] = array(
596 '#value' => '<tr><td><a href="#multireference_anchor_'. $fieldname .'" class="multireference_add_fields" next_item="'. $tbl_i .'" field_name="'. $fieldname .'">[+] add another field</a></td></tr>',
597 );
598
599 return $form;
600
601 case 'validate' :
602 // test # of lines
603 $num = $num_lines[$field['field_name']];
604 if ($num > $field['r_num']) {
605 form_set_error('', t('The '. t($field['widget']['label']) .' field can hold a maximum of '. $field['r_num'] .' items.'));
606 }
607
608 $label = $field['widget']['label'];
609 foreach ($items as $key => $data) {
610 // are the description fields required?
611 if ($field['desc_required'] == 'true' && !empty($data['r_data']) && empty($data['desc'])) {
612 form_set_error('', t("The first description is required for items in the $label field"));
613 break;
614 }
615 if ($field['desc2_required'] == 'true' && !empty($data['r_data']) && empty($data['desc2'])) {
616 form_set_error('', t("The second description is required for items in the $label field."));
617 break;
618 }
619
620 // no all-numeric text fields
621 if (isset($data['r_text']) && is_numeric($data['r_text'])) {
622 form_set_error('', t("All-numeric values are not allowed in the $label text entry fields."));
623 }
624 if ($field['r_field_type'] == 'autocomplete' && is_numeric($data['r_data'])) {
625 form_set_error('', t("All-numeric values are not allowed in the $label reference field."));
626 }
627 }
628 break;
629 }
630 }
631
632
633 /*---- Theming functions ----*/
634
635 /**
636 * Theme function: prepares data and calls defaut line formatter
637 */
638 function multireference_display_default(&$node_field, &$field) {
639 $item_i = 0;
640 $output = '';
641 foreach ($node_field as $item) {
642 $desc = check_plain($item['desc']);
643 $desc = !empty($desc) ? $desc. ': ' : '';
644 $value = _multireference_get_link($field, $item['r_id'], $item['r_text']);
645 $desc2 = '';
646 if ($field['desc2_provide'] && $item['desc2']) {
647 $desc2 = check_plain($item['desc2']);
648 $desc2 = !empty($desc2) ? $desc2 : '';
649 }
650 if (!empty($value)) {
651 $output .= theme('multireference_default_item', $desc, $value, $desc2);
652 }
653 }
654 return $output;
655 }
656
657
658 /**
659 * Theme function: renders each line in a <div>
660 */
661 function theme_multireference_default_item($desc, $value, $desc2) {
662 return "<div>$desc $value $desc2</div>\n";
663 }
664
665
666 /**
667 * Theme function: prepares data and calls table row formatter
668 */
669 function multireference_display_table(&$node_field, &$field) {
670 // header
671 $header[] = $field['t_desc'];
672 $header[] = $field['t_ref'];
673 if ($field['desc2_provide']) {
674 $header[] = $field['t_desc2'];
675 }
676
677 // items
678 $reference = _multireference_filter_reference_type($field['r_type']);
679 foreach ($node_field as $item) {
680 $row = array();
681 $desc = check_plain($item['desc']);
682 $value = _multireference_get_link($field, $item['r_id'], $item['r_text']);
683 $desc2 = ($field['desc2_provide']) ? check_plain($item['desc2']) : ' ';
684 if ($value) {
685 $row = array($desc, $value);
686 if ($field['desc2_provide']) {
687 $row[] = $desc2;
688 }
689 $data[] = $row;
690 }
691 }
692
693 return theme_multireference_theme_table($header, $data);
694 }
695
696 /**
697 * Theme function: returns tabular display of field
698 */
699 function theme_multireference_theme_table($header, $data) {
700 return theme_table($header, $data);
701 }
702
703
704 /*---- Views functions ----*/
705
706
707 /**
708 * Returns views field information for hook_field_settings
709 */
710 function _multireference_views_field_table($field) {
711 $fieldname = $field['field_name'];
712 $fieldtype = $field['type'];
713 $reference = _multireference_filter_reference_type($field['r_type']);
714
715 $options = array(
716 '#type' => 'select',
717 '#options' => array(
718 'default' => t('Default display'),
719 'table' => t('Table display'),
720 ),
721 );
722
723 $filters = array(
724 'description' => array(
725 'name' => "Multireference: description ($fieldname)",
726 'help' => "Filter on the descriptions of items in the $fieldname field.",
727 'field' => $fieldname,
728 'operator' => array('contains' => 'Contains'),
729 'handler' => 'multireference_views_filter_handler_description',
730 ),
731 'reference' => array(
732 'name' => "Multireference: $reference ($fieldname)",
733 'help' => "Filter on the references in the $fieldname field.",
734 'field' => $fieldname,
735 'operator' => array('contains' => 'Contains'),
736 'handler' => 'multireference_views_filter_handler_reference',
737 ),
738 );
739
740 $tables[$fieldname] = array(
741 'name' => 'node_field_multireference_data',
742 'provider' => 'multireference',
743 'join' => array(
744 'left' => array('table' => 'node', 'field' => 'nid'),
745 'right' => array('field' => 'nid'),
746 'extra' => array('field_name' => $fieldname),
747 ),
748 'fields' => array(
749 $fieldname => array(
750 'name' => "Multireference ($fieldname)",
751 'help' => t('Multireference field'),
752 'handler' => 'multireference_views_field_handler',
753 'notafield' => TRUE,
754 'option' => $options,
755 ),
756 ),
757 'filters' => $filters,
758 );
759
760 return $tables;
761 }
762
763 /**
764 * Display field in views
765 */
766 function multireference_views_field_handler($fieldinfo, $fielddata, $value, $data) {
767 $fieldname = $fielddata['field'];
768 $field = content_fields($fieldname);
769 $contents = _multireference_load_values($data->nid, $fieldname);
770
771 switch ($fielddata['options']) {
772 case 'table' :
773 $theme_function = 'table';
774 break;
775 default :
776 $theme_function = 'default';
777 break;
778 }
779
780 eval('$return = multireference_display_'. $theme_function .'( $contents, $field );');
781 return $return;
782 }
783
784 /**
785 * Filter on description text
786 */
787 function multireference_views_filter_handler_description($op, $filter, $filterinfo, &$query) {
788 $value = trim($filter['value']);
789 if (!$value) {
790 return;
791 }
792 else {
793 $value = db_escape_string($value);
794 }
795
796 list($table, $field) = split('\.', $filter['field']);
797
798 switch ($filter['operator']) {
799 case 'contains' :
800 $clause = "( UPPER($table.description) LIKE UPPER('%$value%') OR UPPER($table.description2) LIKE UPPER('%$value%') )";
801 break;
802 }
803
804 $query->ensure_table($table);
805 $query->add_where($clause);
806 $query->set_distinct();
807 }
808
809 /**
810 * Filter on reference text
811 */
812 function multireference_views_filter_handler_reference($op, $filter, $filterinfo, &$query) {
813 $value = trim($filter['value']);
814 if (!$value) {
815 return;
816 }
817 else {
818 $value = db_escape_string($value);
819 }
820
821 list($table, $field) = split('\.', $filter['field']);
822 $field = content_fields($table);
823
824 switch ($field['r_type']) {
825 case 'nodereference' :
826 $join_table = 'node';
827 $join_field = 'title';
828 $join_id = 'nid';
829 break;
830 case 'userreference' :
831 $join_table = 'users';
832 $join_field = 'name';
833 $join_id = 'uid';
834 break;
835 }
836
837 switch ($filter['operator']) {
838 case 'contains' :
839 $clause = "( ($table.r_id IN (SELECT $join_id FROM $join_table WHERE UPPER($join_table.$join_field) LIKE UPPER('%%%$value%%'))) OR UPPER($table.r_text) LIKE UPPER('%%%$value%%') )";
840 break;
841 }
842
843 $query->set_distinct();
844 $query->ensure_table($table);
845 $query->add_where($clause);
846 }
847
848
849 /*---- utility functions ---- */
850
851
852 /**
853 * Load values from database
854 */
855 function _multireference_load_values($nid = 0, $fieldname = '') {
856 $values = array();
857 if ($nid && $fieldname) {
858 $sql = "SELECT r_id, r_text, description, description2, weight FROM {node_field_multireference_data} WHERE nid=%d AND field_name='%s' ORDER BY weight";
859 $result = db_query($sql, $nid, $fieldname);
860 $values = array();
861 while ($data = db_fetch_object($result)) {
862 $values[] = array(
863 'r_id' => $data->r_id,
864 'r_text' => $data->r_text,
865 'desc' => $data->description,
866 'desc2' => $data->description2,
867 );
868 }
869 }
870 return $values;
871 }
872
873
874 /**
875 * filter allowed reference types
876 * (being extra careful because these are eval()-ed)
877 */
878 function _multireference_filter_reference_type($type = NULL) {
879 $allowed_values = array('nodereference', 'userreference');
880 if (!in_array($type, $allowed_values)) {
881 $type = FALSE;
882 }
883 return $type;
884 }
885
886
887 /**
888 * determines numeric and text info for a given reference
889 */
890 function _multireference_get_reference_info(&$field, $ref_data) {
891 $ref_type = _multireference_filter_reference_type($field['r_type']);
892 if (!$ref_type || !$ref_data) {
893 return array('id' => 0, 'text' => '');
894 }
895
896 static $return = array();
897 $index = $ref_type . $ref_data;
898
899 if (!isset($return["$index"])) {
900 $return[$index] = array();
901 $id = is_numeric($ref_data) ? (int) $ref_data : 0;
902 $constrain = _multireference_get_reference_constraint($field);
903
904 switch ($ref_type) {
905 case 'nodereference' :
906 if ($id > 0) {
907 $text = db_result(db_query("SELECT title FROM {node} WHERE nid = %d $constrain", $id));
908 }
909 elseif (!empty($ref_data)) {
910 $text = $ref_data;
911 $id = db_result(db_query("SELECT nid FROM {node} WHERE title = '%s' $constrain", $ref_data));
912 }
913 break;
914
915 case 'userreference' :
916 if ($id > 0) {
917 $text = db_result(db_query("SELECT u.name FROM {users} u, {users_roles} r WHERE u.uid = %d $constrain", $id));
918 }
919 elseif (!empty($ref_data)) {
920 $text = $ref_data;
921 $id = db_result(db_query("SELECT u.uid FROM {users} u, {users_roles} r WHERE name = '%s' $constrain", $ref_data));
922 }
923 break;
924 }
925 $return[$index]['id'] = !empty($id) ? $id : 0;
926 $return[$index]['text'] = !empty($text) ? $text : '';
927 }
928 return $return[$index];
929 }
930
931
932 /**
933 * Returns link or text for reference
934 */
935 function _multireference_get_link(&$field, $r_id = 0, $r_text = FALSE) {
936 $r_type = _multireference_filter_reference_type($field['r_type']);
937 if (!$r_type || !$r_text) {
938 return FALSE;
939 }
940
941 // determine text and path for reference
942 $path = '';
943 $r_id = (int) $r_id;
944 if ($r_id > 0) {
945 if ($r_type == 'nodereference') {
946 $path = drupal_get_path_alias('node/'. $r_id);
947 }
948 elseif ($r_type == 'userreference') {
949 $path = 'user/'. $r_id;
950 }
951 }
952
953 if ($path) {
954 return l($r_text , $path);
955 }
956 else {
957 return check_plain($r_text);
958 }
959 }
960
961
962 /**
963 * generate a select list for descriptions
964 */
965 function _multireference_get_desc_options($values) {
966 $options = array();
967 if (!empty($values)) {
968 $desc_values = split("\n", $values);
969 $options[] = t('--select--');
970 foreach ($desc_values as $value) {
971 $value = trim($value);
972 $options[$value] = $value;
973 }
974 }
975 return $options;
976 }
977
978
979 /**
980 * Handle autocomplete form elements: node references
981 */
982 function multireference_autocomplete_node($fieldname = '', $string = '') {
983 // only bother when we have some actual data
984 if (strlen($string) < 2 || is_numeric($string) || !$fieldname) {
985 return;
986 }
987 $field = content_fields($fieldname);
988 $matches = array();
989 $constrain = _multireference_get_reference_constraint($field);
990 $sql = "SELECT nid, title FROM {node} WHERE LOWER(title) LIKE LOWER('%s%%') $constrain";
991 $result = db_query_range($sql, $string, 0, 10);
992 while ($node = db_fetch_object($result)) {
993 $matches[$node->title] = $node->title;
994 }
995 print drupal_to_js($matches);
996 exit();
997 }
998
999
1000 /**
1001 * Handle autocomplete form elements: user references
1002 */
1003 function multireference_autocomplete_user($fieldname = '', $string = '') {
1004 // only bother when we have some actual data
1005 if (strlen($string) < 2 || is_numeric($string) || !$fieldname) {
1006 return;
1007 }
1008 $field = content_fields($fieldname);
1009 $matches = array();
1010 $constrain = _multireference_get_reference_constraint($field);
1011 $sql = "SELECT u.uid, u.name FROM {users} u, {users_roles} r WHERE LOWER(u.name) LIKE LOWER('%s%%') $constrain";
1012 $result = db_query_range($sql, $string, 0, 10);
1013 while ($user = db_fetch_object($result)) {
1014 $matches[$user->name] = $user->name;
1015 }
1016 print drupal_to_js($matches);
1017 exit();
1018 }
1019
1020
1021 /**
1022 * return unprocessed array of options from one of the reference modules
1023 * return values are cached for performance
1024 */
1025 function _multireference_get_options(&$field) {
1026 static $return = array();
1027 $reference = _multireference_filter_reference_type($field['r_type']);
1028 if (!$reference) {
1029 return array();
1030 }
1031
1032 if (!isset($return[$field['field_name']])) {
1033 if ($reference == 'nodereference') {
1034 include_once(drupal_get_path('module', 'content') .'/nodereference.module');
1035 $options = _nodereference_potential_references($field, true);
1036 }
1037 elseif ($reference == 'userreference') {
1038 include_once(drupal_get_path('module', 'content') .'/userreference.module');
1039 $options = _userreference_potential_references($field);
1040 }
1041 $return[$field['field_name']] = $options;
1042 }
1043
1044 return $return[$field['field_name']];
1045 }
1046
1047
1048 /**
1049 * determine the node type or user role constraints on results
1050 * return values are cached for performance
1051 */
1052 function _multireference_get_reference_constraint(&$field) {
1053 static $constraints = array();
1054 if (!isset($constraints[$field['field_name']])) {
1055 if ($field['r_type'] == 'nodereference') {
1056 $options = $field['referenceable_types'];
1057 foreach ($options as $key => $value) {
1058 if (!empty($value)) {
1059 $types .= $conj ."'$key'";
1060 $conj = ',';
1061 }
1062 }
1063 $constraints[$field['field_name']] = empty($types) ? '' : " AND type IN ($types) ";
1064 }
1065 else {
1066 $options = $field['referenceable_roles'];
1067 foreach ($options as $key => $value) {
1068 if (!empty($value)) {
1069 if ($key == 2) { // authenticated user == in users table, so no constraint
1070 $types = array();
1071 break;
1072 }
1073 $types .= $conj . $key;
1074 $conj = ',';
1075 }
1076 }
1077 $constraints[$field['field_name']] = empty($types) ? '' : " AND r.rid IN ($types) AND r.uid=u.uid ";
1078 }
1079 }
1080 return $constraints[$field['field_name']];
1081 }

  ViewVC Help
Powered by ViewVC 1.1.2