/[drupal]/contributions/modules/civinode/civinode_cck.module
ViewVC logotype

Contents of /contributions/modules/civinode/civinode_cck.module

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


Revision 1.2 - (show annotations) (download) (as text)
Mon Jun 11 05:36:46 2007 UTC (2 years, 5 months ago) by torenware
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +195 -36 lines
File MIME type: text/x-php
Test version of civinode cck with working multiple support + theming
1 <?php
2 /**
3 * New CiviNode Framework for CCK Support.
4 *
5 * Much thanks to dopry and other CCK documenters, since this version
6 * is being done from scratch the better to use the newest bestest APIs
7 *
8 */
9
10 function civinode_cck_menu($can_cache) {
11 $items = array();
12 if (!$can_cache) {
13 _civinode_cck_initialize();
14 }
15 else {
16
17 return $items;
18 }
19 }
20
21
22
23 function _civinode_cck_initialize() {
24 static $initialized, $is_crm_init;
25 if ($initialized)
26 return $is_crm_init;
27 if (!module_exists('civinode'))
28 return false;
29 if (!$initialized and module_exists('views')) {
30 require_once drupal_get_path('module', 'civinode') . '/civinode_views.inc';
31 }
32 $initialized = TRUE;
33 $is_crm_init = civinode_check_init();
34 return $is_crm_init;
35 }
36
37 //TODO more types
38 function _civinode_cck_supported_types() {
39 return array('' => t('-- select data type --'),
40 'contact' => t('CiviCRM Contact'),
41 'group' => t('CiviCRM Group'));
42 }
43
44 /**
45 * Implementation of hook_field_info().
46 *
47 * @return array ('fieldtype' => array('label' => 'example'))
48 * the only key for the fieldtype array is label.
49 */
50 function civinode_cck_field_info() {
51 return array(
52 //'civicrm_contact_field' => array('label' => t('CiviCRM Contact Field')),
53 //'civicrm_contact_fieldgroup' => array('label' => t('CiviCRM Field Group')),
54 'civicrm_contact' => array('label' => t('CiviCRM Contact')),
55 'civicrm_group' => array('label' => t('CiviCRM Group')),
56 );
57 }
58
59
60 /**
61 * Implementation of hook_field_settings().
62 * @param op
63 * one of form, filters, validate, save, database columns
64 * @param field
65 * the field we are working on
66 */
67 function civinode_cck_field_settings($op, $field) {
68 _civinode_cck_initialize();
69 $field_type = $field['type'];
70 switch ($op) {
71 // This will be included on the add field form and
72 // will be shared across all instances of this field.
73 case 'form':
74 $form = array();
75
76 if ($field_type == 'civicrm_contact' or
77 $field_type == 'civicrm_group') {
78 $default_group = $field['default_group_id'];
79
80 $form['default_group_id'] =
81 civinode_group_selector(t('Default CiviCRM Group'),
82 t('Default CiviCRM Group To Draw Contacts From'));
83 $form['default_group_id']['#default_value'] =
84 $field['default_group_id'];
85 }
86
87 if ($field_type == 'civicrm_contact') {
88 $form['default_profile_id'] =
89 civinode_profile_selector(t('CiviCRM Profile'),
90 t('CiviCRM Profile For Displaying Contacts'));
91 $form['default_profile_id']['#default_value'] =
92 $field['default_profile_id'];
93 }
94
95 //This will display our supported types. Contacts
96 //have subtypes here (a crm field group, a contact ref, a contact
97 //rendered as a profile
98 /**
99 $form['civicrm_type'] = array(
100 '#type' => 'select',
101 '#title' => t('Kind of CiviCRM Data'),
102 //To add
103 '#default_value' => $field['settings']['civicrm_type'],
104 );
105 **/
106
107
108 return $form;
109
110 // this will be called when the field settings form is being validated,
111 // before the widget settings form is displayed.
112 case 'validate':
113 //unless we use autocomplete for groups, we will not need this
114 break;
115
116 // these are the key values to save from the field settings form.
117 // They will be used in the form's submit handler
118 case 'save':
119 return array('default_group_id', 'default_profile_id');
120
121 // database columns op return the db structure required to store this field.
122 // *cck has it's own little DDL. They're simple string replacements in an SQL query.
123 case 'database columns':
124 $columns = array(
125 /* 'description' => array(
126 'type' => 'text',
127 'not null' => TRUE,
128 'default' => "''"
129 ),
130 'description_format' => array(
131 'type' => 'int',
132 'not null' => TRUE,
133 'default' => 0
134 ),
135 */ 'object_id' => array(
136 'type' => 'int',
137 'not null' => TRUE,
138 'default' => 0, 'sortable' => FALSE
139 ),
140 //This is related to the entity_table field
141 //used in various CiviCRM tables (contact, group, etc.)
142 'entity_type' => array(
143 'type' => 'varchar',
144 'length' => 50,
145 'not null' => TRUE,
146 'default' => "'civicrm_contact'",
147 'sortable' => TRUE
148 ),
149 //Some data types have object fields, contacts
150 //in particular.
151 'entity_subfield' => array(
152 'type' => 'varchar',
153 'length' => 120,
154 'default' => "'display_name'"
155 ),
156 );
157 return $columns;
158
159 case 'callbacks'://pairs up with cck_address_field::view
160 //return array(
161 // 'view' => CONTENT_CALLBACK_CUSTOM,
162 break;
163
164 //Views module support
165 case 'tables':
166 //$db_info = content_database_info($field);
167 $tables = civinode_views_field_item_table($field);
168 return $tables;
169
170 case 'tables_default':
171 $tables = content_views_field_tables($field);
172 // whatever additions / modifications needed on the default definitions
173 return $tables;
174
175 case 'arguments':
176 break;
177
178 case 'filters':
179 break;
180 }
181 }
182
183 /**
184 * Implementation of hook_field().
185 * @param op
186 * the operation
187 * @param node
188 * the node we're working with.
189 * @param field
190 * the field we're working on with its settings.
191 * @param items
192 * the data for this field
193 * @param teaser
194 * are we a tease?
195 * @param page
196 * is the spotlight on us?
197 */
198 function civinode_cck_field($op, $node, $field, &$items) {
199 $fieldname = $field['field_name'];
200 switch ($op) {
201 // content.module has already loaded the data from our 'database columns'
202 // for us in itemd. if we need or override the data we have in items
203 // (an nid or fid, or some reference) we do it here.
204 // @return array('fieldname' => array('key' => 'value'))
205 case 'load':
206 //this is where we interact with CiviCRM for data.
207 //error_log('grab data for field ' . $fieldname);
208 break;
209
210 // This is where we define a default view these days. If you wish to shortcut
211 // the formatter system you'd do it here. Formatters are a very useful power
212 // output mechanism. I suggest you use it. This hook may be deprecated in the
213 // future.
214 case 'view':
215 foreach ($items as $delta => $item) {
216 $object_id = $item['object_id'];
217 switch ($field['type']) {
218 case 'civicrm_contact':
219 $profile = civinode_get_default_profile_id(0);
220 $output = theme('crm_profile_cid', $profile, $object_id);
221 $items[$delta]['view'] = $output;//cck_address_format($field, $item, 'default', $node);
222 break;
223 case 'civicrm_group':
224 $items[$delta]['view'] = "Group ID {$object_id}";
225 break;
226 }
227
228 }
229 return theme('field', $node, $field, $items, $teaser, $page);
230
231 // Validate the data we recieved from our widgets.
232 case 'validate':
233 /**
234 if ($field['global_settings']['imagerequired']) {
235 foreach ($items as $delta => $item) {
236 if (!isset($item['imageurl'])) {
237 // we'll need to construct some way to get this fieldname
238 $err_field = $field['field_name'].']['.$delta.']['. $field['widget_settings']['imageurl_fieldname'];
239 $err_msg = t('The') .' '. $field['widget_settings']['imageurl_fieldtitle'] .' '. t('is required');
240 form_set_error($err_field, $err_msg);
241 }
242 }
243 }
244 **/
245 break;
246
247 // we're submitting this node. This isn't a preview.... Do whatcha gotta do.
248 case 'submit':
249 //write to our magic caches to get stuff written back
250 break;
251
252 // Here you get a chance to save data before content.module puts data in your
253 // 'database columns'. You could create a node and pass an nid back, save a file,
254 // query an external service and overwrite node_data['key'] with a foreign key value,
255 // write data to your own database table and return its key...
256 case 'insert':
257 //write a whole CiviCRM object here.
258 break;
259
260 // Here again you get to alter the data coming from the widget before it gets to the
261 // content.module on update..
262 case 'update':
263 //write a whole CiviCRM object here.
264 break;
265
266 // You get this before content.module has a chance to delete, so you can stop
267 // the process if there are any problems.
268 case 'delete':
269 break;
270 }
271 return $output;
272 }
273
274
275 /**
276 * Implementation of hook_widget_info().
277 * @return array (
278 * 'widgettype' => array(
279 * 'label' => 'string',
280 * 'field types' => array('fieldtype', ...)
281 * )
282 * )
283 */
284 function civinode_cck_widget_info() {
285 return array(
286 'civicrm_contact_frame' => array(
287 'label' => 'CiviCRM Contact Field Group',
288 'field types' => array('civicrm_fld_group'),
289 ),
290 'civinode_cck_contact' =>
291 array('label' => t('Contact Autocompletor'),
292 'field types' => array('civicrm_contact'),),
293 'civinode_cck_contact_select' =>
294 array('label' => t('Contact Selector (10 or less contacts)'),
295 'field types' => array('civicrm_contact')),
296 'civinode_cck_group'=>
297 array('label' => t('Group Selector'),
298 'field types' => array('civicrm_group'),),
299 );
300 }
301
302 /**
303 * Implementation of hook_widget_settings().
304 */
305 function civinode_cck_widget_settings($op, $widget) {
306 switch ($op) {
307 // settings form to be displayed during field creation.
308 case 'form':
309 /**
310 * what is this exactly?
311 *
312
313 $form['crm_cck_datatype'] = array (
314 '#type' => 'hidden',
315 '#value' => 'imageurl',
316 );
317 $form['imageurl_fieldtitle'] = array (
318 '#type' => 'hidden',
319 '#value' => 'Image Url',
320 );
321 **/
322 $form = array();
323 return $form;
324
325 // settings form validation.
326 case 'validate':
327 break;
328
329 // form keys to save for settings form.
330 case 'save':
331 break; //don't know about next line
332 //return array('imageurl_fieldname', 'imageurl_fieldtitle');
333 }
334 }
335
336
337 /**
338 * Implementation of hook_widget().
339 */
340 function civinode_cck_widget($op, $node, $field, &$items) {
341 $fieldname = $field['field_name'];
342 // $output = "$op $fieldname:\n";
343 // ob_start();
344 // print_r($items);
345 // $output .= ob_get_clean();
346 // error_log($output);
347 switch ($field['type']) {
348 case 'civicrm_contact':
349 $data_type = 'contact';
350 break;
351 case 'civicrm_group':
352 $data_type = 'group';
353 break;
354 default:
355 $data_type = 'unsupported';
356 break;
357 }
358
359 switch ($op) {
360 case 'submit':
361 break;
362 case 'load':
363 break;
364 case 'form':
365 $form = array();
366
367 // Create our form and set #tree == true so the $item structure will be maintained
368 // for later usage in the process form values op.
369 if ($field['multiple']) {
370 $form[$fieldname] = array(
371 '#type' => 'fieldset',
372 //'#title' => t($field['widget']['label']),
373 '#weight' => $field['widget']['weight'],
374 '#collapsible' => TRUE,
375 '#collapsed' => FALSE,
376 '#description' => $field['widget']['description'],
377 '#tree' => TRUE,
378 );
379 }
380 else {
381 $form[$fieldname] = array('#tree' => TRUE);
382 }
383
384 // Iterate through field values.
385 foreach($items as $delta => $item) {
386 //$entity_type = $item['entity_type'];
387 $form[$fieldname][$delta] = _civinode_cck_widget_manual_item_form($data_type, $field, $delta, $item, $delta);
388 }
389 if ($field['multiple']) {
390 //we want to start from 0, so that
391 //we know when to add a label
392 if (!isset($delta))
393 $delta = -1;
394 $form[$fieldname][$delta+1] = _civinode_cck_widget_manual_item_form($data_type, $field, $delta+1);
395 $form[$fieldname][$delta+2] = _civinode_cck_widget_manual_item_form($data_type, $field, $delta+2);
396 }
397 elseif (count($items) == 0) {
398 $form[$fieldname][0] = _civinode_cck_widget_manual_item_form($data_type, $field, 0, $item);
399 }
400 return $form;
401
402 case 'prepare form values':
403 return;
404
405 case 'validate':
406 return;
407
408 case 'submit':
409 return;
410
411 case 'process form values':
412 $fieldname = $field['field_name'];
413 foreach ($items as $delta => $item) {
414 // $errstr = "widget:pfv($delta) \n";
415 // ob_start();
416 // print_r($item);
417 // $errstr .= ob_get_clean();
418 // error_log($errstr);
419 //unpack dojo data
420 if (!is_array($item)) {
421 $items[$delta] = array();
422 $items[$delta]['entity_type'] = $field['type'];
423 $items[$delta]['object_id'] = $item;
424 }
425 else if (is_array($item) and isset($item['cbox']) and $item['cbox']['key']) {
426 $object_id = $item['cbox']['key'];
427 $items[$delta]['object_id'] = $object_id;
428 $items[$delta]['entity_type'] = 'contact';
429 unset($items[$delta]['cbox']);
430 }
431 else { //if ($delta > 0) {
432 //chuck out empty items
433 unset($items[$delta]);
434 }
435 }
436 break;
437
438 return;
439 }
440 }
441
442
443 /**
444 * Implementation of hook_field_formatter_info().
445 */
446 function civinode_cck_field_formatter_info() {
447 $formatters = array(
448 'default' => array(
449 'label' => t('Default'),
450 'field types' => array('civicrm_contact', 'civicrm_group'),
451 ),
452 'link' => array(
453 'label' => t('Link'),
454 'field types' => array('civicrm_contact'),
455 ),
456 'profiled' => array(
457 'label' => t('Contact Profile'),
458 'field types' => array('civicrm_contact'),
459 ),
460 );
461 return $formatters;
462 }
463
464 /**
465 * Implementation of hook_field_formatter().
466 */
467 function civinode_cck_field_formatter($field, $item, $formatter) {
468 // switch formatter in case we implement multiple formatters.
469 switch ($formatter) {
470 case 'profiled':
471 return theme('civinode_cck_profiled_contact', $item, $field);
472 break;
473
474 case 'link':
475 if ($field['type'] == 'civicrm_contact')
476 return theme('civinode_cck_formatter_contact', $item, 'display_name', 'link');
477 else if ($field['type'] == 'civicrm_group')
478 return theme('civinode_cck_formatter_group', $item, NULL, 'link');
479 else
480 return theme('civinode_cck_formatter_default', $item);
481
482
483 default:
484 case 'default':
485 if ($field['type'] == 'civicrm_contact')
486 return theme('civinode_cck_formatter_contact', $item);
487 else if ($field['type'] == 'civicrm_group')
488 return theme('civinode_cck_formatter_group', $item);
489 else
490 return theme('civinode_cck_formatter_default', $item);
491 break;
492 }
493 }
494
495 /**
496 * callback functions for the theme
497 */
498
499 function theme_civinode_cck_formatter_contact($item, $crm_field = 'display_name', $fmt = 'plain') {
500 $output = '';
501 $object_id = $item['object_id'];
502 if (!$object_id)
503 return '';
504 $contact = array();
505 _civinode_cck_cache_mgr('fetch', NULL, $object_id, $contact);
506 if (civinode_check_error($contact))
507 return "oops $object_id";
508 $desc = $contact[$crm_field];
509 switch ($fmt) {
510 case 'link':
511 $desc = l($desc, "civicrm/contact/view", array(),
512 "reset=1&cid=$object_id", NULL, FALSE, TRUE);
513 break;
514 case 'plain':
515 default:
516 $desc = check_plain($desc);
517 break;
518 }
519 $output .= $desc;
520 return $output;
521 }
522
523
524
525 function theme_civinode_cck_profiled_contact($item, $field) {
526 $output = '';
527 $object_id = $item['object_id'];
528 if (!$object_id) {
529 return ""; //may want to make this themeable
530 }
531 //TODO get correct profile from widget info
532 if ($field['default_profile_id'])
533 $default_profile = $field['default_profile_id'];
534 else
535 $default_profile = civinode_get_default_profile_id(0);
536
537 $contact = civinode_util_load_cdata($object_id, $default_profile);
538 if (civinode_check_error($contact))
539 return ""; //again, this may need theming
540
541 $output .= theme('crm_contact', $contact, $field);
542 return $output;
543 }
544
545 function theme_crm_contact($contact_array, $field) {
546 //For now, we do a table
547 $contact_id = $contact_array['contact_id'];
548 $rows = array();
549 $header = array();
550 $pid = $field['default_profile_id'] ?
551 $field['default_profile_id'] :
552 civinode_get_default_profile_id(0);
553 $classes = "crm-profile crm-profile-$pid";
554 //Get the fields and render them
555 $field_list = civinode_get_profile_field_list($pid, 'view');
556 $output = "<div class='$classes'>\n";
557 foreach ($field_list as $node_field => $field) {
558 $field_desc = civinode_get_field_info($pid, $field, 'view');
559 if (!isset($contact_array[$node_field]) or empty($contact_array[$node_field]))
560 continue;
561 $f_title = $field_desc['title'];
562 if (!$f_title)
563 $f_title = $node_field;
564 $rows[] =
565 array(
566 array('data' => $f_title, 'header' => 1,
567 'class' => 'civinode-profile-header'),
568 array('data' => $contact_array[$node_field])
569 );
570 }
571 $output .= theme('table', $header, $rows);
572 $output .= "</div>";
573
574 return $output;
575 }
576
577 function theme_civinode_cck_formatter_group($item) {
578 $output = '';
579 $object_id = $item['object_id'];
580 $group_obj = civinode_get_group_by_id($object_id);
581 if (!$group_obj) {
582 //do something lame that will help us debug
583 return theme('civinode_cck_formatter_default', $item);
584 }
585 $desc = t('%name (gid=%id)',
586 array('%name' => $group_obj->title,
587 '%id' => $group_obj->id)
588 );
589 $output .= $desc;
590 return $output;
591 }
592
593 function theme_civinode_cck_formatter_default($item) {
594 $output = '';
595 /**
596 if (isset($item['imageurl'])) {
597 $output .= l('<img src="'. check_plain($item['imageurl']) .'" />', $item['target_url'], array(),
598 NULL, NULL, FALSE, TRUE);
599 } else {
600 $output .= check_markup($item['description'], $item['description_format']);
601 }
602 $output .= l(t('Link'), $item['target_url']);
603 **/
604 $output .= "{$item['entity_type']} ID = {$item['object_id']}";
605 return $output;
606 }
607
608 function _civinode_cck_cache_mgr($op, $field, &$contact_id, &$data) {
609 //our "singleton simulcrum"
610 static $cache;
611 if (!isset($cache)) {
612 $cache = array();
613 }
614 if ($op == 'fetch') {
615 if (!isset($cache[$field][$contact_id])) {
616 $data = civinode_util_load_cdata($contact_id);
617 $cache[$field][$contact_id] = $data;
618 }
619 else
620 $data = $cache[$field][$contact_id];
621 }
622
623 return NULL;
624 }
625
626 function _civicrm_cck_display_modes() {
627 return
628 array('' => t('-- select display mode --'),
629 'link' => t('Link To CiviCRM'),
630 'profile' => t('Use CiviCRM Profile'),
631 );
632 }
633
634 /**
635 * Helper function to generate forms for each $item.
636 * This code assumes that the $form will in the larger form api structure
637 * as $hl_form['field_id'][$delta] = $form; at the level of ['field_id'] we
638 * either have the desc and title (as a field set) or just the #tree item.
639 */
640 function _civinode_cck_widget_manual_item_form($type, $field, $delta = 0, $item = array()) {
641 $form = array(); //ultimate return value
642 $form_chunk = array(); //ll fields
643 $raw_fieldname = $field['field_name'];
644 $fieldname = $raw_fieldname . "_$delta";
645 $is_multiple = $field['multiple'];
646 $widget_type = $field['widget']['type'];
647 $group_id = $field['default_group_id'];
648 if (!$group_id)
649 $group_id = 0;
650 $object_id = $item['object_id'];
651 if (!$is_multiple) {
652 //We need to add the label? May be better to add higher up
653 $label = $field['widget']['label'];
654 $label = $label ? $label : $fieldname;
655 $desc = $field['widget']['description'];
656 $form['#title'] = $label;
657 if ($desc) {
658 $form['#description'] = $desc;
659 }
660 }
661 else {
662 //we only want a label on the first item
663 if ($delta == 0)
664 $label = $field['widget']['label'];
665 else
666 $label = NULL;
667 $desc = NULL;
668 }
669
670 if ($type == 'contact') {
671 //have a contact?
672 if ($object_id) {
673 $contact = array();
674 _civinode_cck_cache_mgr('fetch', NULL, $object_id, $contact);
675 $object_id = $contact['contact_id'];
676 }
677 if ($widget_type == 'civinode_cck_contact_select') {
678 $options = civinode_group_contact_popup(TRUE, $group_id);
679 $form_chunk =
680 array('#type' => 'select',
681 '#options' => $options,
682 '#default_value' => $object_id ? $object_id : 0,
683 '#weight' => $field['widget']['weight'],
684 );
685 }
686 else if ($widget_type == 'civinode_cck_contact') {
687 $sortname = '';
688 $key = NULL;
689 if ($object_id) {
690 $key = $object_id;
691 $sortname = $contact['sort_name'];
692 }
693 $form_chunk =
694 civinode_contact_autoselect_widget($fieldname, $label,
695 $key, $sortname,
696 $group_id,
697 $desc);
698 }
699
700 }
701
702 else if ($type == 'group') {
703 if ($item['object_id'])
704 $group_id = $item['object_id'];
705 $form_chunk =
706 civinode_group_selector($label, $field['widget']['description'],
707 $group_id);
708
709 }
710
711 $form = array_merge($form, $form_chunk);
712 return $form;
713 }
714
715 function _civinode_cck_widget_manual_item_form_old($type, $field, $delta = 0, $item = array()) {
716
717 $fieldname = $field['widget']['field_name'];
718 if ($delta)
719 $fieldname .= "_$delta";
720 $widget_type = $field['widget']['type'];
721 $label = $field['widget']['label'];
722 $label = $label ? $label : $fieldname;
723 $group_id = $field['default_group_id'];
724 if (!$group_id)
725 $group_id = 0;
726
727 if ($type == 'contact') {
728 $object_id = $item['object_id'];
729 if (is_array($object_id)) {
730 $object_id = $object_id['cbox']['key'];
731 }
732 if ($object_id) {
733 $contact = array();
734 _civinode_cck_cache_mgr('fetch', NULL, $object_id, $contact);
735
736 if ($contact['sort_name']) {
737 $value = $contact['sort_name'];
738 }
739 else {
740 //object id is not available, so do not use it
741 error_log("civinode_cck error -- Contact $object_id not found");
742 $object_id = NULL;
743 }
744 }
745 if ($widget_type == 'civinode_cck_contact_select') {
746 $options = civinode_group_contact_popup(TRUE, $group_id);
747 $form['object_id'] =
748 array('#type' => 'select',
749 '#title' => $label,
750 '#options' => $options,
751 '#default_value' => $object_id ? $object_id : 0,
752 '#description' => $field['widget']['description'],
753 '#weight' => $field['widget']['weight'],
754
755 );
756 }
757 else if ($widget_type == 'civinode_cck_contact') {
758 $form['object_id'] =
759 civinode_contact_autoselect_widget($fieldname, $label,
760 $object_id, $value,
761 $group_id,
762 $field['widget']['description']);
763 }
764 }
765 elseif ($type == 'group') {
766 if ($item['object_id'])
767 $group_id = $item['object_id'];
768 $form['object_id'] =
769 civinode_group_selector($label, $field['widget']['description'],
770 $group_id);
771 }
772 //TODO other data types by object_id
773 $form['entity_type'] =
774 array('#type' => 'hidden',
775 '#value' => $type, //$item['entity_type'],
776 );
777 return $form;
778 }

  ViewVC Help
Powered by ViewVC 1.1.2