/[drupal]/contributions/modules/civinode/civinode_utils.inc
ViewVC logotype

Contents of /contributions/modules/civinode/civinode_utils.inc

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


Revision 1.43 - (show annotations) (download) (as text)
Fri Jul 6 22:14:16 2007 UTC (2 years, 4 months ago) by torenware
Branch: MAIN
CVS Tags: HEAD
Changes since 1.42: +57 -46 lines
File MIME type: text/x-php
Fixes for #157103
1 <?php
2 // $Id: civinode_utils.inc,v 1.31.2.8 2007/07/06 21:45:22 torenware Exp $
3 /**
4 *
5 * CiviNode Utility Functions
6 *
7 * These include wrappers for common CRM related tasks like
8 * determining group membership, going from NID to CID and
9 * back, and doing loads.
10 *
11 */
12
13 //lowlevel routines to bypass the normal API.
14 //all of these routines should be treated as private
15 //with extreme prejudice.
16 require_once 'lowlevel/civinode_groups.inc';
17
18 //Some magic numbers that Lobo won't code compatibly for us (rant rant)
19 define('CIVINODE_MAGIC_ACTION_NONE', 0);
20 define('CIVINODE_MAGIC_ACTION_ADD', 1);
21 define('CIVINODE_MAGIC_ACTION_UPDATE', 2);
22 define('CIVINODE_MAGIC_ACTION_VIEW', 4);
23 define('CIVINODE_MAGIC_ACTION_DELETE', 8);
24 define('CIVINODE_MAGIC_ACTION_BROWSE', 16);
25 define('CIVINODE_MAGIC_ACTION_ENABLE', 32);
26 define('CIVINODE_MAGIC_ACTION_DISABLE', 64);
27 define('CIVINODE_MAGIC_ACTION_EXPORT', 128);
28 define('CIVINODE_MAGIC_ACTION_BASIC', 256);
29 define('CIVINODE_MAGIC_ACTION_ADVANCED', 512);
30 define('CIVINODE_MAGIC_ACTION_PREVIEW', 1024);
31 define('CIVINODE_MAGIC_ACTION_FOLLOWUP', 2048);
32 define('CIVINODE_MAGIC_ACTION_MAP', 4096);
33 define('CIVINODE_MAGIC_ACTION_PROFILE', 8192);
34 define('CIVINODE_MAGIC_ACTION_MAX_ACTION', 16383);
35
36
37
38 /**
39 * Initialization checks
40 *
41 *
42 */
43 function civinode_check_init(){
44 if (function_exists('civicrm_initialize')) {
45 civicrm_initialize(TRUE);
46 return TRUE;
47 }
48 return FALSE;
49 }
50
51
52 /**
53 * Check for Voter component
54 */
55 function civinode_voter_install() {
56 if (!civinode_check_init())
57 return FALSE;
58 if (function_exists('crm_voter_create_campaign'))
59 return TRUE;
60 else
61 return FALSE;
62 }
63
64 /**
65 * Check for admin level access for this operation
66 */
67 function civinode_check_admin_access($op = 'view'){
68 global $user;
69 //user_access is heavily cached, so we don't
70 //worry about doing any more of it
71 if ( user_access('administer CiviCRM', $user))
72 return TRUE;
73 if ( $op == 'view' and user_access('view all contacts'))
74 return TRUE;
75 if ( ($op == 'update' or $op == 'delete') and user_access('edit all contacts'))
76 return TRUE;
77
78 return FALSE;
79
80 }
81
82
83 /**
84 * Error handling. We will want to keep error info
85 * around so we can pass it to UI, etc. The setter
86 * will do this.
87 *
88 * @defgroup Error_Handlers
89 */
90
91 /**
92 * Error testing and logging routine.
93 *
94 * @ingroup Error_Handlers
95 * @param mixed $obj value returned by CiviCRM API that may be error.
96 * @return boolean TRUE if $obj is a CiviCRM error.
97 */
98 function civinode_check_error($obj = NULL, $log_error = TRUE){
99 //Reset the error
100 civinode_clear_error();
101 if (!civinode_check_init()){
102 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
103 return FALSE;
104 }
105 if (!$obj) {
106 $obj = _civinode_get_last_error();
107 }
108 //Docs are wrong... :-(
109 //if(crm_is_error($obj)){
110 if($obj and is_a($obj, 'CRM_Core_Error')){
111 //$msg = $obj->_errors[0]['message'];
112 _civinode_set_error($obj);
113 if (!$log_error)
114 return TRUE;
115 //may want to record the calling URL as well...
116 $trace = debug_backtrace();
117 $caller = $trace[1]['function'] . "@" . $trace[1]['line'];
118 watchdog('CRM', "$msg ($caller)", WATCHDOG_ERROR);
119 return TRUE;
120 }
121 else
122 return FALSE;
123
124 }
125
126 /**
127 * Get the text of the last error checked via civinode_check_error
128 *
129 * @ingroup Error_Handlers
130 * @return string Error string.
131 */
132 function civinode_get_last_error(){
133 $err_obj = _civinode_set_error();
134 if ($err_obj) {
135 $msg = $err_obj->_errors[0]['message'];
136 return $msg;
137 }
138 return '';
139 }
140
141 /**
142 * Get the last error object checked via civinode_check_error
143 *
144 * @ingroup Error_Handlers
145 * @return object PEAR error object.
146 */
147
148 function civinode_get_last_error_object() {
149 $err_obj = _civinode_set_error();
150 return $err_obj;
151 }
152
153 /**
154 * Clear the last error saved.
155 *
156 * @ingroup Error_Handlers
157 *
158 */
159 function civinode_clear_error(){
160 _civinode_set_error(NULL, TRUE);
161 }
162
163
164 function _civinode_set_error($value = NULL, $reset = FALSE){
165 static $error;
166 $last_error = $error;
167 if($reset){
168 $error = NULL;
169 return NULL;
170 }
171 if(!$value)
172 return $last_error;
173 else{
174 $error = $value;
175 return $value;
176 }
177
178 }
179
180
181 /**
182 * Non destructively see if you can get the last error
183 * off the error stack, if there is one.
184 *
185 * @ingroup Error_Handlers
186 * @return for now, a PEAR error object
187 */
188 function &_civinode_get_last_error(){
189 $last_error = NULL;
190 if (!civinode_check_init()){
191 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
192 return "FATAL: CiviCRM not installed";
193 }
194
195 $error_stack =& CRM_Core_Error::singleton();
196 //For now, let's see how "deep the rabbit hole goes" and
197 //return just the tip of the stack.
198 if ($error_stack->hasErrors()) {
199 $errors = $error_stack->getErrors();
200 $last_error = array_pop($errors);
201 }
202
203 return $last_error;
204 }
205
206
207 /**
208 * Metadata about contacts
209 *
210 * @defgroup CiviCRM_MetaData
211 */
212
213
214 /**
215 * Get a list of profile names.
216 *
217 * @ingroup CiviCRM_MetaData
218 * @param array Search criteria for profiles (UNUSED).
219 * @return array of int => string
220 */
221 function civinode_get_profiles($params = NULL){
222 if (!civinode_check_init()){
223 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
224 return FALSE;
225 }
226 //Note: as of 1.4, we ignore params
227 //We may want to use the auth table to reduce this
228 //list (i.e., you don't have the right, you can't
229 //assign it.
230 $profiles = crm_uf_get_profile_groups();
231 //winnow it down here later...
232 return $profiles;
233 }
234
235 /**
236 * Get the human-readable name of a profile.
237 *
238 * @ingroup CiviCRM_MetaData
239 * @param int CiviCRM Profile ID
240 * @return string
241 */
242 function civinode_get_profile_title($pid){
243 static $cache;
244 if(isset($cache[$pid]))
245 return $cache[$pid];
246 if (!civinode_check_init()){
247 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
248 return NULL;
249 }
250 $cache[$pid] = crm_uf_get_profile_title($pid);
251 return $cache[$pid];
252 }
253
254
255
256 /**
257 * Get the right profile ID for displaying this drupal user.
258 *
259 * @ingroup CiviCRM_MetaData
260 * @param int Drupal UID
261 * @return int CiviCRM Profile ID
262 */
263 function civinode_get_default_profile_id($uid = 0){
264 $pid = variable_get('civinode_default_pid', 1);
265 return $pid; //TO DO: make this settable for the individual
266 }
267
268
269 /**
270 * Get the appropriate meta data for this PID and operation
271 *
272 * @ingroup CiviCRM_MetaData
273 * @param int CiviCRM Profile ID
274 * @param string $op Drupal-style operation name
275 * @return array of field_name => array
276 */
277 function civinode_get_profile_metadata($pid, $op = ''){
278 if (!civinode_check_init()){
279 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
280 return FALSE;
281 }
282 static $cache;
283 $action = CRM_CORE_ACTION_VIEW;
284 switch($op){
285 default:
286 //We will translate Drupal ops into actions here
287 $action = CRM_CORE_ACTION_VIEW;
288 break;
289 }
290 //structure of cache: first by pid, then ACTION
291 if(isset($cache[$pid])){
292 if(isset($cache[$pid][$action]))
293 return $cache[$pid][$action];
294 }
295 else
296 $cache[$pid] = array();
297
298 //what should visibility be set to??
299 $raw_data = crm_uf_get_profile_fields($pid, FALSE, $action);
300 $title = crm_uf_get_profile_title($pid);
301 $cache[$pid][$action] = $raw_data;
302
303 return $cache[$pid][$action];
304 }
305
306
307 /**
308 * This function is a nasty hack to get around the way location-related
309 * fields get handled. It returns a map from what names are used for
310 * fields in a node or the assoc array calls in the CRM API,
311 * into the names used internally by CRM for formatting info.
312 *
313 * @ingroup CiviCRM_MetaData
314 * @param int CiviCRM Profile ID
315 * @param string $op Drupal-style operation name
316 * @return array of string
317 */
318 function civinode_get_profile_field_list($profile_id, $op = 'view'){
319 static $cache;
320 $cache_key = "$op::$profile_id";
321 if(isset($cache[$cache_key]))
322 return $cache[$cache_key];
323 $meta_data = civinode_get_profile_metadata($profile_id, $op);
324 $fields = array();
325 if($meta_data){
326 $raw_fields = array_keys($meta_data);
327 foreach($raw_fields as $raw_field){
328 list($base, $loc_type_id) = explode('-', $raw_field);
329 //does this preserve order??
330 $fields[$base] = $raw_field;
331 }
332 }
333 $cache[$cache_key] = $fields;
334 return $fields;
335 }
336
337 /**
338 * Get the appropriate meta data for this field for this PID and operation
339 *
340 * @ingroup CiviCRM_MetaData
341 * @param int CiviCRM Profile ID
342 * @param string $op Drupal-style operation name
343 * @return array of string => mixed
344 */
345 function civinode_get_field_info($pid, $fld_name, $op = 'view'){
346 //This function is a candidate for yet more
347 //caching, but see if we are spending lots of time here
348 //first...
349
350 $metadata = civinode_get_profile_metadata($pid, $op);
351 //This would be easy, except that CRM plays games with locations.
352 //Since it does, we will need to deal with multiple locations
353 //and convert to the "base form"
354
355 //First, maybe we won't have to deal with this problem
356 if(isset($metadata[$fld_name]))
357 return $metadata[$fld_name];
358 //OK, not so lucky. See if we are dealing with a location
359 //dependent item
360 $keys = array_keys($metadata);
361 $real_key = "";
362 foreach($keys as $key){
363 list($base, $loc_type_id) = explode('-', $key);
364 if($base == $fld_name){
365 $real_key = $base;
366 break;
367 }
368 }
369 if($real_key)
370 return $metadata[$real_key];
371
372 return NULL; //we don't recognize this key
373 }
374
375
376 /**
377 * Get a Drupal user's CRM contact_id. Caching wrapper for crm_uf_get_match_id
378 *
379 * @ingroup CiviCRM_MetaData
380 * @param int Drupal UID
381 * @return int CiviCRM Profile ID
382 *
383 */
384 function civinode_util_get_user_cid($uid){
385 if(!$uid)
386 return 0;
387 static $cid_cache;
388 if(!isset($cid_cache[$uid])){
389 if (!civinode_check_init()){
390 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
391 return FALSE;
392 }
393 $cid = crm_uf_get_match_id($uid);
394 //No user should lack a cid, so we
395 //may be registering. Don't cache
396 //to cover that case.
397 if ($cid)
398 $cid_cache[$uid] = $cid;
399 else
400 return 0;
401 }
402 return $cid_cache[$uid];
403 }
404
405
406 /**
407 * Loads contact data using a profile as a filter
408 *
409 * @ingroup CiviCRM_MetaData
410 * @param int $cid CRM Contact ID
411 * @param int $pid CRM Profile ID
412 * @return array assoc. array of contact data
413 */
414 function civinode_util_load_cdata($cid, $pid = 0){
415 if (!civinode_check_init()){
416 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
417 return NULL;
418 }
419 $params = array('contact_id' => $cid);
420 if ($pid) {
421 $return_properties = array();
422 $keys = civinode_get_profile_field_list($pid, 'view');
423 foreach (array_keys($keys) as $key) {
424 $return_properties[$key] = 1;
425 }
426 }
427 else {
428 $return_properties = NULL;
429 }
430
431 $data = crm_fetch_contact($params, $return_properties);
432 return $data;
433 }
434
435
436 /**
437 * Generate a nice link back to the contact
438 *
439 * @param unknown_type $contact_id
440 * @param unknown_type $format
441 * @param unknown_type $params
442 * @return unknown
443 */
444 function civinode_util_link_to_crm($contact_id, $format = NULL, $params = array()) {
445 $data = civinode_util_load_cdata($contact_id);
446 if (!$data)
447 return NULL;
448 $new_params = array();
449 if ($params) {
450 foreach ($params as $key => $text) {
451 $val_fld = _civinode_strip_t_fld_type($key);
452 $new_params[$key] = $data[$val_fld];
453 }
454 }
455 if (!$format) {
456 $format = '%display_name';
457 $new_params['%display_name'] = $data['display_name'];
458 }
459 $text = t($format, $new_params);
460 //http://design/civicrm/contact/view?reset=1&cid=1624
461 //link allowing HTML
462 $link = l($text, "civicrm/contact/view", array(), "reset=1&cid=$contact_id", NULL, FALSE, TRUE);
463 return $link;
464 }
465
466 function _civinode_strip_t_fld_type($fld) {
467 //remove that first char
468 $first_char = substr($fld, 0, 1);
469 if ($first_char == '%' or
470 $first_char == ':' or
471 $first_char == '!')
472 return substr($fld, 1); //rest of string
473 else
474 return $fld;
475 }
476
477
478 /**
479 * Information about groups
480 * @defgroup CiviCRM_Groups
481 */
482
483
484 /**
485 * List groups by various criteria
486 *
487 * @ingroup CiviCRM_Groups
488 * @param array $params assoc array of search params. NULL is all groups.
489 * @return array of int => string
490 */
491 function civinode_get_groups($params = NULL){
492 //we just wrap crm_get_groups
493 if (!civinode_check_init()){
494 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
495 return FALSE;
496 }
497 $groups = crm_get_groups($params);
498 if(civinode_check_error($groups))
499 return NULL;
500 $group_list = array();
501 foreach($groups as $gdata){
502 $group_list[$gdata->id] = $gdata->title;
503 }
504
505 return $group_list;
506
507 }
508
509
510 /**
511 * List static groups for a contact.
512 *
513 * @ingroup CiviCRM_Groups
514 * @param int $cid CiviCRM Contact ID
515 * @return array of int => string
516 */
517 function civinode_get_groups_for_cid($cid) {
518 static $group_cache;
519 if (!is_array($group_cache))
520 $group_cache = array();
521 $groups = array();
522 if (!isset($group_cache[$cid])) {
523 if (!civinode_check_init()){
524 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
525 return FALSE;
526 }
527 //Get static groups
528 //$list = CiviNode_LL_getContactGroup($cid, 'Added');
529 //LL is required since crm_contact_get_groups stupidly requires
530 //you to belong to a group to check membership
531 $list = CiviNode_LL_getContactGroup($cid, 'Added');
532
533 if (civinode_check_error($list))
534 return FALSE;
535
536 foreach ($list as $eid => $data) {
537 $groups[] = $data['group_id'];
538 }
539 $group_cache[$cid] = $groups;
540 }
541 else
542 $groups = $group_cache[$cid];
543
544 return $groups;
545 }
546
547
548 /**
549 * Wrapper to add a contact to a group.
550 *
551 * @ingroup CiviCRM_Groups
552 * @param int $group_id CiviCRM Group ID
553 * @param int $cid CiviCRM Contact ID
554 * @param string $source source to save to CRM data store.
555 * @return boolean TRUE if the contact was successfully added.
556 */
557 function civinode_add_contact_to_group($group_id, $contact_id, $source = 'civinode'){
558 if (civinode_util_cid_in_group($contact_id, $group_id))
559 return TRUE; //nothing to do.
560 $group = civinode_get_group_by_id($group_id);
561 if (!$group or civinode_check_error($group))
562 return FALSE;
563 $contact = crm_get_contact(array('contact_id' => $contact_id));
564 if (!$contact or civinode_check_error($contact))
565 return FALSE;
566 //Work-around for a 1.4 bug: id is set here, but not contact_id
567 if (!isset($contact->contact_id))
568 $contact->contact_id = $contact->id;
569 $contacts = array($contact);
570 //'API' could be whatever you want, including the name of your module
571 crm_add_group_contacts($group, $contacts, 'Added', 'API');
572 return TRUE;
573 }
574
575
576 /**
577 * Remove a contact from a group
578 *
579 * @ingroup CiviCRM_Groups
580 * @param int $group_id CiviCRM Group ID
581 * @param int $cid CiviCRM Contact ID
582 * @return boolean TRUE if the contact was successfully removed (or was not in this group).
583 */
584 function civinode_remove_contact_from_group($gid, $cid){
585 $group = civinode_get_group_by_id($id);
586 if (!$group)
587 return FALSE;
588 if (!civinode_util_cid_in_group($cid, $gid))
589 return TRUE; //nothing to do, but we are also OK
590 $to_remove = array();
591 $cobj = crm_get_contact(array('contact_id' => $cid));
592 if (civinode_check_error($cobj))
593 return FALSE;
594 $to_remove[] =& $cobj;
595 $rslt = crm_delete_group_contacts($group, $to_remove, 'API');
596 if (!$rslt)
597 return TRUE; //success
598 else
599 return !civinode_check_error($rslt); //so we log the error
600
601 }
602
603
604 /**
605 * Get a group by name, creating it if need be
606 *
607 * @ingroup CiviCRM_Groups
608 * @param string $name name of the group to retrieve or create.
609 * @param string $source what module created group (UNUSED?)
610 * @param boolean $create if true and no group exists, create a group.
611 * @return int The CiviCRM Group ID of the group (false/0 if failed)
612 */
613 function civinode_get_group_by_name($name, $source = 'civinode', $create = TRUE){
614 if (!civinode_check_init()){
615 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
616 return NULL;
617 }
618 $groups = crm_get_groups(array('title' => $name));
619 if(civinode_check_error($groups))
620 return NULL;
621 $gid = 0; //pessimism
622 if (count($groups)) {
623 //find an exact match
624 foreach ($groups as $group) {
625 if ($name == $group->title) {
626 $gid = $group->id;
627 break;
628 }
629 }
630
631 }
632 else if ($create) {
633 //Need a fresh minted group
634 $params = array('title' => $name,
635 'source' => $source,
636 'is_active' => 1);
637 $group = crm_create_group($params);
638 if(civinode_check_error($group))
639 return NULL;
640 $gid = $group->id;
641 }
642
643 return $gid;
644
645 }
646
647
648 /**
649 * Wrapper to fetch a CRM group object
650 *
651 * @ingroup CiviCRM_Groups
652 * @param int $gid CiviCRM Group ID
653 * @return object the CiviCRM group object (NULL on error)
654 */
655 function civinode_get_group_by_id($gid){
656 if (!civinode_check_init()){
657 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
658 return NULL;
659 }
660 $groups = crm_get_groups(array('id' => $gid));
661 if(civinode_check_error($groups))
662 return NULL;
663 //Is this a behavior change from 1.3???
664 return count($groups) ? $groups[0] : NULL;
665 }
666
667
668
669 /**
670 * Get target groups as allowed for the current user
671 *
672 * @ingroup CiviCRM_Groups
673 * @return array of int => string.
674 */
675 function civinode_get_drupal_allowed_groups() {
676 //TO DO: this can be greatly sped up.
677 $gids = civinode_get_current_target_groups('view');
678 $groups = array();
679 if (count($gids)) {
680 foreach ($gids as $gid) {
681 $group = civinode_get_group_by_id($gid);
682 $groups[$gid] = $group->title;
683 }
684 }
685 return $groups;
686 }
687
688 /**
689 * Groups for this user
690 *
691 * @param string $op
692 * @return array
693 */
694 function civinode_get_current_target_groups($op = 'view') {
695 civinode_check_init();
696 $group_list = civinode_get_groups();
697 return array_keys($group_list);
698 }
699
700
701 /**
702 * Determines if a CRM group contains a contact.
703 *
704 * @ingroup CiviCRM_Groups
705 * @param int $cid CRM Contact ID
706 * @param int $gid CRM Group ID
707 * @return bool TRUE if it belongs
708 */
709 function civinode_util_cid_in_group($cid, $gid){
710 if (!$cid or !$gid)
711 return FALSE; //sanity clause
712 if (!civinode_check_init()){
713 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
714 return FALSE;
715 }
716 //use a search instead, since it detects smart groups also.
717 $params = array('group' => array($gid => 1), 'contact_id' => $cid);
718 $contact = crm_fetch_contact($params);
719 if (civinode_check_error($contact))
720 return FALSE;
721 //return $cnt ? TRUE : FALSE;
722 return TRUE;
723 }
724
725
726
727
728 /**
729 * Wrapper for getting back an array of contact ids.
730 *
731 * @ingroup CiviCRM_Groups
732 * @param int $gid CiviCRM group ID
733 * @param int $start index of first record
734 * @param int $num_recs number of records to pull. 0 is "all records"
735 *
736 */
737 function civinode_util_group_contacts($gid, $start = 0, $num_recs = 0){
738 if (!civinode_check_init()){
739 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
740 return NULL;
741 }
742 $groups = array( $gid => 1);
743 $params = array( 'group' => $groups );
744 $returnProperties = array('contact_id' => 1);
745 $limit = $num_recs ? $num_recs : 100;
746 $contacts = crm_contact_search($params, $returnProperties, NULL, $start, $limit);
747 $list = array();
748 foreach($contacts[0] as $contact){
749 $list[] = $contact['contact_id'];
750 }
751 return $list;
752 }
753
754
755 /**
756 * Activity wrappers
757 *
758 * @defgroup CiviCRM_Activity_History
759 */
760
761
762 /**
763 * Creates a simple activity history record
764 *
765 * @ingroup CiviCRM_Activity_History
766 * @param int $cid CRM Contact ID to associate with the activity
767 * @param int $id_to_save An integer key you want to save with the activity
768 * @param string $activity_type 'Meeting' or other defined activity type
769 * @param string $module_base UI name of the module storing this stuff.
770 * @param string $desc Short description to display about the activity
771 * @param int $group_id An optional CRM group_id to associate with the activity
772 * @param string $call_back The name of a PHP function with the following
773 * prototype, returning a URL:
774 *
775 * function my_details_handler($it_to_save, $crm_activity_hist_id);
776 *
777 * You can use civinode_get_activity($crm_activity_hist_id) to get back
778 * an associative array with the data stored in the activity record.
779 *
780 *
781 * @param int $date Unix time stamp. Default is now, i.e., time().
782 * @return boolean TRUE on success
783 */
784 function civinode_create_activity($cid, $id_to_save, $activity_type,
785 $module_base = 'civinode',
786 $desc = "", $group_id = 0,
787 $call_back = NULL, $date = NULL){
788 $params = array('module' => $module_base,
789 'entity_table' => 'civicrm_contact',
790 'entity_id' => $cid,
791 'activity_summary' => $desc,
792 'activity_type' => $activity_type);
793 if (!$date)
794 $date = time();
795
796 $date_str = date('Ymd000000', $date);
797 $params['activity_date'] = $date_str;
798 $params['activity_id'] = $id_to_save;
799 //callback...
800 //$url = url($link);
801 if ($call_back)
802 $params['callback'] = $call_back;
803 $hist = crm_create_activity_history($params);
804 return civinode_check_error($hist);
805 }
806
807
808 /**
809 * Getter for activity history data
810 *
811 * @ingroup CiviCRM_Activity_History
812 */
813 function civinode_get_activity($crm_activity_hist_id){
814 $defaults = array();
815 $params = array('id' => $crm_activity_hist_id);
816 $activity = crm_get_activity_history_object($params, $defaults);
817 if (civinode_check_error($activity))
818 return NULL;
819 return $defaults;
820 }
821
822
823
824 /**
825 * Sample URL callback for activities
826 *
827 * @ingroup CiviCRM_Activity_History
828 */
829 function civinode_activity_callback($saved_id, $crm_activity_id) {
830 //error_log("Call back was called");
831 $defaults = civinode_get_activity($crm_activity_id);
832 if (!civinode_check_error($defaults)) {
833 //We are cheating: we assume that the module is really
834 //a path
835 if (isset($defaults['module'])) {
836 $base = $defaults['module'] . "/activity/$crm_activity_id/$saved_id";
837 return url($base);
838 }
839
840 }
841 }
842
843
844 //TO DO: we may want to do synchronization via cron as well. PITA. :-(
845
846 /**
847 * Form API widgets and stuff
848 *
849 * @defgroup CiviNode_Form_Widgets
850 */
851
852
853
854 /**
855 * AJAX autocompleter handler for CiviCRM Contacts
856 *
857 * @ingroup CiviNode_Form_Widgets
858 */
859 function civinode_contact_autocompleter($key, $val, $string){
860 if (!civinode_check_init()){
861 watchdog('CRM', t('CiviCRM must be installed for CiviNode'),
862 WATCHDOG_ERROR);
863 exit();
864 }
865 //first, require that we have at least 3 characters
866 if (strlen($string) < 3)
867 exit();
868
869 //OR is really needed here. Lobo??
870 $return_fields = array('display_name' => 1,
871 'id' => 1,
872 'contact_type' => 1,
873 );
874
875 $params['sort_name'] = "%$string%";
876 //Check the key/val argument for special handling
877 if ($key == 'gid' and is_numeric($val)) {
878 $params['group'] = array($val => 1);
879
880 }
881 $rslt = crm_contact_search($params, $return_fields);
882 $matches = array();
883 foreach($rslt[0] as $id => $data){
884 $id_str = " (" . $id . ")";
885 $matches[$data['display_name'] . $id_str] = check_plain($data['display_name'] . $id_str);
886 }
887 //This assumes you are using
888 //4.7 RC2 or later...
889 print drupal_to_js($matches);
890 exit();
891
892 }
893
894
895
896 /**
897 * Returns a keyed array of id => 'useful display name' for all basic CRM types
898 * It assumes that we want to check for access permissions for the global
899 * Drupal user (for contacts and groups). This function is useful for presenting
900 * selection options to users during input forms, etc.
901 *
902 * @ingroup CiviNode_Form_Widgets
903 */
904 function civinode_get_allowed_options($type, $params = NULL) {
905 static $cache;
906 if(isset($cache[$type]) and !$params) {
907 return $cache[$type];
908 }
909 if (!civinode_check_init()){
910 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
911 return NULL;
912 }
913 //See if we have voter available
914 $voter_install = civinode_voter_install();
915
916 $result = array();
917 switch($type) {
918 case 'relationship':
919 $relationships = crm_get_relationship_types();
920 while($relationship = array_pop($relationships)) {
921 $result[$relationship->id] = $relationship->description;
922 }
923 break;
924
925 case 'group':
926 $result = civinode_get_drupal_allowed_groups();
927 break;
928
929 case 'profile':
930 $result = crm_uf_get_profile_groups();
931 break;
932
933 case 'contact':
934 $allowed_groups = civinode_get_drupal_allowed_groups();
935 $groups = array();
936 //we restrict to the requested groups if there are any.
937 //0 is the "universal" group, so skip this if it is requested
938 if ($params and isset($params['groups']) and !in_array(0, $params['groups'])) {
939 foreach ($params['groups'] as $requested_group) {
940 if (isset($allowed_groups[$requested_group]))
941 $groups[$requested_group] = $allowed_groups[$requested_group];
942 }
943 }
944 else
945 $groups = $allowed_groups;
946 foreach($groups as $gid => $title) {
947
948 $tmp = crm_get_groups(array('id' => $gid));
949 $group = array_pop($tmp);
950 $group_contacts = crm_get_group_contacts($group, array('display_name'));
951 foreach($group_contacts as $contact) {
952 $result[$contact->contact_id] = $contact->display_name;
953 }
954 }
955 break;
956
957 case 'activity':
958 require_once 'CRM/Core/PseudoConstant.php';
959 $result =& CRM_Core_PseudoConstant::activityType(true, 'id > 3');
960 break;
961
962 case 'tag':
963 require_once 'CRM/Core/PseudoConstant.php';
964 $result =& CRM_Core_PseudoConstant::tag();
965 break;
966
967 case 'location':
968 require_once 'CRM/Core/PseudoConstant.php';
969 $result =& CRM_Core_PseudoConstant::locationType(true);
970 break;
971
972 case 'campaign':
973 if ($voter_install) {
974 $result = civinode_voter_campaign_selector();
975 }
976 break;
977
978 case 'canvass':
979 if ($voter_install) {
980 $result = civinode_voter_canvass_selector();
981 }
982 break;
983
984
985 /* disabled for now
986 case 'field':
987 $fields = crm_get_class_properties('Individual', 'custom');
988 foreach($fields as $field) {
989 dprint_r($field);
990 $result[$field[data_type] .':' . $field[id]] =
991 implode(' : ', array($field[name], $field[description]));
992 }
993 break;
994 */
995
996 /* disabled for now
997 case 'search':
998 require_once 'CRM/Core/PseudoConstant.php';
999 $result =& CRM_Core_PseudoConstant::savedSearch();
1000 break; */
1001
1002 }
1003 //For now, if we had to restrict the query, do not cache
1004 if (!$params)
1005 $cache[$type] = $result;
1006
1007 return $result;
1008 }
1009
1010
1011
1012 /**
1013 * Forms API Widget for selecting groups
1014 *
1015 * @ingroup CiviNode_Form_Widgets
1016 * @return array of Forms API parameters
1017 */
1018 function civinode_group_selector($title, $desc = NULL, $default_gid = 0,
1019 $params = NULL){
1020 $groups = civinode_get_groups($params);
1021 if (!$default_gid)
1022 $default_gid = 0; //must be explicit for Drupal Forms API
1023 //Since none is an option...
1024 $groups[0] = t('<select a group>');
1025 $widget = array(
1026 '#type' => 'select',
1027 '#title' => $title,
1028 '#options' => $groups
1029 );
1030 //if ($default_gid)
1031 $widget['#default_value'] = $default_gid;
1032 if ($desc)
1033 $widget['#description'] = $desc;
1034
1035 return $widget;
1036
1037 }
1038
1039
1040 /**
1041 * Forms API Widget for selecting CiviCRM profiles
1042 *
1043 * @ingroup CiviNode_Form_Widgets
1044 * @return array of Forms API parameters
1045 */
1046 function civinode_profile_selector($title, $desc = NULL, $default_pid = 0,
1047 $params = NULL){
1048 $options = civinode_get_profiles($params);
1049 $options[0] = t('-- select a profile -- ');
1050 $widget = array(
1051 '#type' => 'select',
1052 '#title' => $title,
1053 '#options' => $options
1054 );
1055 if ($default_pid)
1056 $widget['#default_value'] = $default_pid;
1057 if ($desc)
1058 $widget['#description'] = $desc;
1059
1060 return $widget;
1061
1062
1063 }
1064
1065 /**
1066 * Campaign selector...
1067 */
1068 function civinode_voter_campaign_selector(){
1069 if (civinode_voter_install())
1070 return crm_voter_get_campaigns();
1071 else
1072 return array();
1073 }
1074
1075
1076 /**
1077 * Canvass selector...
1078 */
1079 function civinode_voter_canvass_selector(){
1080 if (civinode_voter_install())
1081 return crm_voter_get_canvasses();
1082 else
1083 return array();
1084 }
1085
1086 /**
1087 * A forms api widget for a autocompleting contact widget
1088 *
1089 * @ingroup CiviNode_Form_Widgets
1090 */
1091 function civinode_contact_auto_selector($title, $desc = NULL,
1092 $autocomplete = 'civinode/autocomplete/contact',
1093 $key='any', $val = 'any'){
1094 $widget = array(
1095 '#type' => 'textfield',
1096 '#title' => $title,
1097 '#size' => 60,
1098 '#autocomplete_path' => $autocomplete . "/$key/$val"
1099 );
1100 if ($desc)
1101 $widget['#description'] = $desc;
1102
1103 return $widget;
1104
1105
1106 }
1107
1108
1109 /**
1110 * Editing widget for a profile, wrapped for Forms API
1111 *
1112 * For now, we directly use CiviCRM UI, since we don't have quite
1113 * enough metadata available to us to do this right ourselves.
1114 *
1115 * If called w/o a contact_id, this widget will put up the UI for
1116 * creating a new contact.
1117 *
1118 * @ingroup CiviNode_Form_Widgets
1119 */
1120 function civinode_get_edit_profile_html($pid, $contact_id = 0){
1121 if (!civinode_check_init()){
1122 watchdog('CRM', t('CiviCRM must be installed for CiviNode'), WATCHDOG_ERROR);
1123 return NULL;
1124 }
1125
1126 $action = $contact_id ?
1127 CIVINODE_MAGIC_ACTION_UPDATE :
1128 CIVINODE_MAGIC_ACTION_ADD;
1129
1130 if (!isset($_POST['op']) or $_POST['op'] == t('Delete')
1131 or $_POST['op'] == t('Preview')) {
1132 //$action += CIVINODE_MAGIC_ACTION_PREVIEW;
1133 unset($_POST['_qf_default']);
1134 unset($_REQUEST['_qf_default']);
1135 }
1136 $title = crm_uf_get_profile_title($pid);
1137 $reset = isset($_POST['edit']) ? FALSE : TRUE;
1138 $output = crm_uf_get_profile_html( $contact_id, $title, $action, FALSE, $reset );
1139 //Now wrap it for the API. It may make sense
1140 //to put this into a fieldset as well.
1141 return array('its_data' => array('#value' => $output),
1142 '#title' => $title,
1143 '#collapsible' => TRUE,
1144 '#type' => 'fieldset',
1145 '#weight' => -3);
1146
1147 }
1148
1149
1150 /**
1151 * Handlers for relationships
1152 * @defgroup CiviCRM_Relationships
1153 */
1154
1155
1156
1157 /**
1158 * Fetch a relationship for a contact
1159 *
1160 * @ingroup CiviCRM_Relationships
1161 * @param int $contact_id CRM contact_id
1162 * @param array $rel_types names of relation types to retrieve.
1163 * @return
1164 */
1165 function civinode_fetch_relationships($contact_id, $rel_types = array()){
1166 static $types;
1167 if (!civinode_check_init()){
1168 watchdog('CRM', t('CiviCRM must be installed for CiviNode'),
1169 WATCHDOG_ERROR);
1170 return NULL;
1171 }
1172
1173 //No contact, no relationship!
1174 if (!$contact_id)
1175 return FALSE;
1176 $contact = crm_get_contact(array('contact_id' => $contact_id));
1177 if (!$contact or civinode_check_error($contact))
1178 return FALSE;
1179 //First, we need type objects. Cache 'em
1180 $type_objs = array();
1181 if ($rel_types and count($rel_types)) {
1182 if (!$types) {
1183 $all_types = crm_get_relationship_types();
1184 foreach ($all_types as $robj) {
1185 if (isset($robj->name_a_b)) {
1186 $types[$robj->name_a_b] = $robj;
1187 if ($robj->name_a_b != $robj->name_b_a)
1188 $types[$robj->name_b_a] = $robj;
1189 }
1190 }
1191 }
1192 foreach ($rel_types as $type_name) {
1193 //pull out the right objects. For now, a missing
1194 //type is *not* an error (TO DO: best behavior?)
1195 if (isset($types[$type_name]))
1196 $type_objs[] = $types[$type_name];
1197 }
1198 }
1199 //Docs say this returns an array or null
1200 return crm_get_relationships($contact, NULL, $type_objs);
1201
1202 }
1203
1204 /**
1205 * Dojo support
1206 */
1207
1208 function civinode_contact_autoselect_widget($var_name, $title,
1209 $key = '', $val = '',
1210 $group_id = 0,
1211 $desc = NULL,
1212 $initialize = TRUE) {
1213 static $dojo_init, $dojo_cache;
1214 $self_id = "cbox_{$var_name}";
1215 $shadow_id = "cbox_val_{$var_name}";
1216 $setter_func = "cn_cck_{$var_name}_setter";
1217 $attribs =
1218 array('dojoType' => 'ComboBox',
1219 'mode' => 'remote',
1220 'dataUrl' => _civinode_dojo_dataurl($group_id),
1221 'onValueChanged' => $setter_func,
1222 //'setSelectedValue' => "$setter_func(arguments[0])",
1223 );
1224 $item['cbox']['key'] =
1225 array('#type' => 'textfield',
1226 '#title' => $title,
1227 '#id' => $self_id,
1228 '#description' => $desc,
1229 '#maxlength' => 60,
1230 '#attributes' => $attribs,
1231 '#default_value' => $key, //sort name of contact
1232 );
1233 //shadow item to hold val info
1234 $attribs =
1235 array('style' => 'display: none;');
1236 $item['cbox']['value'] =
1237 array(
1238 '#type' => 'textfield',
1239 '#attributes' => $attribs,
1240 '#id' => $shadow_id,
1241 '#default_value' => $val,
1242 );
1243 if ($initialize and !$dojo_init) {
1244 $dojo_init = TRUE;
1245 $dojo_cache = array();
1246 $dojo_lib = _civinode_get_path('dojo_lib');
1247 $configs = "
1248 var djConfig = { isDebug: false };
1249 ";
1250 drupal_add_js($configs, 'inline', 'header');
1251 //add the lib file, cache it
1252 drupal_add_js($dojo_lib, 'module', 'footer');
1253 //activate the widget
1254 $js = "
1255 //alert('test this');
1256 dojo.require('dojo.widget.ComboBox');
1257 ";
1258 drupal_add_js($js, 'inline', 'footer');
1259 }
1260
1261 //and make sure setters get written exactly once
1262 if (!isset($dojo_cache[$setter_func])) {
1263 $dojo_cache[$setter_func] = 1;
1264 _civinode_dojo_render_callback_js($setter_func, $shadow_id, $self_id, $val, $key);
1265 }
1266 return $item;
1267 }
1268
1269 function _civinode_dojo_render_callback_js($funcname, $targ_did, $self_id, $sort_name, $contact_id) {
1270 //TODO add cslashes
1271 $js = "
1272 function $funcname(value) {
1273 var control_did = '$targ_did';
1274 var key_did = '$self_id';
1275 var key_handle = document.getElementById(key_did);
1276 //if (!key_handle)
1277 // alert('No key handle for ' + key_did);
1278 var handle = document.getElementById(control_did);
1279 //alert('$targ_did = ' + value + ', key = ' + key_handle.value);
1280 if (handle) {
1281 handle.value = value;
1282 }
1283 }
1284
1285 function init_$self_id(){
1286 dojo.widget.byId('$self_id').setAllValues('$sort_name', '$contact_id');
1287 document.getElementById('$targ_did').value = '$sort_name';
1288 }
1289 ";
1290 //render this into the header
1291 drupal_add_js($js, 'inline');
1292 if ($sort_name) {
1293 $init_js = "
1294 dojo.addOnLoad(init_$self_id);
1295 ";
1296 //and add it to run deferred
1297 drupal_add_js($init_js, 'inline', 'footer', TRUE);
1298 }
1299 }
1300
1301
1302 function _civinode_dojo_dataurl($group_id = 0) {
1303 //$path = _civinode_get_path('ajax');
1304 //TODO generalized domain_id as set below
1305 $path = base_path() . "civinode/dojo/contact/$group_id";
1306 //$path = "http://crm17dj/civinode/dojo/contact/$group_id";
1307 return $path . "?d=1&s=%{searchString}";
1308 }
1309
1310
1311 function civinode_dojo_widgets($widget_type, $group_id = 0, $size = 6) {
1312 if (_civinode_cck_initialize() and $widget_type == 'contact') {
1313 require_once _civinode_get_path() . "CRM/Utils/Type.php";
1314 $domainID = CRM_Utils_Type::escape( $_GET['d'], 'Integer' );
1315 $name = strtolower( CRM_Utils_Type::escape( $_GET['s'], 'String' ) );
1316
1317 $host = $_SERVER['HTTP_HOST'];
1318 //error_log("Host was $host");
1319
1320 $elements = _civinode_contact_list_by_group($group_id, $size, $name);
1321 //$cnt = count($elements);
1322 //error_log("$cnt elements for grp $group_id and $name");
1323 require_once 'Services/JSON.php';
1324 $json =& new Services_JSON( );
1325 echo $json->encode( $elements );
1326 }
1327 exit();
1328 }
1329
1330 function civinode_group_contact_popup($add_empty = TRUE, $group_id = 0, $size = 10) {
1331 _civinode_cck_initialize();
1332 $elements = _civinode_contact_list_by_group($group_id, $size);
1333 $options = array();
1334 if ($add_empty) {
1335 $options['0'] = t('--select contact--');
1336 }
1337 foreach ($elements as $pair) {
1338 $options[$pair[1]] = $pair[0];
1339 }
1340 return $options;
1341 }
1342
1343
1344 function _civinode_contact_list_by_group($group_id, $size, $name = '') {
1345 //error_log('invoke dojo search');
1346 $params = array();
1347 if ($group_id)
1348 $params['group'] = array($group_id => 1);
1349
1350 //Initialize the contact query
1351 if (!function_exists('crm_create_event')) {
1352 //we are running < 1.7, likely 1.6
1353 require_once 'CRM/Contact/Form/Search.php';
1354 $newP =& CRM_Contact_Form_Search::convertFormValues( $params );
1355