commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / webform_civicrm / includes / utils.inc
1 <?php
2
3 /**
4 * @file
5 * Webform CiviCRM module's common utility functions.
6 */
7
8 /**
9 * Get options for a specific field
10 *
11 * @param array $field
12 * Webform component array
13 * @param string $context
14 * Where is this being called from?
15 * @param array $data
16 * Array of crm entity data
17 *
18 * @return array
19 */
20 function wf_crm_field_options($field, $context, $data) {
21 $ret = array();
22 $fields = wf_crm_get_fields();
23 if ($pieces = wf_crm_explode_key($field['form_key'])) {
24 list( , $c, $ent, $n, $table, $name) = $pieces;
25 // Ensure we have complete info for this field
26 $field += $fields[$table . '_' . $name];
27 if ($name === 'contact_sub_type') {
28 list($contact_types, $sub_types) = wf_crm_get_contact_types();
29 $ret = wf_crm_aval($sub_types, $data['contact'][$c]['contact'][1]['contact_type'], array());
30 }
31 elseif ($name === 'relationship_type_id') {
32 $ret = wf_crm_get_contact_relationship_types($data['contact'][$c]['contact'][1]['contact_type'], $data['contact'][$n]['contact'][1]['contact_type'], $data['contact'][$c]['contact'][1]['contact_sub_type'], $data['contact'][$n]['contact'][1]['contact_sub_type']);
33 }
34 elseif ($name === 'relationship_permission') {
35 $ret = array(
36 1 => t('!a may view and edit !b', array('!a' => wf_crm_contact_label($c, $data, 'plain'), '!b' => wf_crm_contact_label($n, $data, 'plain'))),
37 2 => t('!a may view and edit !b', array('!a' => wf_crm_contact_label($n, $data, 'plain'), '!b' => wf_crm_contact_label($c, $data, 'plain'))),
38 3 => t('Both contacts may view and edit each other'),
39 );
40 }
41 // If this is a contract reference or shared address field, list webform contacts
42 elseif ($name === 'master_id' || wf_crm_aval($field, 'data_type') === 'ContactReference') {
43 $contact_type = wf_crm_aval($field, 'reference_contact_type', 'contact');
44 foreach ($data['contact'] as $num => $contact) {
45 if ($num != $c || $name != 'master_id') {
46 if ($contact_type == 'contact' || $contact_type == $contact['contact'][1]['contact_type']) {
47 $ret[$num] = wf_crm_contact_label($num, $data, 'plain');
48 }
49 }
50 }
51 }
52 elseif ($name == 'privacy') {
53 $ret = wf_crm_get_privacy_options();
54 }
55 elseif ($table === 'other') {
56 if ($field['table'] === 'tag') {
57 $split = explode('_', $name);
58 $ret = CRM_Core_BAO_Tag::getTags("civicrm_{$ent}", $ret, wf_crm_aval($split, 1), '- ');
59 }
60 elseif ($field['table'] === 'group') {
61 $ret = wf_crm_apivalues('group', 'get', array('is_hidden' => 0), 'title');
62 }
63 }
64 elseif ($name === 'survey_id') {
65 $ret = wf_crm_get_surveys(wf_crm_aval($data, "activity:$c:activity:1", array()));
66 }
67 elseif ($name == 'event_id') {
68 $ret = wf_crm_get_events($data['reg_options'], $context);
69 }
70 elseif ($table == 'contribution' && $name == 'is_test') {
71 // Getoptions would return 'yes' and 'no' - this is a bit more descriptive
72 $ret = array(0 => t('Live Transactions'), 1 => t('Test Mode'));
73 }
74 // Not a real field so can't call getoptions for this one
75 elseif ($table == 'membership' && $name == 'num_terms') {
76 $ret = drupal_map_assoc(range(1, 9));
77 }
78 // Aside from the above special cases, most lists can be fetched from api.getoptions
79 else {
80 $params = array('field' => $name, 'context' => 'create');
81 // Custom fields - use main entity
82 if (substr($table, 0, 2) == 'cg') {
83 $table = $ent;
84 }
85 else {
86 // Pass data into api.getoptions for contextual filtering
87 $params += wf_crm_aval($data, "$ent:$c:$table:$n", array());
88 }
89 $ret = wf_crm_apivalues($table, 'getoptions', $params);
90
91 // Hack to format money data correctly
92 if (!empty($field['data_type']) && $field['data_type'] === 'Money') {
93 $old = $ret;
94 $ret = array();
95 foreach ($old as $key => $val) {
96 $ret[number_format(str_replace(',', '', $key), 2, '.', '')] = $val;
97 }
98 }
99 }
100 // Remove options that were set behind the scenes on the admin form
101 if ($context != 'config_form' && !empty($field['extra']['multiple']) && !empty($field['expose_list'])) {
102 foreach (wf_crm_aval($data, "$ent:$c:$table:$n:$name", array()) as $key => $val) {
103 unset($ret[$key]);
104 }
105 }
106 }
107 if (!empty($field['exposed_empty_option'])) {
108 $ret = array(0 => $field['exposed_empty_option']) + $ret;
109 }
110 return $ret;
111 }
112
113 /**
114 * Get list of states, keyed by abbreviation rather than ID.
115 * FIXME use the api for this.
116 * @param null|int|string $param
117 */
118 function wf_crm_get_states($param = NULL) {
119 $ret = array();
120 if (!$param || $param == 'default') {
121 $config = CRM_Core_Config::singleton();
122 if (!$param && !empty($config->provinceLimit)) {
123 $param = implode(',', $config->provinceLimit);
124 }
125 else {
126 $param = (int) $config->defaultContactCountry;
127 }
128 }
129 else {
130 $param = (int) $param;
131 }
132 $sql = "SELECT name AS label, UPPER(abbreviation) AS value FROM civicrm_state_province WHERE country_id IN ($param) ORDER BY name";
133 $dao = CRM_Core_DAO::executeQuery($sql);
134 while ($dao->fetch()) {
135 $ret[$dao->value] = $dao->label;
136 }
137 // Localize the state/province names if in an non-en_US locale
138 $tsLocale = CRM_Utils_System::getUFLocale();
139 if ($tsLocale != '' and $tsLocale != 'en_US') {
140 $i18n = CRM_Core_I18n::singleton();
141 $i18n->localizeArray($ret, array('context' => 'province'));
142 CRM_Utils_Array::asort($ret);
143 }
144 return $ret;
145 }
146
147 /**
148 * Match a state/province id to its abbr. and vice-versa
149 *
150 * @param $input
151 * User input (state province id or abbr)
152 * @param $ret
153 * String: 'abbreviation' or 'id'
154 * @param $country_id
155 * Int: (optional) must be supplied if fetching id from abbr
156 *
157 * @return string or integer
158 */
159 function wf_crm_state_abbr($input, $ret = 'abbreviation', $country_id = NULL) {
160 $input_type = $ret == 'id' ? 'abbreviation' : 'id';
161 $sql = "SELECT $ret FROM civicrm_state_province WHERE $input_type = %1";
162 $vars = array(1 => array($input, $ret == 'id' ? 'String' : 'Integer'));
163 if ($ret === 'id') {
164 if (!$country_id || $country_id === 'default') {
165 $config = CRM_Core_Config::singleton();
166 $country_id = (int) $config->defaultContactCountry;
167 }
168 $sql .= ' AND country_id = %2';
169 $vars[2] = array($country_id, 'Integer');
170 }
171 $sql .= ' LIMIT 0, 1';
172 return CRM_Core_DAO::singleValueQuery($sql, $vars);
173 }
174
175 /**
176 * Get list of events.
177 * FIXME use the api for this.
178 *
179 * @param array $reg_options
180 * @param string $context
181 * @return array
182 */
183 function wf_crm_get_events($reg_options, $context) {
184 $ret = array();
185 $format = wf_crm_aval($reg_options, 'title_display', 'title');
186 $sql = "SELECT id, title, start_date, end_date, event_type_id FROM civicrm_event WHERE is_template = 0 AND is_active = 1";
187 // 'now' means only current events, 1 means show all past events, other values are relative date strings
188 $date_past = wf_crm_aval($reg_options, 'show_past_events', 'now');
189 if ($date_past != '1') {
190 $date_past = date('Y-m-d H:i:s', strtotime($date_past));
191 $sql .= " AND (end_date >= '$date_past' OR end_date IS NULL)";
192 }
193 // 'now' means only past events, 1 means show all future events, other values are relative date strings
194 $date_future = wf_crm_aval($reg_options, 'show_future_events', '1');
195 if ($date_future != '1') {
196 $date_future = date('Y-m-d H:i:s', strtotime($date_future));
197 $sql .= " AND (end_date <= '$date_future' OR end_date IS NULL)";
198 }
199 if (is_numeric($reg_options['event_type'])) {
200 $sql .= ' AND event_type_id = ' . $reg_options['event_type'];
201 }
202 $sql .= ' ORDER BY start_date ' . ($context == 'config_form' ? 'DESC' : '');
203 $dao = CRM_Core_DAO::executeQuery($sql);
204 while ($dao->fetch()) {
205 $ret[$dao->id . '-' . $dao->event_type_id] = wf_crm_format_event($dao, $format);
206 }
207 return $ret;
208 }
209
210 /**
211 * @param array|object $event
212 * @param string $format
213 * @return string
214 */
215 function wf_crm_format_event($event, $format) {
216 $format = explode(' ', $format);
217 // Date format
218 foreach ($format as $value) {
219 if (strpos($value, 'dateformat') === 0) {
220 $config = CRM_Core_Config::singleton();
221 $date_format = $config->$value;
222 }
223 }
224 $event = (object) $event;
225 $title = array();
226 if (in_array('title', $format)) {
227 $title[] = $event->title;
228 }
229 if (in_array('type', $format)) {
230 $types = wf_crm_apivalues('event', 'getoptions', array('field' => 'event_type_id', 'context' => 'get'));
231 $title[] = $types[$event->event_type_id];
232 }
233 if (in_array('start', $format) && $event->start_date) {
234 $title[] = CRM_Utils_Date::customFormat($event->start_date, $date_format);
235 }
236 if (in_array('end', $format) && $event->end_date) {
237 // Avoid showing redundant end-date if it is the same as the start date
238 $same_day = substr($event->start_date, 0, 10) == substr($event->end_date, 0, 10);
239 if (!$same_day || in_array('dateformatDatetime', $format) || in_array('dateformatTime', $format)) {
240 $end_format = (in_array('dateformatDatetime', $format) && $same_day) ? $config->dateformatTime : $date_format;
241 $title[] = CRM_Utils_Date::customFormat($event->end_date, $end_format);
242 }
243 }
244 return implode(' - ', $title);
245 }
246
247 /**
248 * Get list of surveys
249 * @param array $act
250 *
251 * @return array
252 */
253 function wf_crm_get_surveys($act = array()) {
254 return wf_crm_apivalues('survey', 'get', array_filter($act), 'title');
255 }
256
257 /**
258 * Get list of activity types
259 * @param string $case_type_name
260 * @param array $campaign_act_types
261 *
262 * @return array
263 */
264 function wf_crm_get_activity_types($case_type_name, &$campaign_act_types) {
265 // Return activities only appropriate to this case
266 if ($case_type_name) {
267 $case_info = new CRM_Case_XMLProcessor_Process();
268 return $case_info->get($case_type_name, 'ActivityTypes');
269 }
270 // Fetch activity types from the api
271 $params = array(
272 'option_group_id' => 'activity_type',
273 'is_active' => 1,
274 'options' => array(
275 'order' => 'label',
276 ),
277 );
278 // Include campaign types if CiviCampaign is enabled
279 $comp = CRM_Core_Component::getEnabledComponents();
280 $campaign_type = wf_crm_aval($comp, 'CiviCampaign:componentID');
281
282 $ret = array();
283 foreach (wf_crm_apivalues('option_value', 'get', $params) as $val) {
284 if (empty($val['component_id'])) {
285 $ret[$val['value']] = $val['label'];
286 }
287 elseif ($val['component_id'] == $campaign_type) {
288 $campaign_act_types[$val['value']] = $ret[$val['value']] = $val['label'];
289 }
290 }
291
292 return $ret;
293 }
294
295 /**
296 * Get activity types related to CiviCampaign
297 * @return array
298 */
299 function wf_crm_get_campaign_activity_types() {
300 $ret = array();
301 if (array_key_exists('activity_survey_id', wf_crm_get_fields())) {
302 $vals = wf_crm_apivalues('option_value', 'get', array(
303 'option_group_id' => 'activity_type',
304 'is_active' => 1,
305 'component_id' => 'CiviCampaign',
306 ));
307 foreach ($vals as $val) {
308 $ret[$val['value']] = $val['label'];
309 }
310 }
311 return $ret;
312 }
313
314 /**
315 * Get contact types and sub-types
316 * Unlike pretty much every other option list CiviCRM wants "name" instead of "id"
317 *
318 * @return array
319 */
320 function wf_crm_get_contact_types() {
321 static $contact_types = array();
322 static $sub_types = array();
323 if (!$contact_types) {
324 $data = wf_crm_apivalues('contact_type', 'get', array('is_active' => 1));
325 foreach ($data as $type) {
326 if (empty($type['parent_id'])) {
327 $contact_types[strtolower($type['name'])] = $type['label'];
328 continue;
329 }
330 $sub_types[strtolower($data[$type['parent_id']]['name'])][$type['name']] = $type['label'];
331 }
332 }
333 return array($contact_types, $sub_types);
334 }
335
336 /**
337 * In reality there is no contact field 'privacy' so this is not a real option list.
338 * These are actually 5 separate contact fields that this module munges into 1 for better usability.
339 *
340 * @return array
341 */
342 function wf_crm_get_privacy_options() {
343 return array(
344 'do_not_email' => ts('Do not email'),
345 'do_not_phone' => ts('Do not phone'),
346 'do_not_mail' => ts('Do not mail'),
347 'do_not_sms' => ts('Do not sms'),
348 'do_not_trade' => ts('Do not trade'),
349 'is_opt_out' => ts('NO BULK EMAILS (User Opt Out)'),
350 );
351 }
352
353 /**
354 * Get relationship type data
355 *
356 * @return array
357 */
358 function wf_crm_get_relationship_types() {
359 static $types = array();
360 if (!$types) {
361 foreach (wf_crm_apivalues('relationship_type', 'get', array('is_active' => 1)) as $r) {
362 $r['type_a'] = strtolower(wf_crm_aval($r, 'contact_type_a'));
363 $r['type_b'] = strtolower(wf_crm_aval($r, 'contact_type_b'));
364 $r['sub_type_a'] = wf_crm_aval($r, 'contact_sub_type_a');
365 $r['sub_type_b'] = wf_crm_aval($r, 'contact_sub_type_b');
366 $types[$r['id']] = $r;
367 }
368 }
369 return $types;
370 }
371
372 /**
373 * Get valid relationship types for a given pair of contacts
374 *
375 * @param $type_a
376 * Contact type
377 * @param $type_b
378 * Contact type
379 * @param $sub_type_a
380 * Contact sub-type
381 * @param $sub_type_b
382 * Contact sub-type
383 *
384 * @return array
385 */
386 function wf_crm_get_contact_relationship_types($type_a, $type_b, $sub_type_a, $sub_type_b) {
387 $ret = array();
388 foreach (wf_crm_get_relationship_types() as $t) {
389 $reciprocal = ($t['label_a_b'] != $t['label_b_a'] && $t['label_b_a'] || $t['type_a'] != $t['type_b']);
390 if (($t['type_a'] == $type_a || !$t['type_a'])
391 && ($t['type_b'] == $type_b || !$t['type_b'])
392 && (in_array($t['sub_type_a'], $sub_type_a) || !$t['sub_type_a'])
393 && (in_array($t['sub_type_b'], $sub_type_b) || !$t['sub_type_b'])
394 ) {
395 $ret[$t['id'] . ($reciprocal ? '_a' : '_r')] = $t['label_a_b'];
396 }
397 // Reciprocal form - only show if different from above
398 if ($reciprocal
399 && ($t['type_a'] == $type_b || !$t['type_a'])
400 && ($t['type_b'] == $type_a || !$t['type_b'])
401 && (in_array($t['sub_type_a'], $sub_type_b) || !$t['sub_type_a'])
402 && (in_array($t['sub_type_b'], $sub_type_a) || !$t['sub_type_b'])
403 ) {
404 $ret[$t['id'] . '_b'] = $t['label_b_a'];
405 }
406 }
407 return $ret;
408 }
409
410 /**
411 * List dedupe rules available for a contact type
412 *
413 * @param string $contact_type
414 * @return array
415 */
416 function wf_crm_get_matching_rules($contact_type) {
417 static $rules;
418 $contact_type = ucfirst($contact_type);
419 if (!$rules) {
420 $rules = array_fill_keys(array('Individual', 'Organization', 'Household'), array());
421 $dao = CRM_Core_DAO::executeQuery('SELECT * FROM civicrm_dedupe_rule_group');
422 while ($dao->fetch()) {
423 $rules[$dao->contact_type][$dao->id] = $dao->title;
424 }
425 }
426 return $rules[$contact_type];
427 }
428
429 /**
430 * Get ids or values of enabled CiviCRM fields for a webform.
431 *
432 * @param stdClass $node
433 * Node object
434 * @param array|null $submission
435 * (optional) if supplied, will match field keys with submitted values
436 * @param boolean $show_all
437 * (optional) if true, get every field even if it belongs to a contact that does not exist
438 *
439 * @return array of enabled fields
440 */
441 function wf_crm_enabled_fields($node, $submission = NULL, $show_all = FALSE) {
442 $enabled = array();
443 if (!empty($node->webform['components']) && (!empty($node->webform_civicrm) || $show_all)) {
444 $fields = wf_crm_get_fields();
445 foreach ($node->webform['components'] as $c) {
446 $exp = explode('_', $c['form_key'], 5);
447 if (count($exp) == 5) {
448 list($lobo, $i, $ent, $n, $id) = $exp;
449 if ((isset($fields[$id]) || $id == 'fieldset_fieldset') && $lobo == 'civicrm' && is_numeric($i) && is_numeric($n)) {
450 if (!$show_all && ($ent == 'contact' || $ent == 'participant') && empty($node->webform_civicrm['data']['contact'][$i])) {
451 continue;
452 }
453 if ($submission) {
454 $enabled[$c['form_key']] = wf_crm_aval($submission, $c['cid'], NULL, TRUE);
455 }
456 else {
457 $enabled[$c['form_key']] = $c['cid'];
458 }
459 }
460 }
461 }
462 }
463 return $enabled;
464 }
465
466 /**
467 * Fetches CiviCRM field data.
468 *
469 * @param string $var
470 * Name of variable to return: fields, tokens, or sets
471 *
472 * @return array
473 * fields: The CiviCRM contact fields this module supports
474 * tokens: Available tokens keyed to field ids
475 * sets: Info on fieldsets (entities)
476 */
477 function wf_crm_get_fields($var = 'fields') {
478 static $fields = array();
479 static $tokens;
480 static $sets;
481
482 if (!$fields) {
483 $config = CRM_Core_Config::singleton();
484 $components = $config->enableComponents;
485
486 $sets = array(
487 'contact' => array('entity_type' => 'contact', 'label' => t('Contact Fields')),
488 'other' => array('entity_type' => 'contact', 'label' => t('Tags and Groups'), 'max_instances' => 1),
489 'address' => array('entity_type' => 'contact', 'label' => t('Address'), 'max_instances' => 9),
490 'phone' => array('entity_type' => 'contact', 'label' => t('Phone'), 'max_instances' => 9),
491 'email' => array('entity_type' => 'contact', 'label' => t('Email'), 'max_instances' => 9),
492 'website' => array('entity_type' => 'contact', 'label' => t('Website'), 'max_instances' => 9),
493 'im' => array('entity_type' => 'contact', 'label' => t('Instant Message'), 'max_instances' => 9),
494 'activity' => array('entity_type' => 'activity', 'label' => t('Activity'), 'max_instances' => 30, 'attachments' => TRUE),
495 'relationship' => array('entity_type' => 'contact', 'label' => t('Relationship'), 'help_text' => TRUE),
496 );
497 $conditional_sets = array(
498 'CiviCase' => array('entity_type' => 'case', 'label' => t('Case Settings'), 'max_instances' => 30),
499 'CiviEvent' => array('entity_type' => 'participant', 'label' => t('Participant'), 'max_instances' => 9),
500 'CiviContribute' => array('entity_type' => 'contribution', 'label' => t('Contribution')),
501 'CiviMember' => array('entity_type' => 'membership', 'label' => t('Membership')),
502 'CiviGrant' => array('entity_type' => 'grant', 'label' => t('Grant'), 'max_instances' => 30, 'attachments' => TRUE),
503 );
504 foreach ($conditional_sets as $component => $set) {
505 if (in_array($component, $components)) {
506 $sets[$set['entity_type']] = $set;
507 }
508 }
509
510 $moneyDefaults = array(
511 'type' => 'number',
512 'data_type' => 'Money',
513 'extra' => array(
514 'field_prefix' => wf_crm_aval($config, 'defaultCurrencySymbol', '$'),
515 'point' => wf_crm_aval($config, 'monetaryDecimalPoint', '.'),
516 'separator' => wf_crm_aval($config, 'monetaryThousandSeparator', ','),
517 'decimals' => 2,
518 'min' => 0,
519 ),
520 );
521
522 // Field keys are in the format table_column
523 // Use a # sign as a placeholder for field number in the title (or by default it will be appended to the end)
524 // Setting 'expose_list' allows the value to be set on the config form
525 // Set label for 'empty_option' for exposed lists that do not require input
526 $fields['contact_contact_sub_type'] = array(
527 'name' => t('Type of @contact'),
528 'type' => 'select',
529 'extra' => array('multiple' => 1, 'civicrm_live_options' => 1),
530 'expose_list' => TRUE,
531 );
532 $fields['contact_existing'] = array(
533 'name' => t('Existing Contact'),
534 'type' => 'civicrm_contact',
535 'extra' => array(
536 'search_prompt' => t('- Choose existing -'),
537 ),
538 );
539 // Organization / household names
540 foreach (array('organization' => t('Organization Name'), 'legal' => t('Legal Name'), 'household' => t('Household Name')) as $key => $label) {
541 $fields['contact_' . $key . '_name'] = array(
542 'name' => $label,
543 'type' => 'textfield',
544 'contact_type' => $key == 'household' ? 'household' : 'organization',
545 );
546 }
547 $fields['contact_sic_code'] = array(
548 'name' => t('SIC Code'),
549 'type' => 'textfield',
550 'contact_type' => 'organization',
551 );
552 // Individual names
553 if (version_compare(CRM_Utils_System::version(), '4.5', '<')) {
554 // This setting doesn't exist prior to 4.5 so hard-code it.
555 $enabled_names = array('Prefix', 'Suffix', 'First Name', 'Middle Name', 'Last Name');
556 }
557 else {
558 $enabled_names = wf_crm_explode_multivalue_str(CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_edit_options'));
559 $name_options = CRM_Core_OptionGroup::values('contact_edit_options', FALSE, FALSE, FALSE, NULL, 'name');
560 $enabled_names = array_intersect_key($name_options, array_flip($enabled_names));
561 }
562 foreach (array('prefix_id' => t('Name Prefix'), 'formal_title' => t('Formal Title'), 'first_name' => t('First Name'), 'middle_name' => t('Middle Name'), 'last_name' => t('Last Name'), 'suffix_id' => t('Name Suffix')) as $key => $label) {
563 if (in_array(ucwords(str_replace(array('_id', '_'), array('', ' '), $key)), $enabled_names)) {
564 $fields['contact_' . $key] = array(
565 'name' => $label,
566 'type' => strpos($key, '_id') ? 'select' : 'textfield',
567 'contact_type' => 'individual',
568 );
569 }
570 }
571 $fields['contact_nick_name'] = array(
572 'name' => t('Nickname'),
573 'type' => 'textfield',
574 );
575 $fields['contact_gender_id'] = array(
576 'name' => t('Gender'),
577 // Gender should be textfield if using https://civicrm.org/extensions/gender-self-identify
578 'type' => function_exists('genderselfidentify_civicrm_apiWrappers') ? 'textfield' : 'select',
579 'contact_type' => 'individual',
580 );
581 $fields['contact_job_title'] = array(
582 'name' => t('Job Title'),
583 'type' => 'textfield',
584 'contact_type' => 'individual',
585 );
586 $fields['contact_birth_date'] = array(
587 'name' => t('Birth Date'),
588 'type' => 'date',
589 'extra' => array(
590 'start_date' => '-100 years',
591 'end_date' => 'now',
592 ),
593 'contact_type' => 'individual',
594 );
595 $fields['contact_preferred_communication_method'] = array(
596 'name' => t('Preferred Communication Method(s)'),
597 'type' => 'select',
598 'extra' => array('multiple' => 1),
599 );
600 $fields['contact_privacy'] = array(
601 'name' => t('Privacy Preferences'),
602 'type' => 'select',
603 'extra' => array('multiple' => 1),
604 );
605 $fields['contact_preferred_language'] = array(
606 'name' => t('Preferred Language'),
607 'type' => 'select',
608 'value' => $config->lcMessages,
609 );
610 if (array_key_exists('file', webform_components())) {
611 $fields['contact_image_URL'] = array(
612 'name' => t('Upload Image'),
613 'type' => 'file',
614 'extra' => array('width' => 40),
615 'data_type' => 'File',
616 );
617 }
618 $fields['contact_contact_id'] = array(
619 'name' => t('Contact ID'),
620 'type' => 'hidden',
621 );
622 $fields['contact_external_identifier'] = array(
623 'name' => t('External ID'),
624 'type' => 'hidden',
625 );
626 $fields['contact_source'] = array(
627 'name' => t('Source'),
628 'type' => 'textfield',
629 );
630 $fields['contact_cs'] = array(
631 'name' => t('Checksum'),
632 'type' => 'hidden',
633 'value_callback' => TRUE,
634 );
635 $fields['contact_employer_id'] = array(
636 'name' => t('Current Employer'),
637 'type' => 'select',
638 'expose_list' => TRUE,
639 'empty_option' => t('None'),
640 'data_type' => 'ContactReference',
641 'contact_type' => 'individual',
642 'reference_contact_type' => 'organization'
643 );
644 $fields['contact_is_deceased'] = array(
645 'name' => t('Is Deceased'),
646 'type' => 'select',
647 'extra' => array('aslist' => 0),
648 'contact_type' => 'individual',
649 );
650 $fields['contact_deceased_date'] = array(
651 'name' => t('Deceased Date'),
652 'type' => 'date',
653 'extra' => array(
654 'start_date' => '-100 years',
655 'end_date' => 'now',
656 ),
657 'contact_type' => 'individual',
658 );
659 $fields['email_email'] = array(
660 'name' => t('Email'),
661 'type' => 'email',
662 );
663 foreach (array('street_address' => t('Street Address'), 'supplemental_address_1' => t('Street Address # Line 2'), 'supplemental_address_2' => t('Street Address # Line 3'), 'city' => t('City')) as $key => $value) {
664 $fields['address_' . $key] = array(
665 'name' => $value,
666 'type' => 'textfield',
667 'extra' => array('width' => $key == 'city' ? 20 : 60),
668 );
669 }
670 $fields['address_postal_code'] = array(
671 'name' => t('Postal Code'),
672 'type' => 'textfield',
673 'extra' => array('width' => 7),
674 );
675 $fields['address_postal_code_suffix'] = array(
676 'name' => t('Postal Code Suffix'),
677 'type' => 'textfield',
678 'extra' => array(
679 'width' => 5,
680 'description' => t('+4 digits of Zip Code'),
681 ),
682 );
683 $fields['address_country_id'] = array(
684 'name' => t('Country'),
685 'type' => 'select',
686 'extra' => array('civicrm_live_options' => 1),
687 'value' => $config->defaultContactCountry,
688 );
689 $fields['address_state_province_id'] = array(
690 'name' => t('State/Province'),
691 'type' => 'textfield',
692 'extra' => array(
693 'maxlength' => 5,
694 'width' => 4,
695 ),
696 'data_type' => 'state_province_abbr',
697 );
698 $fields['address_county_id'] = array(
699 'name' => t('District/County'),
700 'type' => 'textfield',
701 );
702 $fields['address_master_id'] = array(
703 'name' => t('Share address of'),
704 'type' => 'select',
705 'expose_list' => TRUE,
706 'extra' => array('aslist' => 0),
707 'empty_option' => t('Do Not Share'),
708 );
709 $fields['phone_phone'] = array(
710 'name' => t('Phone Number'),
711 'type' => 'textfield',
712 );
713 $fields['phone_phone_ext'] = array(
714 'name' => t('Phone Extension'),
715 'type' => 'textfield',
716 'extra' => array(
717 'width' => 4,
718 ),
719 );
720 $fields['phone_phone_type_id'] = array(
721 'name' => t('Phone # Type'),
722 'type' => 'select',
723 'table' => 'phone',
724 'expose_list' => TRUE,
725 );
726 $fields['im_name'] = array(
727 'name' => t('Screen Name'),
728 'type' => 'textfield',
729 );
730 $fields['im_provider_id'] = array(
731 'name' => t('IM Provider'),
732 'type' => 'select',
733 'expose_list' => TRUE,
734 );
735 foreach (array('address' => t('Address # Location'), 'phone' => t('Phone # Location'), 'email' => t('Email # Location'), 'im' => t('IM # Location')) as $key => $label) {
736 if (isset($sets[$key])) {
737 $fields[$key . '_location_type_id'] = array(
738 'name' => $label,
739 'type' => 'select',
740 'expose_list' => TRUE,
741 'value' => '1',
742 );
743 }
744 }
745 $fields['website_url'] = array(
746 'name' => t('Website'),
747 'type' => 'textfield',
748 'data_type' => 'Link',
749 );
750 $fields['website_website_type_id'] = array(
751 'name' => t('Website # Type'),
752 'type' => 'select',
753 'expose_list' => TRUE,
754 );
755 $fields['other_group'] = array(
756 'name' => t('Group(s)'),
757 'type' => 'select',
758 'extra' => array('multiple' => 1, 'civicrm_live_options' => 1),
759 'table' => 'group',
760 'expose_list' => TRUE,
761 );
762 $tagsets = array('' => t('Tag(s)')) + CRM_Core_BAO_Tag::getTagSet('civicrm_contact');
763 foreach ($tagsets as $pid => $name) {
764 $fields['other_tag' . ($pid ? "_$pid" : '')] = array(
765 'name' => $name,
766 'type' => 'select',
767 'extra' => array('multiple' => 1, 'civicrm_live_options' => 1),
768 'table' => 'tag',
769 'expose_list' => TRUE,
770 );
771 }
772 $fields['activity_activity_type_id'] = array(
773 'name' => t('Activity # Type'),
774 'type' => 'select',
775 'expose_list' => TRUE,
776 );
777 $fields['activity_target_contact_id'] = array(
778 'name' => t('Activity # Participant(s)'),
779 'type' => 'select',
780 'expose_list' => TRUE,
781 'extra' => array(
782 'multiple' => 1,
783 ),
784 'data_type' => 'ContactReference',
785 );
786 $fields['activity_source_contact_id'] = array(
787 'name' => t('Activity # Creator'),
788 'type' => 'select',
789 'expose_list' => TRUE,
790 'data_type' => 'ContactReference',
791 'exposed_empty_option' => '- ' . t('Automatic') . ' -',
792 );
793 $fields['activity_subject'] = array(
794 'name' => t('Activity # Subject'),
795 'type' => 'textfield',
796 );
797 $fields['activity_details'] = array(
798 'name' => t('Activity # Details'),
799 'type' => module_exists('webform_html_textarea') ? 'html_textarea' : 'textarea',
800 );
801 $fields['activity_status_id'] = array(
802 'name' => t('Activity # Status'),
803 'type' => 'select',
804 'expose_list' => TRUE,
805 'exposed_empty_option' => '- ' . t('Automatic') . ' -',
806 );
807 $fields['activity_priority_id'] = array(
808 'name' => t('Activity # Priority'),
809 'type' => 'select',
810 'expose_list' => TRUE,
811 'exposed_empty_option' => '- ' . t('Automatic') . ' -',
812 );
813 $fields['activity_assignee_contact_id'] = array(
814 'name' => t('Assign Activity # to'),
815 'type' => 'select',
816 'expose_list' => TRUE,
817 'empty_option' => t('No One'),
818 'data_type' => 'ContactReference',
819 );
820 $fields['activity_location'] = array(
821 'name' => t('Activity # Location'),
822 'type' => 'textfield',
823 );
824 $fields['activity_activity_date_time'] = array(
825 'name' => t('Activity # Date'),
826 'type' => 'date',
827 'value' => 'now',
828 );
829 $fields['activity_activity_date_time_timepart'] = array(
830 'name' => t('Activity # Time'),
831 'type' => 'time',
832 'value' => 'now',
833 );
834 $fields['activity_duration'] = array(
835 'name' => t('Activity # Duration'),
836 'type' => 'number',
837 'extra' => array(
838 'field_suffix' => t('min.'),
839 'min' => 0,
840 'step' => 5,
841 'integer' => 1,
842 ),
843 );
844 if (isset($sets['case'])) {
845 $case_info = new CRM_Case_XMLProcessor_Process();
846 $fields['case_case_type_id'] = array(
847 'name' => t('Case # Type'),
848 'type' => 'select',
849 'expose_list' => TRUE,
850 );
851 $fields['case_client_id'] = array(
852 'name' => t('Case # Client'),
853 'type' => 'select',
854 'expose_list' => TRUE,
855 'extra' => array('required' => 1, 'multiple' => $case_info->getAllowMultipleCaseClients()),
856 'data_type' => 'ContactReference',
857 'set' => 'caseRoles',
858 'value' => 1,
859 );
860 $fields['case_status_id'] = array(
861 'name' => t('Case # Status'),
862 'type' => 'select',
863 'expose_list' => TRUE,
864 'exposed_empty_option' => '- ' . t('Automatic') . ' -',
865 );
866 $fields['case_medium_id'] = array(
867 'name' => t('Medium'),
868 'type' => 'select',
869 'expose_list' => TRUE,
870 );
871 $fields['case_subject'] = array(
872 'name' => t('Case # Subject'),
873 'type' => 'textfield',
874 );
875 $fields['case_creator_id'] = array(
876 'name' => t('Case # Creator'),
877 'type' => 'select',
878 'expose_list' => TRUE,
879 'data_type' => 'ContactReference',
880 'set' => 'caseRoles',
881 'exposed_empty_option' => '- ' . t('Automatic') . ' -',
882 );
883 // Fetch case roles
884 $sets['caseRoles'] = array('entity_type' => 'case', 'label' => t('Case Roles'));
885 // Use the vanilla civicrm_api for this because it will throw an error in CiviCRM 4.4 (api doesn't exist)
886 $case_types = civicrm_api('case_type', 'get', array('version' => 3, 'options' => array('limit' => 0)));
887 foreach (wf_crm_aval($case_types, 'values', array()) as $case_type) {
888 foreach ($case_type['definition']['caseRoles'] as $role) {
889 foreach (wf_crm_get_relationship_types() as $rel_type) {
890 if ($rel_type['name_b_a'] == $role['name']) {
891 if (!isset($fields['case_role_' . $rel_type['id']])) {
892 $fields['case_role_' . $rel_type['id']] = array(
893 'name' => $rel_type['label_b_a'],
894 'type' => 'select',
895 'expose_list' => TRUE,
896 'data_type' => 'ContactReference',
897 'set' => 'caseRoles',
898 'empty_option' => t('None'),
899 );
900 }
901 $fields['case_role_' . $rel_type['id']]['case_types'][] = $case_type['id'];
902 break;
903 }
904 }
905 }
906 }
907 }
908 $fields['relationship_relationship_type_id'] = array(
909 'name' => t('Relationship Type(s)'),
910 'type' => 'select',
911 'expose_list' => TRUE,
912 'extra' => array(
913 'civicrm_live_options' => 1,
914 'multiple' => 1,
915 ),
916 );
917 $fields['relationship_is_active'] = array(
918 'name' => t('Is Active'),
919 'type' => 'select',
920 'expose_list' => TRUE,
921 'value' => '1',
922 );
923 $fields['relationship_relationship_permission'] = array(
924 'name' => t('Permissions'),
925 'type' => 'select',
926 'expose_list' => TRUE,
927 'empty_option' => t('No Permissions'),
928 );
929 $fields['relationship_start_date'] = array(
930 'name' => t('Start Date'),
931 'type' => 'date',
932 'extra' => array(
933 'start_date' => '-50 years',
934 'end_date' => '+10 years',
935 ),
936 );
937 $fields['relationship_end_date'] = array(
938 'name' => t('End Date'),
939 'type' => 'date',
940 'extra' => array(
941 'start_date' => '-50 years',
942 'end_date' => '+10 years',
943 ),
944 );
945 $fields['relationship_description'] = array(
946 'name' => t('Description'),
947 'type' => 'textarea',
948 );
949 if (isset($sets['contribution'])) {
950 $fields['contribution_contribution_page_id'] = array(
951 'name' => ts('Contribution Page'),
952 'type' => 'hidden',
953 'expose_list' => TRUE,
954 'empty_option' => t('None'),
955 'extra' => array(
956 'hidden_type' => 'hidden',
957 ),
958 'weight' => 9999,
959 );
960 $fields['contribution_total_amount'] = array(
961 'name' => t('Contribution Amount'),
962 'weight' => 9991,
963 ) + $moneyDefaults;
964 $fields['contribution_payment_processor_id'] = array(
965 'name' => t('Payment Processor'),
966 'type' => 'select',
967 'expose_list' => TRUE,
968 'extra' => array('aslist' => 0),
969 'exposed_empty_option' => t('Pay Later'),
970 'value_callback' => TRUE,
971 'weight' => 9995,
972 );
973 $fields['contribution_note'] = array(
974 'name' => t('Contribution Note'),
975 'type' => 'textarea',
976 'weight' => 9993,
977 );
978 $fields['contribution_soft'] = array(
979 'name' => t('Soft Credit To'),
980 'type' => 'select',
981 'expose_list' => TRUE,
982 'extra' => array('multiple' => TRUE),
983 'data_type' => 'ContactReference',
984 );
985 $fields['contribution_honor_contact_id'] = array(
986 'name' => t('In Honor/Memory of'),
987 'type' => 'select',
988 'expose_list' => TRUE,
989 'empty_option' => t('No One'),
990 'data_type' => 'ContactReference',
991 );
992 $fields['contribution_honor_type_id'] = array(
993 'name' => t('Honoree Type'),
994 'type' => 'select',
995 'expose_list' => TRUE,
996 );
997 $fields['contribution_is_test'] = array(
998 'name' => t('Payment Processor Mode'),
999 'type' => 'select',
1000 'expose_list' => TRUE,
1001 'extra' => array('civicrm_live_options' => 1),
1002 'value' => 0,
1003 'weight' => 9997,
1004 );
1005 $fields['contribution_source'] = array(
1006 'name' => t('Contribution Source'),
1007 'type' => 'textfield',
1008 );
1009 }
1010 if (isset($sets['participant'])) {
1011 $fields['participant_event_id'] = array(
1012 'name' => t('Event(s)'),
1013 'type' => 'select',
1014 'extra' => array('multiple' => 1, 'civicrm_live_options' => 1),
1015 'expose_list' => TRUE,
1016 );
1017 $fields['participant_role_id'] = array(
1018 'name' => t('Participant Role'),
1019 'type' => 'select',
1020 'expose_list' => TRUE,
1021 'value' => '1',
1022 'extra' => array('multiple' => 1, 'required' => 1),
1023 );
1024 $fields['participant_status_id'] = array(
1025 'name' => t('Registration Status'),
1026 'type' => 'select',
1027 'expose_list' => TRUE,
1028 'value' => 0,
1029 'exposed_empty_option' => '- ' . t('Automatic') . ' -',
1030 );
1031 if (isset($sets['contribution'])) {
1032 $fields['participant_fee_amount'] = array(
1033 'name' => t('Participant Fee'),
1034 ) + $moneyDefaults;
1035 }
1036 }
1037 if (isset($sets['membership'])) {
1038 $fields['membership_membership_type_id'] = array(
1039 'name' => t('Membership Type'),
1040 'type' => 'select',
1041 'expose_list' => TRUE,
1042 'extra' => array('civicrm_live_options' => 1),
1043 );
1044 $fields['membership_status_id'] = array(
1045 'name' => t('Membership Status'),
1046 'type' => 'select',
1047 'expose_list' => TRUE,
1048 'value' => 0,
1049 'exposed_empty_option' => '- ' . t('Automatic') . ' -',
1050 );
1051 $fields['membership_num_terms'] = array(
1052 'name' => t('Number of Terms'),
1053 'type' => 'select',
1054 'expose_list' => TRUE,
1055 'value' => 1,
1056 'empty_option' => t('Enter Dates Manually'),
1057 );
1058 if (isset($sets['contribution'])) {
1059 $fields['membership_fee_amount'] = array(
1060 'name' => t('Membership Fee'),
1061 ) + $moneyDefaults;
1062 }
1063 $fields['membership_join_date'] = array(
1064 'name' => t('Member Since'),
1065 'type' => 'date',
1066 );
1067 $fields['membership_start_date'] = array(
1068 'name' => t('Start Date'),
1069 'type' => 'date',
1070 );
1071 $fields['membership_end_date'] = array(
1072 'name' => t('End Date'),
1073 'type' => 'date',
1074 );
1075 }
1076 // Add campaign fields
1077 if (in_array('CiviCampaign', $components)) {
1078 $fields['activity_engagement_level'] = array(
1079 'name' => t('Engagement Level'),
1080 'type' => 'select',
1081 'empty_option' => t('None'),
1082 'expose_list' => TRUE,
1083 );
1084 $fields['activity_survey_id'] = array(
1085 'name' => t('Survey/Petition'),
1086 'type' => 'select',
1087 'expose_list' => TRUE,
1088 'empty_option' => t('None'),
1089 'extra' => array('civicrm_live_options' => 1),
1090 );
1091 foreach (array_intersect(array('activity', 'membership', 'participant', 'contribution'), array_keys($sets)) as $ent) {
1092 $fields[$ent . '_campaign_id'] = array(
1093 'name' => t('Campaign'),
1094 'type' => 'select',
1095 'expose_list' => TRUE,
1096 'extra' => array('civicrm_live_options' => 1),
1097 'empty_option' => t('None'),
1098 );
1099 }
1100 }
1101 // CiviGrant fields
1102 if (isset($sets['grant'])) {
1103 $fields['grant_contact_id'] = array(
1104 'name' => t('Grant Applicant'),
1105 'type' => 'select',
1106 'expose_list' => TRUE,
1107 'data_type' => 'ContactReference',
1108 );
1109 $fields['grant_grant_type_id'] = array(
1110 'name' => t('Grant Type'),
1111 'type' => 'select',
1112 'expose_list' => TRUE,
1113 'extra' => array('civicrm_live_options' => 1),
1114 );
1115 $fields['grant_status_id'] = array(
1116 'name' => t('Grant Status'),
1117 'type' => 'select',
1118 'expose_list' => TRUE,
1119 'value' => 0,
1120 'exposed_empty_option' => '- ' . t('Automatic') . ' -',
1121 );
1122 $fields['grant_application_received_date'] = array(
1123 'name' => t('Application Received Date'),
1124 'type' => 'date',
1125 );
1126 $fields['grant_decision_date'] = array(
1127 'name' => t('Decision Date'),
1128 'type' => 'date',
1129 );
1130 $fields['grant_money_transfer_date'] = array(
1131 'name' => t('Money Transfer Date'),
1132 'type' => 'date',
1133 );
1134 $fields['grant_grant_due_date'] = array(
1135 'name' => t('Grant Report Due'),
1136 'type' => 'date',
1137 );
1138 $fields['grant_grant_report_received'] = array(
1139 'name' => t('Grant Report Received?'),
1140 'type' => 'select',
1141 'extra' => array('aslist' => 0),
1142 );
1143 $fields['grant_rationale'] = array(
1144 'name' => t('Grant Rationale'),
1145 'type' => 'textarea',
1146 );
1147 $fields['grant_note'] = array(
1148 'name' => t('Grant Notes'),
1149 'type' => 'textarea',
1150 );
1151 $fields['grant_amount_total'] = array(
1152 'name' => t('Amount Requested'),
1153 ) + $moneyDefaults;
1154 $fields['grant_amount_granted'] = array(
1155 'name' => t('Amount Granted'),
1156 ) + $moneyDefaults;
1157 }
1158
1159 // File attachment fields
1160 $numAttachments = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'max_attachments');
1161 foreach ($sets as $ent => $set) {
1162 if (!empty($set['attachments']) && $numAttachments) {
1163 $sets["{$ent}upload"] = array(
1164 'label' => t('File Attachments'),
1165 'entity_type' => $ent,
1166 );
1167 for ($i = 1; $i <= $numAttachments; $i++) {
1168 $fields["{$ent}upload_file_$i"] = array(
1169 'name' => t('Attachment !num', array('!num' => $i)),
1170 'type' => 'file',
1171 'data_type' => 'File',
1172 );
1173 }
1174 }
1175 }
1176
1177 $tokens = array(
1178 'display_name' => t('display name'),
1179 'first_name' => t('first name'),
1180 'nick_name' => t('nickname'),
1181 'middle_name' => t('middle name'),
1182 'last_name' => t('last name'),
1183 'individual_prefix' => t('name prefix'),
1184 'individual_suffix' => t('name suffix'),
1185 'gender' => t('gender'),
1186 'birth_date' => t('birth date'),
1187 'job_title' => t('job title'),
1188 'current_employer' => t('current employer'),
1189 'contact_id' => t('contact id'),
1190 'street_address' => t('street address'),
1191 'city' => t('city'),
1192 'state_province' => t('state/province abbr'),
1193 'state_province_name' => t('state/province full'),
1194 'postal_code' => t('postal code'),
1195 'country' => t('country'),
1196 'world_region' => t('world region'),
1197 'phone' => t('phone number'),
1198 'email' => t('email'),
1199 );
1200
1201 // Pull custom fields and match to Webform element types
1202 $custom_types = array(
1203 'Select' => array('type' => 'select'),
1204 'Multi-Select' => array('type' => 'select', 'extra' => array('multiple' => 1)),
1205 'AdvMulti-Select' => array('type' => 'select', 'extra' => array('multiple' => 1)),
1206 'Radio' => array('type' => 'select', 'extra' => array('aslist' => 0)),
1207 'CheckBox' => array('type' => 'select', 'extra' => array('multiple' => 1)),
1208 'Text' => array('type' => 'textfield'),
1209 'TextArea' => array('type' => 'textarea'),
1210 'RichTextEditor' => array('type' => module_exists('webform_html_textarea') ? 'html_textarea' : 'textarea'),
1211 'Select Date' => array('type' => 'date'),
1212 'Link' => array('type' => 'textfield'),
1213 'Select Country' => array('type' => 'select'),
1214 'Multi-Select Country' => array('type' => 'select', 'extra' => array('multiple' => 1)),
1215 'Select State/Province' => array('type' => 'select'),
1216 'Multi-Select State/Province' => array('type' => 'select', 'extra' => array('multiple' => 1)),
1217 'Autocomplete-Select' => array('type' => 'select'),
1218 'File' => array('type' => 'file'),
1219 );
1220 list($contact_types) = wf_crm_get_contact_types();
1221 $custom_extends = "'" . implode("','", array_keys($contact_types + $sets)) . "'";
1222 $sql = "
1223 SELECT cf.*, cg.title AS custom_group_name, LOWER(cg.extends) AS entity_type, cg.extends_entity_column_id, cg.extends_entity_column_value AS sub_types, cg.is_multiple, cg.max_multiple, cg.id AS custom_group_id, cg.help_pre as cg_help
1224 FROM civicrm_custom_field cf
1225 INNER JOIN civicrm_custom_group cg ON cg.id = cf.custom_group_id
1226 WHERE cf.is_active <> 0 AND cg.extends IN ($custom_extends) AND cg.is_active <> 0
1227 ORDER BY cf.custom_group_id, cf.weight";
1228 $dao = CRM_Core_DAO::executeQuery($sql);
1229 while ($dao->fetch()) {
1230 if (isset($custom_types[$dao->html_type])) {
1231 $set = 'cg' . $dao->custom_group_id;
1232 if ($dao->entity_type == 'address' || $dao->entity_type == 'relationship' || $dao->entity_type == 'membership') {
1233 $set = $dao->entity_type;
1234 }
1235 elseif (!isset($sets[$set])) {
1236 $sets[$set]['label'] = $dao->custom_group_name;
1237 if (isset($contact_types[$dao->entity_type]) || $dao->entity_type == 'contact') {
1238 $sets[$set]['entity_type'] = 'contact';
1239 if ($dao->entity_type != 'contact') {
1240 $sets[$set]['contact_type'] = $dao->entity_type;
1241 }
1242 if ($dao->is_multiple) {
1243 $sets[$set]['max_instances'] = ($dao->max_multiple ? $dao->max_multiple : 9);
1244 }
1245 else {
1246 $sets[$set]['max_instances'] = 1;
1247 }
1248 }
1249 else {
1250 $sets[$set]['entity_type'] = $dao->entity_type;
1251 }
1252 if ($dao->sub_types) {
1253 $sets[$set]['sub_types'] = wf_crm_explode_multivalue_str($dao->sub_types);
1254 }
1255 if ($dao->extends_entity_column_id) {
1256 $sets[$set]['extension_of'] = $dao->extends_entity_column_id;
1257 }
1258 $sets[$set]['help_text'] = $dao->cg_help;
1259 }
1260 $id = $set . '_custom_' . $dao->id;
1261 $fields[$id] = $custom_types[$dao->html_type];
1262 if ($dao->html_type == 'Text' && $dao->data_type == 'Money') {
1263 $fields[$id] = $moneyDefaults;
1264 }
1265 $fields[$id]['name'] = $dao->label;
1266 $fields[$id]['required'] = $dao->is_required;
1267 $fields[$id]['extra']['description'] = $dao->help_pre;
1268 $fields[$id]['value'] = implode(',', wf_crm_explode_multivalue_str($dao->default_value));
1269 $fields[$id]['data_type'] = $dao->data_type;
1270 if (!empty($dao->help_pre) || !empty($dao->help_post)) {
1271 $fields[$id]['extra']['description'] = $dao->help_pre ? $dao->help_pre : $dao->help_post;
1272 $fields[$id]['has_help'] = TRUE;
1273 }
1274 // Conditional rule - todo: support additional entities
1275 if ($sets[$set]['entity_type'] == 'contact' && !empty($sets[$set]['sub_types'])) {
1276 $fields[$id]['civicrm_condition'] = array(
1277 'andor' => 'or',
1278 'action' => 'show',
1279 'rules' => array(
1280 'contact_contact_sub_type' => $sets[$set]['sub_types'],
1281 ),
1282 );
1283 }
1284
1285 if ($dao->entity_type == 'relationship' && $dao->sub_types) {
1286 $fields[$id]['attributes']['data-relationship-type'] = implode(',', wf_crm_explode_multivalue_str($dao->sub_types));
1287 }
1288
1289 if ($fields[$id]['type'] == 'date') {
1290 $fields[$id]['extra']['start_date'] = ($dao->start_date_years ? '-' . $dao->start_date_years : '-50') . ' years';
1291 $fields[$id]['extra']['end_date'] = ($dao->end_date_years ? '+' . $dao->end_date_years : '+50') . ' years';
1292 // Add "time" component for datetime fields
1293 if (!empty($dao->time_format)) {
1294 $fields[$id]['name'] .= ' - ' . t('date');
1295 $fields[$id . '_timepart'] = array(
1296 'name' => $dao->label . ' - ' . t('time'),
1297 'type' => 'time',
1298 'extra' => array('hourformat' => $dao->time_format == 1 ? '12-hour' : '24-hour'),
1299 );
1300 }
1301 }
1302 elseif ($fields[$id]['data_type'] == 'ContactReference') {
1303 $fields[$id]['expose_list'] = TRUE;
1304 $fields[$id]['empty_option'] = t('None');
1305 }
1306 elseif ($fields[$id]['data_type'] !== 'Boolean' && $fields[$id]['type'] == 'select') {
1307 $fields[$id]['extra']['civicrm_live_options'] = 1;
1308 }
1309 elseif ($fields[$id]['type'] == 'textarea') {
1310 $fields[$id]['extra']['cols'] = $dao->note_columns;
1311 $fields[$id]['extra']['rows'] = $dao->note_rows;
1312 }
1313 }
1314 }
1315 $dao->free();
1316 }
1317 return $$var;
1318 }
1319
1320 /**
1321 * Get a field based on its short or full name
1322 * @param string $key
1323 * @return array|null
1324 */
1325 function wf_crm_get_field($key) {
1326 $fields = wf_crm_get_fields();
1327 if (isset($fields[$key])) {
1328 return $fields[$key];
1329 }
1330 if ($pieces = wf_crm_explode_key($key)) {
1331 list( , , , , $table, $name) = $pieces;
1332 if (isset($fields[$table . '_' . $name])) {
1333 return $fields[$table . '_' . $name];
1334 }
1335 }
1336 }
1337
1338 /**
1339 * Lookup a uf ID from contact ID or vice-versa
1340 * With no arguments passed in, this function will return the contact_id of the current logged-in user
1341 *
1342 * @param $id
1343 * (optional) uf or contact ID - defaults to current user
1344 * @param $type
1345 * (optional) what type of ID is supplied - defaults to user id
1346 * @return null
1347 */
1348 function wf_crm_user_cid($id = NULL, $type = 'uf') {
1349 static $current_user = NULL;
1350 if (!$id) {
1351 if ($current_user !== NULL) {
1352 return $current_user;
1353 }
1354 global $user;
1355 $id = $user_lookup = $user->uid;
1356 }
1357 if (!$id || !is_numeric($id)) {
1358 return NULL;
1359 }
1360 // Lookup current domain for multisite support
1361 static $domain = 0;
1362 if (!$domain) {
1363 $domain = wf_civicrm_api('domain', 'get', array('current_domain' => 1, 'return' => 'id'));
1364 $domain = wf_crm_aval($domain, 'id', 1);
1365 }
1366 $result = wf_crm_apivalues('uf_match', 'get', array(
1367 $type . '_id' => $id,
1368 'domain_id' => $domain,
1369 'sequential' => 1,
1370 ));
1371 if ($result) {
1372 if (!empty($user_lookup)) {
1373 $current_user = $result[0]['contact_id'];
1374 }
1375 return $type == 'uf' ? $result[0]['contact_id'] : $result[0]['uf_id'];
1376 }
1377 }
1378
1379 /**
1380 * Fetch contact display name
1381 *
1382 * @param $cid
1383 * Contact id
1384 *
1385 * @return string
1386 */
1387 function wf_crm_display_name($cid) {
1388 if (!$cid || !is_numeric($cid)) {
1389 return '';
1390 }
1391 civicrm_initialize();
1392 $result = wf_civicrm_api('contact', 'get', array('id' => $cid, 'return.display_name' => 1, 'is_deleted' => 0));
1393 return check_plain(wf_crm_aval($result, "values:$cid:display_name", ''));
1394 }
1395
1396 /**
1397 * @param integer $n
1398 * @param array $data Form data
1399 * @param string $html Controls how html should be treated. Options are:
1400 * * 'escape': (default) Escape html characters
1401 * * 'wrap': Escape html characters and wrap in a span
1402 * * 'plain': Do not escape (use when passing into an FAPI options list which does its own escaping)
1403 * @return string
1404 */
1405 function wf_crm_contact_label($n, $data = array(), $html = 'escape') {
1406 $label = trim(wf_crm_aval($data, "contact:$n:contact:1:webform_label", ''));
1407 if (!$label) {
1408 $label = t('Contact !num', array('!num' => $n));
1409 }
1410 if ($html != 'plain') {
1411 $label = check_plain($label);
1412 }
1413 if ($html == 'wrap') {
1414 $label = '<span class="contact-label number-' . $n . '">' . $label . '</span>';
1415 }
1416 return $label;
1417 }
1418
1419 /**
1420 * Explodes form key into an array and verifies that it is in the right format
1421 *
1422 * @param $key
1423 * Webform component field key (string)
1424 *
1425 * @return array or NULL
1426 */
1427 function wf_crm_explode_key($key) {
1428 $pieces = explode('_', $key, 6);
1429 if (count($pieces) != 6 || $pieces[0] !== 'civicrm') {
1430 return FALSE;
1431 }
1432 return $pieces;
1433 }
1434
1435 /**
1436 * Convert a | separated string into an array
1437 *
1438 * @param string $str
1439 * String representation of key => value select options
1440 *
1441 * @return array of select options
1442 */
1443 function wf_crm_str2array($str) {
1444 $ret = array();
1445 if ($str) {
1446 foreach (explode("\n", trim($str)) as $row) {
1447 if ($row && $row[0] !== '<' && strpos($row, '|')) {
1448 list($k, $v) = explode('|', $row);
1449 $ret[trim($k)] = trim($v);
1450 }
1451 }
1452 }
1453 return $ret;
1454 }
1455
1456 /**
1457 * Convert an array into a | separated string
1458 *
1459 * @param array $arr
1460 * Array of select options
1461 *
1462 * @return string
1463 * String representation of key => value select options
1464 */
1465 function wf_crm_array2str($arr) {
1466 $str = '';
1467 foreach ($arr as $k => $v) {
1468 $str .= ($str ? "\n" : '') . $k . '|' . $v;
1469 }
1470 return $str;
1471 }
1472
1473 /**
1474 * Wrapper for all CiviCRM API calls
1475 * For consistency, future-proofing, and error handling
1476 *
1477 * @param string $entity
1478 * API entity
1479 * @param string $operation
1480 * API operation
1481 * @param array $params
1482 * API params
1483 *
1484 * @return array
1485 * Result of API call
1486 */
1487 function wf_civicrm_api($entity, $operation, $params) {
1488 $params += array(
1489 'check_permissions' => FALSE,
1490 'version' => 3
1491 );
1492 $result = civicrm_api($entity, $operation, $params);
1493 // I guess we want silent errors for getoptions b/c we check it for failure separately
1494 if (!empty($result['is_error']) && $operation != 'getoptions') {
1495 $bt = debug_backtrace();
1496 $n = $bt[0]['function'] == 'wf_civicrm_api' ? 1 : 0;
1497 $file = explode('/', $bt[$n]['file']);
1498 if (isset($params['credit_card_number'])) {
1499 $params['credit_card_number'] = "xxxxxxxxxxxx".substr($params['credit_card_number'], -4);
1500 }
1501 watchdog('webform_civicrm',
1502 'The CiviCRM "%function" API returned the error: "%msg" when called by function "!fn" on line !line of !file with parameters: "!params"',
1503 array(
1504 '%function' => $entity . ' ' . $operation,
1505 '%msg' => $result['error_message'],
1506 '!fn' => $bt[$n+1]['function'],
1507 '!line' => $bt[$n]['line'],
1508 '!file' => array_pop($file),
1509 '!params' => print_r($params, TRUE),
1510 ),
1511 WATCHDOG_ERROR);
1512 }
1513 return $result;
1514 }
1515
1516 /**
1517 * Get the values from an api call
1518 *
1519 * @param string $entity
1520 * API entity
1521 * @param string $operation
1522 * API operation
1523 * @param array $params
1524 * API params
1525 * @param string $value
1526 * Reduce each result to this single value
1527 *
1528 * @return array
1529 * Values from API call
1530 */
1531 function wf_crm_apivalues($entity, $operation, $params = array(), $value = NULL) {
1532 if (is_numeric($params)) {
1533 $params = array('id' => $params);
1534 }
1535 $params += array('options' => array());
1536 // Work around the api's default limit of 25
1537 $params['options'] += array('limit' => 0);
1538 $ret = wf_crm_aval(wf_civicrm_api($entity, $operation, $params), 'values', array());
1539 if ($value) {
1540 foreach ($ret as &$values) {
1541 $values = wf_crm_aval($values, $value);
1542 }
1543 }
1544 return $ret;
1545 }
1546
1547 /**
1548 * Check if a name or email field exists for this contact.
1549 * This determines whether a new contact can be created on the webform.
1550 *
1551 * @param $enabled
1552 * Array of enabled fields
1553 * @param $c
1554 * Contact #
1555 * @param $contact_type
1556 * Contact type
1557 * @return int
1558 */
1559 function wf_crm_name_field_exists($enabled, $c, $contact_type) {
1560 foreach (wf_crm_required_contact_fields($contact_type) as $f) {
1561 $fid = 'civicrm_' . $c . '_contact_1_' . $f['table'] . '_' . $f['name'];
1562 if (!empty($enabled[$fid])) {
1563 return 1;
1564 }
1565 }
1566 return 0;
1567 }
1568
1569 /**
1570 * At least one of these fields is required to create a contact
1571 *
1572 * @param string $contact_type
1573 * @return array of fields
1574 */
1575 function wf_crm_required_contact_fields($contact_type) {
1576 if ($contact_type == 'individual') {
1577 return array(
1578 array('table' => 'email', 'name' => 'email'),
1579 array('table' => 'contact', 'name' => 'first_name'),
1580 array('table' => 'contact', 'name' => 'last_name'),
1581 array('table' => 'contact', 'name' => 'nick_name'),
1582 );
1583 }
1584 return array(array('table' => 'contact', 'name' => $contact_type . '_name'));
1585 }
1586
1587 /**
1588 * These are the contact location fields this module supports
1589 *
1590 * @return array
1591 */
1592 function wf_crm_location_fields() {
1593 return array('address', 'email', 'phone', 'website', 'im');
1594 }
1595
1596 /**
1597 * These are the address fields this module supports
1598 *
1599 * @return array
1600 */
1601 function wf_crm_address_fields() {
1602 return array(
1603 'street_address',
1604 'city',
1605 'state_province_id',
1606 'country_id',
1607 'postal_code'
1608 );
1609 }
1610
1611 /**
1612 * Returns a count of children of a webform component
1613 *
1614 * @param int $nid
1615 * @param int $id
1616 * @return int
1617 */
1618 function _wf_crm_child_components($nid, $id) {
1619 return db_select('webform_component', 'c')
1620 ->fields('c')
1621 ->condition('nid', $nid)
1622 ->condition('pid', $id)
1623 ->countQuery()
1624 ->execute()
1625 ->fetchField();
1626 }
1627
1628 /**
1629 * @param string
1630 * @return array
1631 */
1632 function wf_crm_explode_multivalue_str($str) {
1633 $sp = CRM_Core_DAO::VALUE_SEPARATOR;
1634 if (is_array($str)) {
1635 return $str;
1636 }
1637 return explode($sp, trim((string) $str, $sp));
1638 }
1639
1640 /**
1641 * Check if value is a positive integer
1642 * @param mixed $val
1643 * @return bool
1644 */
1645 function wf_crm_is_positive($val) {
1646 return is_numeric($val) && $val > 0 && round($val) == $val;
1647 }