commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / webform_civicrm / includes / wf_crm_admin_form.inc
1 <?php
2
3 /**
4 * @file
5 * Webform CiviCRM module's admin form.
6 */
7
8 class wf_crm_admin_form {
9 private $form;
10 private $form_state;
11 private $node;
12 private $fields;
13 private $sets;
14 private $settings;
15 private $data;
16
17 function __construct($form, &$form_state, $node) {
18 module_load_include('inc', 'webform_civicrm', 'includes/utils');
19 module_load_include('inc', 'webform_civicrm', 'includes/wf_crm_admin_help');
20 civicrm_initialize();
21 $this->form = $form;
22 $this->form_state = &$form_state;
23 $this->node = &$node;
24 $this->fields = wf_crm_get_fields();
25 $this->sets = wf_crm_get_fields('sets');
26 }
27
28 /**
29 * Build admin form for civicrm tab of a webform
30 * @return array
31 */
32 public function buildForm() {
33 $this->form_state['storage']['nid'] = $this->node->nid;
34
35 // Display confirmation message before deleting fields
36 if (!empty($this->form_state['storage']['msg'])) {
37 return $this->buildConfirmationForm();
38 }
39
40 // Add css & js
41 $this->addResources();
42
43 if (empty($this->form_state['values'])) {
44 $this->initializeForm();
45 }
46 else {
47 $this->rebuildForm();
48 }
49 // Merge in existing fields
50 $existing = array_keys(wf_crm_enabled_fields($this->node, NULL, TRUE));
51 $this->settings += array_fill_keys($existing, 'create_civicrm_webform_element');
52
53 // Sort fields by set
54 foreach ($this->fields as $fid => $field) {
55 if (isset($field['set'])) {
56 $set = $field['set'];
57 }
58 else {
59 list($set) = explode('_', $fid, 2);
60 }
61 $this->sets[$set]['fields'][$fid] = $field;
62 }
63
64 // Build form fields
65 $this->buildFormIntro();
66 foreach ($this->data['contact'] as $n => $c) {
67 $this->buildContactTab($n, $c);
68 }
69 $this->buildMessageTabs();
70
71 // Component tabs
72 $this->buildActivityTab();
73 if (isset($this->sets['case'])) {
74 $this->buildCaseTab();
75 }
76 if (isset($this->sets['participant'])) {
77 $this->buildParticipantTab();
78 }
79 if (isset($this->sets['membership'])) {
80 $this->buildMembershipTab();
81 }
82 if (isset($this->sets['contribution'])) {
83 $this->buildContributionTab();
84 }
85 if (isset($this->sets['grant'])) {
86 $this->buildGrantTab();
87 }
88 $this->buildOptionsTab();
89
90 $this->form['actions']['submit'] = array(
91 '#type' => 'submit',
92 '#value' => t('Save Settings'),
93 );
94 return $this->form;
95 }
96
97 /**
98 * Initialize form on first view
99 */
100 private function initializeForm() {
101 $this->settings = isset($this->node->webform_civicrm) ? $this->node->webform_civicrm : $this->defaultSettings();
102 $this->data = &$this->settings['data'];
103 // Warn of incompatible modules
104 $incompatibilities = array(
105 'form_builder_webform' => t('Form builder Webform UI'),
106 'webform_alt_ui' => t('Webform Alternate UI'),
107 );
108 foreach ($incompatibilities as $module => $label) {
109 if (module_exists($module)) {
110 drupal_set_message(t('The module %module is not compatible with Webform CiviCRM Integration. Please disable it before continuing.', array('%module' => $label)), 'error');
111 }
112 }
113 }
114
115 /**
116 * On rebuilding the form
117 */
118 private function rebuildForm() {
119 $this->settings = wf_crm_aval($this->form_state['storage'], 'vals', $this->form_state['values']);
120 $this->rebuildData();
121 // Hack for nicer UX: pre-check phone, email, etc when user increments them
122 if (!empty($_POST['_triggering_element_name'])) {
123 foreach (array('phone' => 'phone', 'email' => 'email', 'website' => 'url', 'im' => 'name') as $ent => $field) {
124 if (strpos($_POST['_triggering_element_name'], "_number_of_$ent")) {
125 list(, $c) = explode('_', $_POST['_triggering_element_name']);
126 for ($n = 1; $n <= $this->data['contact'][$c]["number_of_$ent"]; ++$n) {
127 $this->settings["civicrm_{$c}_contact_{$n}_{$ent}_{$field}"] = 1;
128 }
129 }
130 }
131 }
132 unset($this->form_state['storage']['vals']);
133 }
134
135 /**
136 * Display confirmation message and buttons before deleting webform components
137 * @return array
138 */
139 private function buildConfirmationForm() {
140 $this->form['#prefix'] = $this->form_state['storage']['msg'];
141 $this->form['cancel'] = $this->form['disable'] = $this->form['delete'] = array('#type' => 'submit');
142 $this->form['delete']['#value'] = t('Remove Fields and Save Settings');
143 $this->form['disable']['#value'] = t('Leave Fields and Save Settings');
144 $this->form['cancel']['#value'] = t('Cancel (go back)');
145 return $this->form;
146 }
147
148 /**
149 * Add necessary css & js
150 */
151 private function addResources() {
152 $this->form['#attached']['css'][] = drupal_get_path('module', 'webform_civicrm') . '/css/webform_civicrm_admin.css';
153 $this->form['#attached']['js'][] = drupal_get_path('module', 'webform_civicrm') . '/js/webform_civicrm_admin.js';
154 $this->form['#attached']['js'][] = array(
155 'data' => array('webform_civicrm' => array('rTypes' => wf_crm_get_relationship_types())),
156 'type' => 'setting',
157 );
158 // Add CiviCRM core css & js, which includes jQuery, jQuery UI + other plugins
159 CRM_Core_Resources::singleton()->addCoreResources();
160 // Markup needed by CRM popup notifications
161 $this->form['#suffix'] = wf_crm_admin_help::helpTemplate();
162 }
163
164 /**
165 * Build fields for form intro
166 */
167 private function buildFormIntro() {
168 $this->form['nid'] = array(
169 '#type' => 'checkbox',
170 '#title' => t('Enable CiviCRM Processing'),
171 '#default_value' => !empty($this->settings['nid']),
172 '#return_value' => $this->node->nid,
173 );
174 $this->help($this->form['nid'], 'intro', t('Webform-CiviCRM Integration'));
175 $this->form['number_of_contacts'] = array(
176 '#type' => 'select',
177 '#title' => t('Number of Contacts'),
178 '#default_value' => count($this->data['contact']),
179 '#options' => drupal_map_assoc(range(1, 30)),
180 );
181 $this->form['change_form_settings'] = array(
182 '#type' => 'button',
183 '#value' => t('Change Form Settings'),
184 '#prefix' => '<div id="no-js-button-wrapper" class="messages warning">',
185 '#suffix' => '<div>' . t('You have Javascript disabled. You will need to click this button after changing any option to see the result.') . '</div></div>',
186 );
187 $this->form['webform_civicrm'] = array('#type' => 'vertical_tabs');
188 // Display intro help to virgins
189 if (!variable_get('webform_civicrm_help_seen')) {
190 variable_set('webform_civicrm_help_seen', TRUE);
191 drupal_add_js('cj(function() {CRM.help("' . t('Welcome to Webform-CiviCRM') . '", {}, "' . url('webform-civicrm/help/intro') . '");});', array('type' => 'inline', 'scope' => 'footer'));
192 }
193 }
194
195 /**
196 * Build fields for a contact
197 * @param int $n Contact number
198 * @param array $c Contact info
199 */
200 private function buildContactTab($n, $c) {
201 list($contact_types, $sub_types) = wf_crm_get_contact_types();
202 $this->form['contact_' . $n] = array(
203 '#type' => 'fieldset',
204 '#title' => $n . '. ' . wf_crm_contact_label($n, $this->data),
205 '#description' => $n > 1 ? NULL : t('Primary contact. Usually assumed to be the person filling out the form.') . '<br />' . t('Enable the "Existing Contact" field to autofill with the current user (or another contact).'),
206 '#group' => 'webform_civicrm',
207 '#attributes' => array('class' => array('contact-icon-' . $c['contact'][1]['contact_type'])),
208 );
209 $this->form['contact_' . $n][$n . '_contact_type'] = array(
210 '#type' => 'select',
211 '#title' => t('Contact Type'),
212 '#default_value' => $c['contact'][1]['contact_type'],
213 '#options' => $contact_types,
214 '#prefix' => '<div class="contact-type-select">',
215 );
216 $this->form['contact_' . $n][$n . '_webform_label'] = array(
217 '#type' => 'textfield',
218 '#title' => t('Label'),
219 '#default_value' => wf_crm_contact_label($n, $this->data, 'plain'),
220 '#suffix' => '</div>',
221 );
222 $this->help($this->form['contact_' . $n][$n . '_webform_label'], 'webform_label', t('Contact Label'));
223 $this->addAjaxItem('contact_' . $n, $n . '_contact_type', 'contact_subtype_wrapper', 'contact-subtype-wrapper');
224
225 // Contact sub-type
226 $fid = 'civicrm_' . $n . '_contact_1_contact_contact_sub_type';
227 $subTypeIsUserSelect = FALSE;
228 if (!empty($sub_types[$c['contact'][1]['contact_type']])) {
229 $field = $this->fields['contact_contact_sub_type'];
230 $field['name'] = t('Type of @contact', array('@contact' => $contact_types[$c['contact'][1]['contact_type']]));
231 $this->form['contact_' . $n]['contact_subtype_wrapper'][$fid] = $subTypeField = $this->addItem($fid, $field);
232 $subTypeIsUserSelect = in_array('create_civicrm_webform_element', $subTypeField['#default_value']);
233 $this->addAjaxItem('contact_' . $n . ':contact_subtype_wrapper', $fid, 'contact_custom_wrapper');
234 }
235 // If no sub-types
236 else {
237 $this->form['contact_' . $n]['contact_subtype_wrapper'][$fid] = array(
238 '#type' => 'value',
239 '#value' => array(),
240 );
241 }
242
243 $this->form['contact_' . $n]['contact_subtype_wrapper']['clear'] = array(
244 '#markup' => '<div class="clearfix"> </div>',
245 );
246
247 foreach ($this->sets as $sid => $set) {
248 if ($set['entity_type'] != 'contact') {
249 continue;
250 }
251 if ($sid == 'relationship' && !($set['max_instances'] = $n - 1)) {
252 continue;
253 }
254 if (!empty($set['contact_type']) && $set['contact_type'] != $c['contact'][1]['contact_type']) {
255 continue;
256 }
257 if (!empty($set['sub_types'])) {
258 if (!$subTypeIsUserSelect && !array_intersect($c['contact'][1]['contact_sub_type'], $set['sub_types'])) {
259 continue;
260 }
261 $pos = &$this->form['contact_' . $n]['contact_subtype_wrapper']['contact_custom_wrapper'];
262 $path = 'contact_' . $n . ':contact_subtype_wrapper:contact_custom_wrapper';
263 }
264 elseif (!empty($set['contact_type']) || $sid == 'contact') {
265 $pos = &$this->form['contact_' . $n]['contact_subtype_wrapper'];
266 $path = 'contact_' . $n . ':contact_subtype_wrapper';
267 }
268 else {
269 $pos = &$this->form['contact_' . $n];
270 $path = 'contact_' . $n;
271 }
272 if (!empty($set['max_instances'])) {
273 if (!isset($c['number_of_' . $sid])) {
274 $c['number_of_' . $sid] = 0;
275 }
276 $selector = array(
277 '#type' => 'select',
278 '#default_value' => $c['number_of_' . $sid],
279 '#prefix' => '<div class="number-of">',
280 '#suffix' => '</div>',
281 );
282 if ($set['max_instances'] > 1) {
283 $selector['#options'] = range(0, $set['max_instances']);
284 $selector['#title'] = t('Number of %type Fields', array('%type' => $set['label']));
285 }
286 else {
287 $selector['#options'] = array(t('No'), t('Yes'));
288 $selector['#title'] = t('Enable %type Fields', array('%type' => $set['label']));
289 }
290 if (!empty($set['help_text'])) {
291 $this->help($selector, "fieldset_$sid", $set['label']);
292 }
293 $pos['contact_' . $n . '_number_of_' . $sid] = $selector;
294 $this->addAjaxItem($path, 'contact_' . $n . '_number_of_' . $sid, $n . $sid . '_wrapper');
295 }
296 else {
297 $c['number_of_' . $sid] = 1;
298 }
299 for ($i = 1; $i <= $c['number_of_' . $sid]; ++$i) {
300 $fsid = 'civicrm_' . $n . $sid . $i . '_fieldset';
301 $fieldset = array(
302 '#type' => 'fieldset',
303 '#title' => $set['label'],
304 '#attributes' => array('id' => $fsid, 'class' => array('web-civi-checkbox-set')),
305 'js_select' => $this->addToggle($fsid),
306 );
307 if ($sid == 'relationship') {
308 $fieldset['#title'] = t('Relationship to !contact', array('!contact' => wf_crm_contact_label($i, $this->data, 'wrap')));
309 }
310 elseif ((isset($set['max_instances']) && $set['max_instances'] > 1)) {
311 $fieldset['#title'] .= ' ' . $i;
312 if (in_array($sid, wf_crm_location_fields()) && $i == 1) {
313 $fieldset['#title'] .= ' ' . t('(primary)');
314 }
315 }
316 foreach ($set['fields'] as $fid => $field) {
317 if ($fid == 'contact_contact_sub_type' ||
318 ($fid == 'address_master_id' && count($this->data['contact']) == 1) ||
319 (isset($field['contact_type']) && $field['contact_type'] != $c['contact'][1]['contact_type'])) {
320 continue;
321 }
322 $fid = 'civicrm_' . $n . '_contact_' . $i . '_' . $fid;
323 $fieldset[$fid] = $this->addItem($fid, $field);
324 }
325 if (isset($set['max_instances'])) {
326 $pos[$n . $sid . '_wrapper'][$n . $sid . $i . '_fieldset'] = $fieldset;
327 }
328 else {
329 $pos[$n . $sid . $i . '_fieldset'] = $fieldset;
330 }
331 }
332 if ($sid == 'contact') {
333 // Matching rule
334 $rule_field = $this->form['contact_' . $n]['contact_subtype_wrapper']["contact_{$n}_settings_matching_rule"] = array(
335 '#type' => 'select',
336 '#options' => array(
337 0 =>t('- None -'),
338 'Unsupervised' => t('Default Unsupervised'),
339 'Supervised' => t('Default Supervised'),
340 ) + wf_crm_get_matching_rules($c['contact'][1]['contact_type']),
341 '#title' => t('Matching Rule'),
342 '#prefix' => '<div class="number-of">',
343 '#suffix' => '</div>',
344 '#default_value' => wf_crm_aval($this->data['contact'][$n], 'matching_rule', 'Unsupervised', TRUE),
345 );
346 $rule_field =& $this->form['contact_' . $n]['contact_subtype_wrapper']["contact_{$n}_settings_matching_rule"];
347 // Reset to default if selected rule doesn't exist or isn't valid for this contact type
348 if (!array_key_exists($rule_field['#default_value'], $rule_field['#options'])) {
349 $rule_field['#default_value'] = $this->form_state['input']["contact_{$n}_settings_matching_rule"] = 'Unsupervised';
350 }
351 $this->help($rule_field, 'matching_rule');
352 }
353 }
354 }
355
356 /**
357 * Configure messages
358 */
359 private function buildMessageTabs() {
360 $tokens = '<strong>' . t('Tokens for !contact', array('!contact' => wf_crm_contact_label(1, $this->data, TRUE))) . ':</strong> [' . implode('], [', wf_crm_get_fields('tokens')) . '].';
361
362 $this->form['prefix'] = array(
363 '#type' => 'fieldset',
364 '#title' => t('Introduction Text'),
365 '#description' => t('This text will appear at the top of the form. You may configure separate messages for known contacts (logged in users, or users following a hashed link from civimail) and unknown (anonymous) users.'),
366 '#group' => 'webform_civicrm',
367 '#attributes' => array('class' => array('civi-icon-text')),
368 );
369 $this->form['prefix']['prefix_known'] = array(
370 '#type' => 'textarea',
371 '#title' => t('Introduction text for known contacts'),
372 '#default_value' => wf_crm_aval($this->settings, 'prefix_known'),
373 '#description' => $tokens,
374 );
375 $this->form['prefix']['prefix_unknown'] = array(
376 '#type' => 'textarea',
377 '#title' => t('Introduction text for unknown contacts'),
378 '#default_value' => wf_crm_aval($this->settings, 'prefix_unknown'),
379 '#description' => t('No tokens available for unknown contacts.'),
380 );
381 $this->form['st_message'] = array(
382 '#type' => 'fieldset',
383 '#title' => t('"Not You?" Message'),
384 '#description' => t('Prompt for users who are logged in as, or following a hashed link for, someone else.'),
385 '#group' => 'webform_civicrm',
386 '#attributes' => array('class' => array('civi-icon-message')),
387 );
388 $this->form['st_message']['toggle_message'] = array(
389 '#type' => 'checkbox',
390 '#title' => t('Display message to known contacts?'),
391 '#default_value' => !empty($this->settings['message']),
392 );
393 $this->form['st_message']['message'] = array(
394 '#type' => 'textfield',
395 '#title' => t('Text (displayed as a status message)'),
396 '#default_value' => wf_crm_aval($this->settings, 'message', t("You are viewing this form as [display name]. Please {click here if that's not you}.")),
397 '#size' => 100,
398 '#maxlength' => 255,
399 '#attributes' => array('style' => 'max-width: 100%;'),
400 '#description' => t('Enclose your "not you" link text in curly brackets {like this}.') . '<p>' . $tokens . '</p>',
401 );
402 }
403
404 /**
405 * Activity settings
406 */
407 private function buildActivityTab() {
408 $this->form['activityTab'] = array(
409 '#type' => 'fieldset',
410 '#title' => t('Activities'),
411 '#group' => 'webform_civicrm',
412 '#attributes' => array('class' => array('civi-icon-activity')),
413 );
414 $num_acts = wf_crm_aval($this->data, "activity:number_of_activity", 0);
415 $this->form['activityTab']["activity_number_of_activity"] = array(
416 '#type' => 'select',
417 '#title' => t('Number of Activities'),
418 '#default_value' => $num_acts,
419 '#options' => range(0, $this->sets['activity']['max_instances']),
420 '#prefix' => '<div class="number-of">',
421 '#suffix' => '</div>',
422 );
423 $this->addAjaxItem("activityTab", "activity_number_of_activity", "activity");
424 for ($n = 1; $n <= $num_acts; ++$n) {
425 $num = "activity_activity_{$n}_fieldset";
426 $this->form['activityTab']['activity'][$num] = array(
427 '#type' => 'fieldset',
428 '#attributes' => array('class' => array('activity-wrapper')),
429 '#title' => t('Activity !num', array('!num' => $n)),
430 );
431 $this->form['activityTab']['activity'][$num]["activity_{$n}_settings_existing_activity_status"] = array(
432 '#type' => 'select',
433 '#title' => t('Update Existing Activity'),
434 '#options' => array('' => '- ' . t('None') . ' -') + wf_crm_apivalues('activity', 'getoptions', array('field' => 'status_id')),
435 '#default_value' => wf_crm_aval($this->data, "activity:$n:existing_activity_status", array()),
436 '#multiple' => TRUE,
437 '#prefix' => '<div class="float-item">',
438 '#suffix' => '</div>',
439 );
440 $this->help($this->form['activityTab']['activity'][$num]["activity_{$n}_settings_existing_activity_status"], 'existing_activity_status');
441 $this->form['activityTab']['activity'][$num]["activity_{$n}_settings_details"] = array(
442 '#type' => 'checkboxes',
443 '#options' => array(
444 'entire_result' => t('Include <em>entire</em> webform submission in activity details'),
445 'view_link' => t('Include link to <em>view</em> webform submission in activity details'),
446 'edit_link' => t('Include link to <em>edit</em> webform submission in activity details'),
447 ),
448 '#default_value' => wf_crm_aval($this->data, "activity:$n:details", array('view_link'), TRUE),
449 );
450 $this->form['activityTab']['activity'][$num]['wrap'] = array();
451 $wrap = &$this->form['activityTab']['activity'][$num]['wrap'];
452 if (isset($this->sets['case'])) {
453 $case_types = wf_crm_apivalues('case', 'getoptions', array('field' => 'case_type_id'));
454 if ($case_types) {
455 $wrap['case']["activity_{$n}_settings_case_type_id"] = array(
456 '#type' => 'select',
457 '#title' => t('File On Case'),
458 '#options' => array(t('- None -')) + $case_types,
459 '#default_value' => $case_type = wf_crm_aval($this->data, "activity:$n:case_type_id"),
460 );
461 // Allow selection of webform cases
462 $num_case = wf_crm_aval($this->data, "case:number_of_case", 0);
463 if ($num_case) {
464 $webform_cases = array();
465 for ($i=1; $i<=$num_case; ++$i) {
466 $webform_cases["#$i"] = t('Case !num', array('!num' => $i));
467 }
468 $wrap['case']["activity_{$n}_settings_case_type_id"]['#options'] = array(
469 t('- None -'),
470 t('This Webform') => $webform_cases,
471 t('Find by Case Type') => $case_types,
472 );
473 }
474 $this->help($wrap['case']["activity_{$n}_settings_case_type_id"], 'file_on_case');
475 $this->addAjaxItem("activityTab:activity:$num:wrap:case", "activity_{$n}_settings_case_type_id", '..:..:wrap');
476 if ($case_type && $case_type[0] !== '#') {
477 $wrap['case']['#type'] = 'fieldset';
478 $wrap['case']['#attributes'] = array('class' => array('web-civi-checkbox-set'));
479 $wrap['case']['#title'] = t('File On Case');
480 $wrap['case']['#description'] = t('File on existing case matching the following criteria:');
481 $this->help($wrap['case'], 'file_on_case');
482 $wrap['case']["activity_{$n}_settings_case_type_id"]['#title'] = t('Case Type');
483 $status_options = wf_crm_apivalues('case', 'getoptions', array('field' => 'status_id'));
484 $wrap['case']["activity_{$n}_settings_case_status_id"] = array(
485 '#type' => 'select',
486 '#title' => t('Case Status'),
487 '#options' => $status_options,
488 '#multiple' => TRUE,
489 '#attributes' => array('class' => array('required')),
490 '#default_value' => wf_crm_aval($this->data, "activity:$n:case_status_id", array_keys($status_options)),
491 );
492 $wrap['case']["activity_{$n}_settings_case_contact_id"] = array(
493 '#type' => 'select',
494 '#title' => t('Case Client'),
495 '#attributes' => array('data-type' => 'ContactReference'),
496 '#options' => $this->contactRefOptions(),
497 '#default_value' => wf_crm_aval($this->data, "activity:$n:case_contact_id"),
498 );
499 }
500 }
501 }
502 $wrap[$num . '_fields'] = array(
503 '#type' => 'fieldset',
504 '#title' => ts('Activity'),
505 '#attributes' => array('id' => $num . '_fields', 'class' => array('web-civi-checkbox-set')),
506 'js_select' => $this->addToggle($num . '_fields'),
507 );
508 foreach ($this->sets['activity']['fields'] as $fid => $field) {
509 if ($fid != 'activity_survey_id') {
510 $fid = "civicrm_{$n}_activity_1_$fid";
511 $wrap[$num . '_fields'][$fid] = $this->addItem($fid, $field);
512 }
513 }
514 $type = $wrap[$num . '_fields']["civicrm_{$n}_activity_1_activity_activity_type_id"]['#default_value'];
515 $type = $type == 'create_civicrm_webform_element' ? 0 : $type;
516 $this->addAjaxItem("activityTab:activity:$num:wrap:{$num}_fields", "civicrm_{$n}_activity_1_activity_activity_type_id", "..:custom");
517 // Add ajax survey type field
518 if (isset($this->fields['activity_survey_id'])) {
519 $this->addAjaxItem("activityTab:activity:$num:wrap:{$num}_fields", "civicrm_{$n}_activity_1_activity_campaign_id", "..:custom");
520 if ($type && array_key_exists($type, wf_crm_get_campaign_activity_types())) {
521 $this->sets['activity_survey'] = array(
522 'entity_type' => 'activity',
523 'label' => $wrap[$num . '_fields']["civicrm_{$n}_activity_1_activity_activity_type_id"]['#options'][$type],
524 'fields' => array(
525 'activity_survey_id' => $this->fields['activity_survey_id'],
526 )
527 );
528 }
529 }
530 // Add custom field sets appropriate to this activity type
531 foreach ($this->sets as $sid => $set) {
532 if ($set['entity_type'] == 'activity' && $sid != 'activity'
533 && (!$type || empty($set['sub_types']) || in_array($type, $set['sub_types']))
534 ) {
535 $fs1 = "activity_activity_{$n}_fieldset_$sid";
536 $wrap['custom'][$fs1] = array(
537 '#type' => 'fieldset',
538 '#title' => $set['label'],
539 '#attributes' => array('id' => $fs1, 'class' => array('web-civi-checkbox-set')),
540 'js_select' => $this->addToggle($fs1),
541 );
542 foreach ($set['fields'] as $fid => $field) {
543 $fid = "civicrm_{$n}_activity_1_$fid";
544 $wrap['custom'][$fs1][$fid] = $this->addItem($fid, $field);
545 }
546 }
547 }
548 }
549 }
550
551 /**
552 * Case settings
553 * FIXME: This is exactly the same code as buildGrantTab. More utilities and less boilerplate needed.
554 */
555 private function buildCaseTab() {
556 $types = wf_crm_apivalues('case', 'getoptions', array('field' => 'case_type_id'));
557 if (!$types) {
558 return;
559 }
560 $this->form['caseTab'] = array(
561 '#type' => 'fieldset',
562 '#title' => t('Cases'),
563 '#group' => 'webform_civicrm',
564 '#attributes' => array('class' => array('civi-icon-case')),
565 );
566 $this->form['caseTab']["case_number_of_case"] = array(
567 '#type' => 'select',
568 '#title' => t('Number of Cases'),
569 '#default_value' => $num = wf_crm_aval($this->data, "case:number_of_case", 0),
570 '#options' => range(0, $this->sets['case']['max_instances']),
571 '#prefix' => '<div class="number-of">',
572 '#suffix' => '</div>',
573 );
574 $this->addAjaxItem("caseTab", "case_number_of_case", "case");
575 for ($n = 1; $n <= $num; ++$n) {
576 $fs = "case_case_{$n}_fieldset";
577 $this->form['caseTab']['case'][$fs] = array(
578 '#type' => 'fieldset',
579 '#title' => t('Case !num', array('!num' => $n)),
580 'wrap' => array('#weight' => 9),
581 );
582 $this->form['caseTab']['case'][$fs]["case_{$n}_settings_existing_case_status"] = array(
583 '#type' => 'select',
584 '#title' => t('Update Existing Case'),
585 '#options' => array('' => '- ' . t('None') . ' -') + wf_crm_apivalues('case', 'getoptions', array('field' => 'status_id')),
586 '#default_value' => wf_crm_aval($this->data, "case:{$n}:existing_case_status", array()),
587 '#multiple' => TRUE,
588 );
589 $this->help($this->form['caseTab']['case'][$fs]["case_{$n}_settings_existing_case_status"], 'existing_case_status');
590 $case_type = wf_crm_aval($this->data, "case:{$n}:case:1:case_type_id");
591 foreach ($this->filterCaseSets($case_type) as $sid => $set) {
592 $fs1 = "case_case_{$n}_fieldset_$sid";
593 if ($sid == 'case') {
594 $pos = &$this->form['caseTab']['case'][$fs];
595 }
596 else {
597 $pos = &$this->form['caseTab']['case'][$fs]['wrap'];
598 }
599 $pos[$fs1] = array(
600 '#type' => 'fieldset',
601 '#title' => $set['label'],
602 '#attributes' => array('id' => $fs1, 'class' => array('web-civi-checkbox-set')),
603 'js_select' => $this->addToggle($fs1),
604 );
605 foreach ($set['fields'] as $fid => $field) {
606 $fid = "civicrm_{$n}_case_1_$fid";
607 if (!$case_type || empty($field['case_types']) || in_array($case_type, $field['case_types'])) {
608 $pos[$fs1][$fid] = $this->addItem($fid, $field);
609 }
610 }
611 }
612 $this->addAjaxItem("caseTab:case:$fs:case_case_{$n}_fieldset_case", "civicrm_{$n}_case_1_case_case_type_id", "..:wrap");
613 }
614 }
615
616 /**
617 * Adjust case role fields to match creator/manager settings for a given case type
618 *
619 * @param int|null $case_type
620 * @return array
621 */
622 private function filterCaseSets($case_type) {
623 $case_sets = array();
624 foreach ($this->sets as $sid => $set) {
625 if ($set['entity_type'] == 'case' && (!$case_type || empty($set['sub_types']) || in_array($case_type, $set['sub_types']))) {
626 if ($sid == 'caseRoles') {
627 // Lookup case-role names
628 $creator = $manager = NULL;
629 // Use the vanilla civicrm_api for this because it will throw an error in CiviCRM 4.4 (api doesn't exist)
630 $case_types = civicrm_api('case_type', 'get', array('version' => 3, 'id' => $case_type, 'options' => array('limit' => 0)));
631 foreach (wf_crm_aval($case_types, 'values', array()) as $type) {
632 foreach ($type['definition']['caseRoles'] as $role) {
633 if (!empty($role['creator'])) {
634 $creator = ($creator == $role['name'] || $creator === NULL) ? $role['name'] : FALSE;
635 }
636 if (!empty($role['manager'])) {
637 $manager = ($manager == $role['name'] || $manager === NULL) ? $role['name'] : FALSE;
638 }
639 }
640 }
641 if ($creator) {
642 $rel_type = wf_civicrm_api('relationshipType', 'getsingle', array('name_b_a' => $creator));
643 $label = $creator == $manager ? ts('Case # Creator/Manager') : ts('Case # Creator');
644 $set['fields']['case_creator_id']['name'] = $rel_type['label_b_a'] . ' (' . $label . ')';
645 unset($set['fields']['case_role_' . $rel_type['id']]);
646 }
647 if ($manager && $manager != $creator) {
648 $rel_type = wf_civicrm_api('relationshipType', 'getsingle', array('name_b_a' => $manager));
649 $set['fields']['case_role_' . $rel_type['id']]['name'] .= ' (' . ts('Case # Manager') . ')';
650 }
651 }
652 $case_sets[$sid] = $set;
653 }
654 }
655 return $case_sets;
656 }
657
658 /**
659 * Event participant settings
660 */
661 private function buildParticipantTab() {
662 $this->form['participant'] = array(
663 '#type' => 'fieldset',
664 '#title' => t('Event Registration'),
665 '#group' => 'webform_civicrm',
666 '#attributes' => array('class' => array('civi-icon-participant')),
667 );
668 $reg_type = wf_crm_aval($this->data, 'participant_reg_type');
669 $this->form['participant']['participant_reg_type'] = array(
670 '#type' => 'select',
671 '#title' => t('Registration Method'),
672 '#default_value' => $reg_type,
673 '#options' => array(
674 t('- None -'),
675 'all' => t('Register all contacts for the same event(s)'),
676 'separate' => t('Register each contact separately'),
677 ),
678 );
679 $this->help($this->form['participant']['participant_reg_type'], 'participant_reg_type');
680 $this->form['participant']['event_type'] = array(
681 '#type' => 'select',
682 '#title' => t('Show Events of Type'),
683 '#options' => array('any' => t('- Any Type -')) + wf_crm_apivalues('event', 'getoptions', array('field' => 'event_type_id')),
684 '#default_value' => wf_crm_aval($this->data, 'reg_options:event_type', 'any'),
685 '#prefix' => '<div id="event-reg-options-wrapper"><div class="web-civi-checkbox-set">',
686 '#parents' => array('reg_options', 'event_type'),
687 '#tree' => TRUE,
688 );
689 $this->form['participant']['show_past_events'] = array(
690 '#type' => 'select',
691 '#title' => t('Show Past Events'),
692 '#default_value' => wf_crm_aval($this->data, 'reg_options:show_past_events', 'now'),
693 '#parents' => array('reg_options', 'show_past_events'),
694 '#tree' => TRUE,
695 '#options' => array(
696 'now' => t('- None -'),
697 1 => t('All'),
698 '-1 day' => t('Past Day'),
699 '-1 week' => t('Past Week'),
700 '-1 month' => t('Past Month'),
701 '-2 month' => t('Past 2 Months'),
702 '-3 month' => t('Past 3 Months'),
703 '-6 month' => t('Past 6 Months'),
704 '-1 year' => t('Past Year'),
705 '-2 year' => t('Past 2 Years'),
706 ),
707 );
708 $this->help($this->form['participant']['show_past_events'], 'reg_options_show_past_events');
709 $this->form['participant']['show_future_events'] = array(
710 '#type' => 'select',
711 '#title' => t('Show Future Events'),
712 '#default_value' => wf_crm_aval($this->data, 'reg_options:show_future_events', 1),
713 '#parents' => array('reg_options', 'show_future_events'),
714 '#tree' => TRUE,
715 '#options' => array(
716 'now' => t('- None -'),
717 1 => t('All'),
718 '+1 day' => t('Next Day'),
719 '+1 week' => t('Next Week'),
720 '+1 month' => t('Next Month'),
721 '+2 month' => t('Next 2 Months'),
722 '+3 month' => t('Next 3 Months'),
723 '+6 month' => t('Next 6 Months'),
724 '+1 year' => t('Next Year'),
725 '+2 year' => t('Next 2 Years'),
726 ),
727 );
728 $this->help($this->form['participant']['show_future_events'], 'reg_options_show_future_events');
729 $this->form['participant']['title_display'] = array(
730 '#type' => 'select',
731 '#title' => t('Title Display'),
732 '#default_value' => wf_crm_aval($this->data, 'reg_options:title_display', 'title'),
733 '#suffix' => '</div>',
734 '#parents' => array('reg_options', 'title_display'),
735 '#tree' => TRUE,
736 '#options' => array(
737 'title' => t('Title Only'),
738 'title type' => t('Title + Event Type'),
739 'title start dateformatYear' => t('Title + Year'),
740 'title start dateformatPartial' => t('Title + Month + Year'),
741 'title start dateformatFull' => t('Title + Start-Date'),
742 'title start dateformatTime' => t('Title + Start-Time'),
743 'title start dateformatDatetime' => t('Title + Start-Date-Time'),
744 'title start end dateformatFull' => t('Title + Start-Date + End'),
745 'title start end dateformatTime' => t('Title + Start-Time + End'),
746 'title start end dateformatDatetime' => t('Title + Start-Date-Time + End'),
747 ),
748 );
749 $this->help($this->form['participant']['title_display'], 'reg_options_title_display');
750 $this->form['participant']['reg_options'] = array(
751 '#prefix' => '<div class="clearfix"> </div>',
752 '#suffix' => '</div>',
753 '#type' => 'fieldset',
754 '#title' => t('Registration Options'),
755 '#collapsible' => TRUE,
756 '#collapsed' => isset($this->data['participant']),
757 '#tree' => TRUE,
758 );
759 $field = array(
760 '#type' => 'select',
761 '#title' => t('Show Remaining Space in Events'),
762 '#default_value' => wf_crm_aval($this->data, 'reg_options:show_remaining', 0),
763 '#options' => array(
764 t('Never'),
765 'always' => t('Always'),
766 '0_full' => t('When full - 0 spaces left'),
767 ),
768 );
769 $this->help($field, 'reg_options_show_remaining');
770 foreach (array(5, 10, 20, 50, 100, 200, 500, 1000) as $num) {
771 $field['#options'][$num]['wrap'] = t('When under !num spaces left', array('!num' => $num));
772 }
773 $this->form['participant']['reg_options']['show_remaining'] = $field;
774 $this->form['participant']['reg_options']['validate'] = array(
775 '#type' => 'checkbox',
776 '#title' => t('Prevent Registration for Past/Full Events'),
777 '#default_value' => (bool) wf_crm_aval($this->data, 'reg_options:validate'),
778 );
779 $this->help($this->form['participant']['reg_options']['validate'], 'reg_options_validate');
780 $this->form['participant']['reg_options']['block_form'] = array(
781 '#type' => 'checkbox',
782 '#title' => t('Block Form Access when Event(s) are Full/Ended'),
783 '#default_value' => (bool) wf_crm_aval($this->data, 'reg_options:block_form'),
784 );
785 $this->form['participant']['reg_options']['disable_unregister'] = array(
786 '#type' => 'checkbox',
787 '#title' => t('Disable unregistering participants from unselected events.'),
788 '#default_value' => (bool) wf_crm_aval($this->data, 'reg_options:disable_unregister'),
789 );
790 $this->form['participant']['reg_options']['allow_url_load'] = array(
791 '#type' => 'checkbox',
792 '#title' => t('Allow events to be autoloaded from URL'),
793 '#default_value' => (bool) wf_crm_aval($this->data, 'reg_options:allow_url_load'),
794 );
795 $this->help($this->form['participant']['reg_options']['block_form'], 'reg_options_block_form');
796 $this->help($this->form['participant']['reg_options']['disable_unregister'], 'reg_options_disable_unregister');
797 $this->help($this->form['participant']['reg_options']['allow_url_load'], 'reg_options_allow_url_load');
798 $this->addAjaxItem('participant', 'participant_reg_type', 'participants');
799 $this->addAjaxItem('participant', 'event_type', 'participants');
800 $this->addAjaxItem('participant', 'show_past_events', 'participants');
801 $this->addAjaxItem('participant', 'show_future_events', 'participants');
802 $this->addAjaxItem('participant', 'title_display', 'participants');
803
804 for ($n = 1; $reg_type && (($n <= count($this->data['contact']) && $reg_type != 'all') || $n == 1); ++$n) {
805 $this->form['participant']['participants'][$n] = array(
806 '#type' => 'fieldset',
807 '#title' => $reg_type == 'all' ? t('Registration') : wf_crm_contact_label($n, $this->data, 'wrap'),
808 );
809 $num = wf_crm_aval($this->data, "participant:{$n}:number_of_participant");
810 if (!$num || ($n > 1 && $reg_type == 'all')) {
811 $num = 0;
812 }
813 $this->form['participant']['participants'][$n]['participant_' . $n . '_number_of_participant'] = array(
814 '#type' => 'select',
815 '#title' => $reg_type == 'all' ? t('Number of Event Sets') : t('Number of Event Sets for !contact', array('!contact' => wf_crm_contact_label($n, $this->data, 'wrap'))),
816 '#default_value' => $num,
817 '#options' => range(0, $this->sets['participant']['max_instances']),
818 '#prefix' => '<div class="number-of">',
819 '#suffix' => '</div>',
820 );
821 $this->addAjaxItem("participant:participants:{$n}", 'participant_' . $n . '_number_of_participant', 'div');
822 $particpant_extensions = array(
823 1 => 'role_id',
824 2 => 'event_id',
825 3 => 'event_type'
826 );
827 for ($e = 1; $e <= $num; ++$e) {
828 $fs = "participant_{$n}_event_{$e}_fieldset";
829 $this->form['participant']['participants'][$n]['div'][$fs] = array(
830 '#type' => 'fieldset',
831 '#title' => t('Event !num', array('!num' => $e)),
832 '#attributes' => array('id' => $fs),
833 );
834 foreach ($this->sets as $sid => $set) {
835 if ($set['entity_type'] == 'participant') {
836 $sid = 'civicrm_' . $n . '_participant_' . $e . '_' . $sid . '_fieldset';
837 $class = 'web-civi-checkbox-set';
838 if (!empty($set['sub_types'])) {
839 $role_id = wf_crm_aval($this->data, "participant:$n:particpant:$e:role_id", '');
840 $event_id = wf_crm_aval($this->data, "participant:$n:particpant:$e:event_id", '');
841 $event_type = wf_crm_aval($this->data, 'reg_options:event_type', '');
842 if ($event_id && $event_id !== 'create_civicrm_webform_element') {
843 list($event_id, $event_type) = explode('-', $event_id);
844 }
845 $ext = $particpant_extensions[$set['extension_of']];
846 if (!in_array($$ext, $set['sub_types'])) {
847 $class .= ' hidden';
848 }
849 $class .= ' extends-condition ' . str_replace('_', '', $ext) . '-' . implode('-', $set['sub_types']);
850 }
851 $this->form['participant']['participants'][$n]['div'][$fs][$sid] = array(
852 '#type' => 'fieldset',
853 '#title' => $set['label'],
854 '#attributes' => array('id' => $sid, 'class' => array($class)),
855 'js_select' => $this->addToggle($sid),
856 );
857 foreach ($set['fields'] as $fid => $field) {
858 $id = 'civicrm_' . $n . '_participant_' . $e . '_' . $fid;
859 $item = $this->addItem($id, $field);
860 if ($fid == 'participant_event_id') {
861 $item['#prefix'] = '<div class="auto-width">';
862 $item['#suffix'] = '</div>';
863 }
864 if ($fid == 'participant_event_id' || $fid == 'participant_role_id') {
865 $item['#attributes']['onchange'] = "wfCiviAdmin.participantConditional('#$fs');";
866 $item['#attributes']['class'][] = $fid;
867 $$fid = wf_crm_aval($item, '#default_value');
868 }
869 $this->form['participant']['participants'][$n]['div'][$fs][$sid][$id] = $item;
870 }
871 }
872 }
873 }
874 }
875 }
876
877 /**
878 * Membership settings
879 */
880 private function buildMembershipTab() {
881 $this->form['membership'] = array(
882 '#type' => 'fieldset',
883 '#title' => t('Memberships'),
884 '#group' => 'webform_civicrm',
885 '#attributes' => array('class' => array('civi-icon-membership')),
886 );
887 for ($c = 1; $c <= count($this->data['contact']); ++$c) {
888 $num = wf_crm_aval($this->data, "membership:{$c}:number_of_membership", 0);
889 $this->form['membership'][$c]["membership_{$c}_number_of_membership"] = array(
890 '#type' => 'select',
891 '#title' => t('Number of Memberships for !contact', array('!contact' => wf_crm_contact_label($c, $this->data, 'wrap'))),
892 '#default_value' => $num,
893 '#options' => range(0, 9),
894 '#prefix' => '<div class="number-of">',
895 '#suffix' => '</div>',
896 );
897 $this->addAjaxItem("membership:$c", "membership_{$c}_number_of_membership", "membership");
898 for ($n = 1; $n <= $num; ++$n) {
899 $fs = "membership_{$c}_membership_{$n}_fieldset";
900 $this->form['membership'][$c]['membership'][$fs] = array(
901 '#type' => 'fieldset',
902 '#title' => t('Membership !num for !contact', array('!num' => $n, '!contact' => wf_crm_contact_label($c, $this->data, 'wrap'))),
903 '#attributes' => array('id' => $fs, 'class' => array('web-civi-checkbox-set')),
904 'js_select' => $this->addToggle($fs),
905 );
906 foreach ($this->sets as $sid => $set) {
907 if ($set['entity_type'] == 'membership') {
908 foreach ($set['fields'] as $fid => $field) {
909 $fid = "civicrm_{$c}_membership_{$n}_$fid";
910 $this->form['membership'][$c]['membership'][$fs][$fid] = $this->addItem($fid, $field);
911 }
912 }
913 }
914 }
915 }
916 }
917
918 /**
919 * Contribution settings
920 */
921 private function buildContributionTab() {
922 $this->form['contribution'] = array(
923 '#type' => 'fieldset',
924 '#title' => t('Contribution'),
925 '#group' => 'webform_civicrm',
926 '#description' => t('In order to process live transactions for events, memberships, or contributions, select a contribution page and its billing fields will be included on the webform.'),
927 '#attributes' => array('class' => array('civi-icon-contribution')),
928 );
929 $fid = 'civicrm_1_contribution_1_contribution_contribution_page_id';
930 $this->form['contribution'][$fid] = $this->addItem($fid, $this->fields['contribution_contribution_page_id']);
931 unset($this->sets['contribution']['fields']['contribution_contribution_page_id']);
932 $this->addAjaxItem('contribution', $fid, 'sets');
933 $page_id = wf_crm_aval($this->data, 'contribution:1:contribution:1:contribution_page_id');
934 if ($page_id) {
935 $page = wf_civicrm_api('contribution_page', 'getsingle', array('id' => $page_id));
936 }
937 if (!$page_id || empty($page['financial_type_id'])) {
938 return;
939 }
940 // Make sure webform is set-up to prevent credit card abuse.
941 $this->checkSubmissionLimit();
942 // Add contribution fields
943 foreach ($this->sets as $sid => $set) {
944 if ($set['entity_type'] == 'contribution' && (empty($set['sub_types']) || $set['sub_types'][0] == $page['financial_type_id'])) {
945 $this->form['contribution']['sets'][$sid] = array(
946 '#type' => 'fieldset',
947 '#title' => $set['label'],
948 '#attributes' => array('id' => $sid, 'class' => array('web-civi-checkbox-set')),
949 'js_select' => $this->addToggle($sid),
950 );
951 foreach ($set['fields'] as $fid => $field) {
952 $fid = "civicrm_1_contribution_1_$fid";
953 $this->form['contribution']['sets'][$sid][$fid] = $this->addItem($fid, $field);
954 }
955 }
956 }
957 }
958
959 /**
960 * Grant settings
961 * FIXME: This is nearly the same code as buildCaseTab. More utilities and less boilerplate needed.
962 */
963 private function buildGrantTab() {
964 $types = wf_crm_apivalues('grant', 'getoptions', array('field' => 'grant_type_id'));
965 if (!$types) {
966 return;
967 }
968 $this->form['grantTab'] = array(
969 '#type' => 'fieldset',
970 '#title' => t('Grants'),
971 '#group' => 'webform_civicrm',
972 '#attributes' => array('class' => array('civi-icon-grant')),
973 );
974 $this->form['grantTab']["grant_number_of_grant"] = array(
975 '#type' => 'select',
976 '#title' => t('Number of Grants'),
977 '#default_value' => $num = wf_crm_aval($this->data, "grant:number_of_grant", 0),
978 '#options' => range(0, $this->sets['grant']['max_instances']),
979 '#prefix' => '<div class="number-of">',
980 '#suffix' => '</div>',
981 );
982 $this->addAjaxItem("grantTab", "grant_number_of_grant", "grant");
983 for ($n = 1; $n <= $num; ++$n) {
984 $fs = "grant_grant_{$n}_fieldset";
985 $this->form['grantTab']['grant'][$fs] = array(
986 '#type' => 'fieldset',
987 '#title' => t('Grant !num', array('!num' => $n)),
988 'wrap' => array('#weight' => 9),
989 );
990 $this->form['grantTab']['grant'][$fs]["grant_{$n}_settings_existing_grant_status"] = array(
991 '#type' => 'select',
992 '#title' => t('Update Existing Grant'),
993 '#options' => array('' => '- ' . t('None') . ' -') + wf_crm_apivalues('grant', 'getoptions', array('field' => 'status_id')),
994 '#default_value' => wf_crm_aval($this->data, "grant:{$n}:existing_grant_status", array()),
995 '#multiple' => TRUE,
996 );
997 $this->help($this->form['grantTab']['grant'][$fs]["grant_{$n}_settings_existing_grant_status"], 'existing_grant_status');
998 $grant_type = wf_crm_aval($this->data, "grant:{$n}:grant:1:grant_type_id");
999 foreach ($this->sets as $sid => $set) {
1000 if ($set['entity_type'] == 'grant' && (!$grant_type || empty($set['sub_types']) || in_array($grant_type, $set['sub_types']))) {
1001 $fs1 = "grant_grant_{$n}_fieldset_$sid";
1002 if ($sid == 'grant') {
1003 $pos = &$this->form['grantTab']['grant'][$fs];
1004 }
1005 else {
1006 $pos = &$this->form['grantTab']['grant'][$fs]['wrap'];
1007 }
1008 $pos[$fs1] = array(
1009 '#type' => 'fieldset',
1010 '#title' => $set['label'],
1011 '#attributes' => array('id' => $fs1, 'class' => array('web-civi-checkbox-set')),
1012 'js_select' => $this->addToggle($fs1),
1013 );
1014 foreach ($set['fields'] as $fid => $field) {
1015 $fid = "civicrm_{$n}_grant_1_$fid";
1016 $pos[$fs1][$fid] = $this->addItem($fid, $field);
1017 }
1018 }
1019 }
1020 $this->addAjaxItem("grantTab:grant:$fs:grant_grant_{$n}_fieldset_grant", "civicrm_{$n}_grant_1_grant_grant_type_id", "..:wrap");
1021 }
1022 }
1023
1024 /**
1025 * Configure additional options
1026 */
1027 private function buildOptionsTab() {
1028 $this->form['options'] = array(
1029 '#type' => 'fieldset',
1030 '#title' => t('Additional Options'),
1031 '#group' => 'webform_civicrm',
1032 '#attributes' => array('class' => array('civi-icon-prefs')),
1033 '#description' => '<p>' .
1034 t('To have this form auto-filled for anonymous users, enable the "Existing Contact" field for !contact and send the following link from CiviMail:', array('!contact' => wf_crm_contact_label(1, $this->data, TRUE))) .
1035 '<br /><code>' . url("node/{$this->node->nid}", array('absolute' => TRUE, 'query' => array('cid1' => ''))) . '{contact.contact_id}&amp;{contact.checksum}</code></p>',
1036 );
1037 $this->form['options']['create_fieldsets'] = array(
1038 '#type' => 'checkbox',
1039 '#title' => t('Create Fieldsets'),
1040 '#default_value' => (bool) $this->settings['create_fieldsets'],
1041 '#description' => t('Create a fieldset around each contact. Provides visual organization of your form. Also allows the contact clone feature to work.'),
1042 );
1043 $this->form['options']['confirm_subscription'] = array(
1044 '#type' => 'checkbox',
1045 '#title' => t('Confirm Subscriptions'),
1046 '#default_value' => (bool) $this->settings['confirm_subscription'],
1047 '#description' => t('Recommended. Send a confirmation email before adding contacts to publicly subscribable mailing list groups.') . '<br />' . t('Your public mailing lists:') . ' <em>',
1048 );
1049 $ml = wf_crm_apivalues('group', 'get', array('is_hidden' => 0, 'visibility' => 'Public Pages', 'group_type' => 2), 'title');
1050 if ($ml) {
1051 if (count($ml) > 4) {
1052 $ml = array_slice($ml, 0, 3);
1053 $ml[] = t('etc.');
1054 }
1055 $this->form['options']['confirm_subscription']['#description'] .= implode(', ', $ml) . '</em>';
1056 }
1057 else {
1058 $this->form['options']['confirm_subscription']['#description'] .= t('none') . '</em>';
1059 }
1060 $this->form['options']['block_unknown_users'] = array(
1061 '#type' => 'checkbox',
1062 '#title' => t('Block Unknown Users'),
1063 '#default_value' => !empty($this->settings['block_unknown_users']),
1064 '#description' => t('Only allow users to see this form if they are logged in or following a personalized link from CiviMail.'),
1065 );
1066 $this->form['options']['new_contact_source'] = array(
1067 '#type' => 'textfield',
1068 '#title' => t('Source Label'),
1069 '#maxlength' => 255,
1070 '#size' => 30,
1071 '#default_value' => $this->settings['new_contact_source'],
1072 '#description' => t('Optional "source" label for any new contact/participant/membership created by this webform.'),
1073 );
1074 }
1075
1076 private function checkSubmissionLimit() {
1077 $webform = &$this->node->webform;
1078 // If anonymous users don't have access to the form, no need for a warning.
1079 if (!in_array('1', $webform['roles'])) {
1080 return;
1081 }
1082 // Handle ajax submission from "submit_limit" mini-form below
1083 if (!empty($_POST['submit_limit']) && !empty($_POST['submit_interval'])) {
1084 $submit_limit = (int) $_POST['submit_limit'];
1085 $submit_interval = (int) $_POST['submit_interval'];
1086 if ($submit_limit > 0 && $submit_interval != 0) {
1087 $webform['submit_limit'] = $submit_limit;
1088 $webform['submit_interval'] = $submit_interval;
1089 db_update('webform')
1090 ->condition('nid', $this->node->nid)
1091 ->fields(array('submit_limit' => $submit_limit, 'submit_interval' => $submit_interval))
1092 ->execute();
1093 }
1094 drupal_set_message(t('Per-user submission limit has been updated. You may revisit these options any time on the <em>Form Settings</em> tab of this webform.'));
1095 }
1096 // Handle ajax submission from "webform_tracking_mode" mini-form below
1097 if (!empty($_POST['webform_tracking_mode']) && $_POST['webform_tracking_mode'] == 'strict') {
1098 variable_set('webform_tracking_mode', 'strict');
1099 drupal_set_message(t('Webform anonymous user tracking has been updated to use the strict method. You may revisit this option any time on the global <a !link>Webform Settings</a> page.',
1100 array('!link' => 'href="/admin/config/content/webform" target="_blank"')
1101 ));
1102 }
1103 // Mini-form to configure submit limit without leaving the page
1104 if ($webform['submit_limit'] == -1) {
1105 $this->form['contribution']['sets']['submit_limit'] = array(
1106 '#markup' => '<div class="messages warning">' .
1107 t('To prevent Credit Card abuse, it is recommended to set the per-user submission limit for this form.') .
1108 ' &nbsp; <button id="configure-submit-limit" type="button">' . t('Configure') . '</button>' .
1109 '<div id="submit-limit-wrapper" style="display:none">' .
1110 t('Limit each user to') .
1111 ' <input class="form-text" type="number" maxlength="2" size="2" name="submit_limit"> ' .
1112 t('submission(s)') . ' <select class="form-select" name="submit_interval">' .
1113 '<option value="-1">' .t('ever') . '</option>' .
1114 '<option value="3600" selected="selected">' .t('every hour') . '</option>' .
1115 '<option value="86400">' .t('every day') . '</option>' .
1116 '<option value="604800">' .t('every week') . '</option>'.
1117 '</select> &nbsp; ' .
1118 ' <button id="configure-submit-limit-save" type="button">' . t('Save') . '</button>' .
1119 ' <button id="configure-submit-limit-cancel" type="button">' . t('Cancel') . '</button>' .
1120 '</div>' .
1121 '</div>',
1122 );
1123 }
1124 // Mini-form to conveniently update global cookie setting
1125 elseif (variable_get('webform_tracking_mode', 'cookie') == 'cookie') {
1126 $this->form['contribution']['sets']['webform_tracking_mode'] = array(
1127 '#markup' => '<div class="messages warning">' .
1128 t('Per-user submission limit is enabled for this form, however the webform anonymous user tracking method is configured to use cookies only, which is not secure enough to prevent Credit Card abuse.') .
1129 ' <button id="webform-tracking-mode" type="button">' . t('Change Now') . '</button>' .
1130 ' <input type="hidden" value="" name="webform_tracking_mode"> ' .
1131 '</div>'
1132 );
1133 }
1134 }
1135
1136 /**
1137 * Set defaults when visiting the civicrm tab for the first time
1138 */
1139 private function defaultSettings() {
1140 return array(
1141 'data' => array(
1142 'contact' => array(
1143 1 => array(
1144 'contact' => array(
1145 1 => array(
1146 'contact_type' => 'individual',
1147 'contact_sub_type' => array(),
1148 ),
1149 ),
1150 ),
1151 ),
1152 'reg_options' => array(
1153 'validate' => 1,
1154 ),
1155 ),
1156 'confirm_subscription' => 1,
1157 'create_fieldsets' => 1,
1158 'new_contact_source' => check_plain($this->node->title),
1159 'civicrm_1_contact_1_contact_first_name' => 'create_civicrm_webform_element',
1160 'civicrm_1_contact_1_contact_last_name' => 'create_civicrm_webform_element',
1161 'civicrm_1_contact_1_contact_existing' => 'create_civicrm_webform_element',
1162 );
1163 }
1164
1165 /**
1166 * Build a field item for the admin form
1167 *
1168 * @param string $fid
1169 * civicrm field id
1170 * @param array $field
1171 * Webform field info
1172 *
1173 * @return array
1174 * FAPI form item array for the admin form
1175 */
1176 private function addItem($fid, $field) {
1177 list(, $c, $ent, $n, $table, $name) = explode('_', $fid, 6);
1178 $item = array(
1179 // We don't need numbers on the admin form since they are already grouped in fieldsets
1180 '#title' => str_replace('#', '', $field['name']),
1181 '#attributes' => wf_crm_aval($field, 'attributes'),
1182 );
1183
1184 // Create dropdown list
1185 if (!empty($field['expose_list'])) {
1186 $field['form_key'] = $fid;
1187 // Retrieve option list
1188 $options = array();
1189 // Placeholder empty option - used by javascript when displaying multiselect as single
1190 if (!empty($field['extra']['multiple']) && empty($field['extra']['required'])) {
1191 $options += array('' => '- ' . t('None') . ' -');
1192 }
1193 // This prevents the multi-select js from adding an illegal empty option
1194 if (!empty($field['extra']['required'])) {
1195 $item['#attributes']['class'][] = 'required';
1196 }
1197 if ($field['type'] != 'hidden') {
1198 $options += array('create_civicrm_webform_element' => t('- User Select -'));
1199 }
1200 $options += wf_crm_field_options($field, 'config_form', $this->data);
1201 $item += array(
1202 '#type' => 'select',
1203 '#options' => $options,
1204 '#multiple' => !empty($field['extra']['multiple']),
1205 '#default_value' => !empty($field['empty_option']) ? 0 : NULL,
1206 );
1207 if (isset($field['empty_option'])) {
1208 $item['#empty_option'] = '- ' . $field['empty_option'] . ' -';
1209 $item['#empty_value'] = 0;
1210 }
1211 if (isset($field['data_type'])) {
1212 $item['#attributes']['data-type'] = $field['data_type'];
1213 }
1214 // Five ways to get default value...
1215 // 1: From current form state
1216 if (isset($this->settings[$fid]) && ($field['type'] != 'hidden')) {
1217 $item['#default_value'] = $this->settings[$fid];
1218 }
1219 // 2: From saved settings
1220 elseif (isset($this->data[$ent][$c][$table][$n][$name])) {
1221 $item['#default_value'] = $this->data[$ent][$c][$table][$n][$name];
1222 }
1223 // 3: From callback function
1224 elseif (isset($field['value_callback'])) {
1225 $method = 'get_default_' . $table . '_' . $name;
1226 $item['#default_value'] = self::$method($fid, $options);
1227 }
1228 // 4: From field default
1229 elseif (isset($field['value'])) {
1230 $item['#default_value'] = $field['value'];
1231 }
1232 // 5: For required fields like phone type, default to the first option
1233 elseif (empty($field['extra']['multiple']) && !isset($field['empty_option'])) {
1234 $options = array_keys($options);
1235 $item['#default_value'] = $options[1];
1236 }
1237 if (!empty($field['extra']['multiple'])) {
1238 $item['#default_value'] = (array) $item['#default_value'];
1239 if (isset($this->settings[$fid]) && !is_array($this->settings[$fid])
1240 && isset($this->data[$ent][$c][$table][$n][$name])) {
1241 $item['#default_value'] += (array) $this->data[$ent][$c][$table][$n][$name];
1242 }
1243 }
1244 }
1245 // Create checkbox
1246 else {
1247 $item += array(
1248 '#type' => 'checkbox',
1249 '#return_value' => 'create_civicrm_webform_element',
1250 '#default_value' => !empty($this->settings[$fid]),
1251 );
1252 }
1253 // Add help
1254 $topic = $table . '_' . $name;
1255 if (method_exists('wf_crm_admin_help', $topic)) {
1256 $this->help($item, $topic);
1257 }
1258 elseif (!empty($field['has_help'])) {
1259 $this->help($item, $name);
1260 }
1261 elseif (wf_crm_aval($field, 'data_type') == 'ContactReference') {
1262 $this->help($item, 'contact_reference');
1263 }
1264 elseif (!empty($field['expose_list']) && !empty($field['extra']['multiple'])) {
1265 $this->help($item, 'multiselect_options', t('Multiple Select Options'));
1266 }
1267 return $item;
1268 }
1269
1270 /**
1271 * Boilerplate-reducing helper function for FAPI ajax.
1272 * Set an existing form element to control an ajax container.
1273 * The container will be created if it doesn't already exist.
1274 *
1275 * @param string $path
1276 * A : separated string of nested array keys leading to the control element's parent
1277 * @param string $control_element
1278 * Array key of the existing element to add ajax behavior to
1279 * @param string $container
1280 * Path to the key of the container to be created (relative to $path) use '..' to go up a level
1281 * @param string $class
1282 * Css class to add to target container
1283 */
1284 private function addAjaxItem($path, $control_element, $container, $class='civicrm-ajax-wrapper') {
1285 // Get a reference to the control container
1286 // For anyone who wants to call this evil - I challenge you to find a better way to accomplish this
1287 eval('$control_container = &$this->form[\'' . str_replace(':', "']['", $path) . "'];");
1288 // Now find the container element (may be outside the $path if .. is used)
1289 foreach (explode(':', $container) as $level) {
1290 if ($level == '..') {
1291 $path = substr($path, 0, strrpos($path, ':'));
1292 }
1293 else {
1294 $path .= ':' . $level;
1295 }
1296 }
1297 eval('$target_container = &$this->form[\'' . str_replace(':', "']['", substr($path, 0, strrpos($path, ':'))) . "'];");
1298 $id = 'civicrm-ajax-' . str_replace(array(':', '_'), '-', $path);
1299 $control_container[$control_element]['#ajax'] = array(
1300 'callback' => 'wf_crm_configure_form_ajax',
1301 'pathstr' => $path,
1302 'wrapper' => $id,
1303 'effect' => 'fade',
1304 );
1305 if (!isset($target_container[$level])) {
1306 $target_container[$level] = array();
1307 }
1308 $target_container[$level]['#prefix'] = '<div class="' . $class . '" id="' . $id . '">';
1309 $target_container[$level]['#suffix'] = '</div>';
1310 }
1311
1312 /**
1313 * Build select all/none js links for a fieldset
1314 */
1315 private function addToggle($name) {
1316 return array('#markup' =>
1317 '<div class="web-civi-js-select">
1318 <a href="javascript:wfCiviAdmin.selectReset(' . "'all', '#$name'" . ')">' . t('Select All') . '</a> |
1319 <a href="javascript:wfCiviAdmin.selectReset(' . "'none', '#$name'" . ')">' . t('Select None') . '</a> |
1320 <a href="javascript:wfCiviAdmin.selectReset(' . "'reset', '#$name'" . ')">' . t('Restore') . '</a>
1321 </div>',
1322 );
1323 }
1324
1325 /**
1326 * Build $this->data array for webform settings; called while rebuilding or post-processing the admin form.
1327 */
1328 private function rebuildData() {
1329 $this->settings['data'] = array('contact' => array());
1330 $this->data = &$this->settings['data'];
1331 list($contact_types, $sub_types) = wf_crm_get_contact_types();
1332 for ($c = 1; $c <= $this->settings['number_of_contacts']; ++$c) {
1333 // Contact settings
1334 if (isset($this->settings[$c . '_contact_type'])) {
1335 $this->data['contact'][$c] = array(
1336 'contact' => array(1 => array(
1337 'contact_type' => $this->settings[$c . '_contact_type'],
1338 'contact_sub_type' => array(),
1339 'webform_label' => $this->settings[$c . '_webform_label'],
1340 )),
1341 );
1342 if ($sub_type = wf_crm_aval($this->settings, 'civicrm_' . $c . '_contact_1_contact_contact_sub_type')) {
1343 $allowed = wf_crm_aval($sub_types, $this->settings[$c . '_contact_type'], array());
1344 foreach ($sub_type as $sub) {
1345 if (isset($allowed[$sub])) {
1346 $this->data['contact'][$c]['contact'][1]['contact_sub_type'][$sub] = $sub;
1347 }
1348 }
1349 }
1350 }
1351 // Add new contact to the form
1352 else {
1353 $this->data['contact'][$c] = array(
1354 'contact' => array(1 => array(
1355 'contact_type' => 'individual',
1356 'contact_sub_type' => array(),
1357 )),
1358 'matching_rule' => 'Unsupervised',
1359 );
1360 // Set defaults for new contact
1361 $this->settings += array(
1362 'civicrm_' . $c . '_contact_1_contact_first_name' => 'create_civicrm_webform_element',
1363 'civicrm_' . $c . '_contact_1_contact_last_name' => 'create_civicrm_webform_element',
1364 );
1365 $link = array('!link' => 'href="http://wiki.civicrm.org/confluence/display/CRMDOC/Webform+CiviCRM+Integration#WebformCiviCRMIntegration-CloningaContact" target="_blank"');
1366 drupal_set_message(t('Tip: Consider using the clone feature to add multiple similar contacts. (<a !link>more info</a>)', $link), 'status', FALSE);
1367 }
1368 }
1369 // Store meta settings, i.e. number of email for contact 1
1370 foreach ($this->settings as $key => $val) {
1371 if (strpos($key, '_number_of_') !== FALSE) {
1372 list($ent, $c, $key) = explode('_', $key, 3);
1373 if (isset($this->data[$ent][$c]) || $ent == 'participant' || $ent == 'membership') {
1374 $this->data[$ent][$c][$key] = $val;
1375 }
1376 // Standalone entities keep their own count independent of contacts
1377 elseif ($ent == 'grant' || $ent == 'activity' || $ent == 'case') {
1378 $this->data[$ent]["number_$key"] = $val;
1379 }
1380 }
1381 elseif (strpos($key, '_settings_') !== FALSE) {
1382 list($ent, $c, , $key) = explode('_', $key, 4);
1383 $val = is_array($val) ? array_filter($val) : $val;
1384 // Don't store settings for nonexistant contacts. Todo: check other entities
1385 if (isset($this->data[$ent][$c]) || $ent !== 'contact') {
1386 $this->data[$ent][$c][$key] = $val;
1387 }
1388 }
1389 }
1390 // Defaults when adding an activity
1391 for ($i=1; $i <= $this->settings['activity_number_of_activity']; ++$i) {
1392 if (!isset($this->settings["activity_{$i}_settings_existing_activity_status"])) {
1393 $this->data['activity'][$i]['activity'][1]['target_contact_id'] = range(1, $this->settings['number_of_contacts']);
1394 }
1395 }
1396 // Defaults when adding a case
1397 for ($i=1; $i <= wf_crm_aval($this->settings, 'case_number_of_case'); ++$i) {
1398 if (!isset($this->settings["civicrm_{$i}_case_1_case_case_type_id"])) {
1399 $case_types = array_keys(wf_crm_apivalues('Case', 'getoptions', array('field' => 'case_type_id')));
1400 $this->data['case'][$i]['case'][1]['case_type_id'] = $case_types[0];
1401 }
1402 }
1403 // Store event settings
1404 if (isset($this->settings['participant_reg_type'])) {
1405 $this->data['participant_reg_type'] = $this->settings['participant_reg_type'];
1406 $this->data['reg_options'] = $this->settings['reg_options'];
1407 }
1408 // Add settings exposed to the back-end to data
1409 foreach ($this->settings as $key => $val) {
1410 if (substr($key, 0, 7) == 'civicrm') {
1411 list(, $c, $ent, $n, $table, $name) = explode('_', $key, 6);
1412 if (is_array($val)) {
1413 // Git rid of the "User Select" and "None" options
1414 unset($val['create_civicrm_webform_element'], $val['']);
1415 }
1416 elseif ($val === 'create_civicrm_webform_element') {
1417 $val = '';
1418 }
1419 // Saves all non-empty values with a hack for fields which needs to be saved even when 0
1420 // FIXME: Really ought to change the select placeholder value to be '' instead of 0
1421 if (isset($this->fields[$table . '_' . $name]['expose_list']) &&
1422 (!empty($val) || (in_array($name, array('num_terms', 'is_active', 'is_test'))))) {
1423 // Don't add data for non-existent contacts
1424 if (!in_array($ent, array('contact', 'participant', 'membership')) || isset($this->data['contact'][$c])) {
1425 $this->data[$ent][$c][$table][$n][$name] = $val;
1426 }
1427 }
1428 }
1429 }
1430 }
1431
1432 /**
1433 * Submission handler, saves CiviCRM options for a Webform node
1434 */
1435 public function postProcess() {
1436 $button = $this->form_state['clicked_button']['#id'];
1437 $nid = $this->node->nid;
1438 $this->settings = wf_crm_aval($this->form_state, 'storage:vals', $this->form_state['values']);
1439
1440 if ((empty($this->node->webform_civicrm) && !$this->settings['nid']) || $button == 'edit-cancel') {
1441 $this->form_state['rebuild'] = TRUE;
1442 unset($this->form_state['storage']['msg']);
1443 return;
1444 }
1445 unset($this->form_state['storage']);
1446
1447 $enabled = $existing = wf_crm_enabled_fields($this->node, NULL, TRUE);
1448 $delete_me = $this->getFieldsToDelete($enabled);
1449
1450 // Display a confirmation before deleting fields
1451 if ($delete_me && $button == 'edit-submit') {
1452 $msg = '<p>' . t('These existing fields are no longer needed for CiviCRM processing based on your new form settings.') . '</p><ul>';
1453 foreach ($delete_me as $key => $id) {
1454 list(, $c, $ent, $n, $table, $name) = explode('_', $key, 6);
1455 $info = '';
1456 if ($ent == 'contact' || $ent == 'participant') {
1457 $info = '<em>' . wf_crm_contact_label($c, wf_crm_aval($this->node, 'webform_civicrm:data'));
1458 }
1459 if ($info && isset($this->sets[$table]['max_instances'])) {
1460 $info .= ' ' . $this->sets[$table]['label'] . ' ' . $n;
1461 }
1462 $info .= $info ? ':</em> ' : '';
1463 $msg .= '<li>' . $info . $this->node->webform['components'][$id]['name'] . '</li>';
1464 }
1465 $msg .= '</ul><p>' . t('Would you like them to be automatically removed from the webform? This is recommended unless you need to keep webform-results information from these fields. (They can still be deleted manually later if you choose not to remove them now.)') . '</p><p><em>' . t('Note: Deleting webform components cannot be undone, and will result in the loss of webform-results info for those elements. Data in the CiviCRM database will not be affected.') . '</em></p>';
1466 $this->form_state['storage']['msg'] = $msg;
1467 $this->form_state['storage']['vals'] = $this->settings;
1468 $this->form_state['rebuild'] = TRUE;
1469 return;
1470 }
1471
1472 module_load_include('inc', 'webform', 'includes/webform.components');
1473 module_load_include('inc', 'webform_civicrm', 'includes/contact_component');
1474 $this->form_state['redirect'] = 'node/' . $nid . '/webform';
1475
1476 // Delete/disable fields
1477 $deleted = 0;
1478 if ($button === 'edit-delete' || ($button === 'edit-disable' && $this->settings['nid'])) {
1479 foreach ($delete_me as $id) {
1480 $field = $this->node->webform['components'][$id];
1481 unset($enabled[$field['form_key']]);
1482 ++$deleted;
1483 if ($button === 'edit-delete') {
1484 webform_component_delete($this->node, $field);
1485 }
1486 else {
1487 $field['form_key'] = 'disabled' . substr($field['form_key'], 7);
1488 webform_component_update($field);
1489 }
1490 }
1491 if ($deleted == 1) {
1492 $p = array('%name' => $field['name']);
1493 drupal_set_message($button === 'edit-delete' ? t('Deleted field: %name', $p) : t('Disabled field: %name', $p));
1494 }
1495 else {
1496 $p = array('!num' => $deleted);
1497 drupal_set_message($button === 'edit-delete' ? t('Deleted !num fields.', $p) : t('Disabled !num fields.', $p));
1498 }
1499 if ($button === 'edit-disable') {
1500 drupal_set_message(t('Disabled fields will still be processed as normal Webform fields, but they will not be autofilled from or saved to the CiviCRM database.'));
1501 }
1502 else {
1503 // Remove empty fieldsets for deleted contacts
1504 foreach ($enabled as $key => $id) {
1505 if (substr($key, -8) == 'fieldset') {
1506 list(, $c, $ent, $i) = explode('_', $key);
1507 if ($ent == 'contact' && $i == 1 && (!$this->settings['nid'] || $c > $this->settings['number_of_contacts'])) {
1508 if (!_wf_crm_child_components($this->node->nid, $id)) {
1509 webform_component_delete($this->node, $this->node->webform['components'][$id]);
1510 }
1511 }
1512 }
1513 }
1514 }
1515 }
1516
1517 // Disable CiviCRM for this form
1518 if (!$this->settings['nid']) {
1519 $this->disable();
1520 drupal_set_message(t('CiviCRM processing for this form is now disabled.'));
1521 }
1522
1523 // CiviCRM enabled
1524 else {
1525 webform_ensure_record($this->node);
1526 $this->rebuildData();
1527 if (!$this->settings['toggle_message']) {
1528 $this->settings['message'] = '';
1529 }
1530 // Index disabled components
1531 $disabled = array();
1532 foreach (wf_crm_aval($this->node->webform, 'components', array()) as $field) {
1533 if (substr($field['form_key'], 0, 9) === 'disabled_') {
1534 $field['form_key'] = 'civicrm' . substr($field['form_key'], 8);
1535 $disabled[$field['form_key']] = $field;
1536 }
1537 }
1538
1539 $i = 0;
1540 $created = array();
1541 foreach ($this->settings as $key => $val) {
1542 if (substr($key, 0, 7) == 'civicrm') {
1543 ++$i;
1544 $field = wf_crm_get_field($key);
1545 if (!isset($enabled[$key])) {
1546 $val = (array) $val;
1547 if (in_array('create_civicrm_webform_element', $val, TRUE) || (!empty($val[0]) && $field['type'] == 'hidden')) {
1548 // Restore disabled component
1549 if (isset($disabled[$key])) {
1550 webform_component_update($disabled[$key]);
1551 $enabled[$key] = $disabled[$key]['cid'];
1552 drupal_set_message(t('Re-enabled field: %name', array('%name' => $disabled[$key]['name'])));
1553 }
1554 // Create new component
1555 else {
1556 $field += array(
1557 'nid' => $nid,
1558 'form_key' => $key,
1559 'weight' => $i,
1560 );
1561 self::insertComponent($field, $enabled, $this->settings);
1562 $created[] = $field['name'];
1563 if (isset($field['civicrm_condition'])) {
1564 $this->addConditionalRule($field, $enabled);
1565 }
1566 }
1567 }
1568 }
1569 elseif ($field['type'] == 'hidden' && !empty($field['expose_list'])) {
1570 $component = $this->node->webform['components'][$enabled[$key]];
1571 $component['value'] = $val;
1572 webform_component_update($component);
1573 }
1574 }
1575 }
1576 if (count($created) == 1) {
1577 drupal_set_message(t('Added field: %name', array('%name' => $created[0])));
1578 }
1579 elseif ($created) {
1580 drupal_set_message(t('Added !num fields to the form.', array('!num' => count($created))));
1581 }
1582
1583 // Create record
1584 if (empty($this->node->webform_civicrm)) {
1585 drupal_write_record('webform_civicrm_forms', $this->settings);
1586 drupal_set_message(t('CiviCRM processing for this form is now enabled.'));
1587 }
1588 // Update record
1589 else {
1590 drupal_write_record('webform_civicrm_forms', $this->settings, 'nid');
1591 drupal_set_message(t('Your CiviCRM form settings have been updated.'));
1592 }
1593 // Update existing contact fields
1594 foreach ($existing as $fid => $id) {
1595 if (substr($fid, -8) === 'existing') {
1596 wf_crm_update_existing_component($this->node->webform['components'][$id], $enabled, $this->data);
1597 }
1598 }
1599 }
1600 // Make sure the updates are visible to anonymous users.
1601 cache_clear_all();
1602
1603 // Clear the entity cache.
1604 if (module_exists('entitycache')) {
1605 cache_clear_all($nid, 'cache_entity_node');
1606 }
1607 }
1608
1609 /**
1610 * Create a conditional rule if the source and target fields both exist.
1611 * TODO: This is fairly minimal. It doesn't check if the rule already exists,
1612 * and doesn't work if both fields haven't been created yet.
1613 *
1614 * @param array $field
1615 * @param array $enabled
1616 */
1617 private function addConditionalRule($field, $enabled) {
1618 list(, $c, $ent, $n, $table, $name) = explode('_', $field['form_key'], 6);
1619 $rgid = $weight = -1;
1620 foreach ($this->node->webform['conditionals'] as $rgid => $existing) {
1621 $weight = $existing['weight'];
1622 }
1623 $rgid++;
1624 $rule_group = $field['civicrm_condition'] + array(
1625 'nid' => $this->node->nid,
1626 'rgid' => $rgid,
1627 'weight' => $weight,
1628 'target' => $enabled[$field['form_key']],
1629 'target_type' => 'component',
1630 );
1631 $rule_group['rules'] = array();
1632 foreach ($field['civicrm_condition']['rules'] as $source => $conditions) {
1633 $source_key = "civicrm_{$c}_{$ent}_{$n}_{$source}";
1634 $source_id = wf_crm_aval($enabled, $source_key);
1635 if ($source_id) {
1636 $options = wf_crm_field_options(array('form_key' => $source_key), '', $this->settings['data']);
1637 foreach ($conditions as $condition) {
1638 if (isset($options[$condition])) {
1639 $rule_group['rules'][] = array(
1640 'source_type' => 'component',
1641 'source' => $source_id,
1642 'operator' => 'equal',
1643 'value' => $condition,
1644 );
1645 }
1646 }
1647 }
1648 }
1649 if ($rule_group['rules']) {
1650 $this->node->webform['conditionals'][] = $rule_group;
1651 module_load_include('inc', 'webform', 'includes/webform.conditionals');
1652 webform_conditional_insert($rule_group);
1653 }
1654 }
1655
1656 private function help(&$field, $topic, $title = NULL) {
1657 wf_crm_admin_help::addHelp($field, $topic, $title);
1658 }
1659
1660 /**
1661 * Search for fields that should be deleted
1662 * @param array $fields
1663 * @return array
1664 */
1665 private function getFieldsToDelete($fields) {
1666 // Find fields to delete
1667 foreach ($fields as $key => $val) {
1668 $val = (array) wf_crm_aval($this->settings, $key);
1669 if (((in_array('create_civicrm_webform_element', $val, TRUE)) && $this->settings['nid'])
1670 || strpos($key, 'fieldset') !== FALSE) {
1671 unset($fields[$key]);
1672 }
1673 else {
1674 $field = wf_crm_get_field($key);
1675 if (!empty($val[0]) && $field['type'] == 'hidden') {
1676 unset($fields[$key]);
1677 }
1678 }
1679 }
1680 return $fields;
1681 }
1682
1683 /**
1684 * Add a CiviCRM field to a webform
1685 *
1686 * @param $field: array
1687 * Webform field info
1688 * @param $enabled: array
1689 * Array of enabled fields (reference)
1690 * @param $settings
1691 * webform_civicrm configuration for this form
1692 */
1693 static function insertComponent(&$field, &$enabled, $settings) {
1694 $options = NULL;
1695 list(, $c, $ent, $n, $table, $name) = explode('_', $field['form_key'], 6);
1696 $contact_type = $settings['data']['contact'][$c]['contact'][1]['contact_type'];
1697 // Replace the # token with set number (or append to the end if no token)
1698 if ($n > 1) {
1699 if (strpos($field['name'], '#') === FALSE) {
1700 $field['name'] .= " $n";
1701 }
1702 else {
1703 $field['name'] = str_replace('#', $n, $field['name']);
1704 }
1705 }
1706 elseif ($table == 'relationship') {
1707 $field['name'] = t('Relationship to !contact', array('!contact' => wf_crm_contact_label($n, $settings['data']))) . ' ' . $field['name'];
1708 }
1709 else {
1710 $field['name'] = str_replace(' #', '', $field['name']);
1711 }
1712 if ($name == 'contact_sub_type') {
1713 list($contact_types) = wf_crm_get_contact_types();
1714 $field['name'] = t('Type of @contact', array('@contact' => $contact_types[$contact_type]));
1715 }
1716 // Defaults for existing contact field
1717 if ($name == 'existing') {
1718 $vals = $enabled + $settings;
1719 // Set the allow_create flag based on presence of name or email fields
1720 $field['extra']['allow_create'] = $a = wf_crm_name_field_exists($vals, $c, $contact_type);
1721 $field['extra']['none_prompt'] = $a ? t('+ Create new +') : t('- None Found -');
1722 if ($c == 1 && $contact_type == 'individual') {
1723 // Default to hidden field for 1st contact
1724 $field['extra'] += array(
1725 'widget' => 'hidden',
1726 'default' => 'user',
1727 );
1728 }
1729 }
1730 // A width of 20 is more sensible than Drupal's default of 60
1731 if (($field['type'] == 'textfield' || $field['type'] == 'email') && empty($field['extra']['width'])) {
1732 $field['extra']['width'] = 20;
1733 }
1734 // Support html_textarea module
1735 if ($field['type'] == 'html_textarea') {
1736 $field['value']['format'] = filter_default_format();
1737 $field['value']['value'] = '';
1738 }
1739 // Retrieve option list
1740 if ($field['type'] == 'select') {
1741 if ($options = wf_crm_field_options($field, 'component_insert', $settings['data'])) {
1742 $field['extra']['items'] = wf_crm_array2str($options);
1743 // Default to select widget
1744 if (!isset($field['extra']['aslist']) && empty($field['extra']['multiple'])) {
1745 $field['extra']['aslist'] = 1;
1746 }
1747 // A single static radio should be shown as a checkbox
1748 if (count($options) == 1 && empty($field['extra']['aslist']) && empty($field['extra']['civicrm_live_options'])) {
1749 $field['extra']['multiple'] = 1;
1750 }
1751 }
1752 }
1753 if (isset($field['value_callback'])) {
1754 $method = 'get_default_' . $table . '_' . $name;
1755 $field['value'] = self::$method($field['form_key'], $options);
1756 }
1757 // For hidden+select fields such as contribution_page
1758 if ($field['type'] == 'hidden' && !empty($field['expose_list']) && !empty($settings[$field['form_key']])) {
1759 $field['value'] = $settings[$field['form_key']];
1760 }
1761 // Create fieldsets - for contact and contact-specific event fields only
1762 if ($ent != 'activity' && $ent != 'case' && $ent != 'contribution' && $ent != 'grant'
1763 && ($ent != 'participant' || wf_crm_aval($settings['data'], 'participant_reg_type') == 'separate')) {
1764 self::addFieldset($c, $field, $enabled, $settings);
1765 }
1766 // Create page break for contribution page
1767 if ($name == 'contribution_page_id') {
1768 self::addPageBreak($field);
1769 }
1770 // Merge defaults and create webform component
1771 $field += array('extra' => array());
1772 if ($defaults = webform_component_invoke($field['type'], 'defaults')) {
1773 $field += $defaults;
1774 }
1775 if (isset($enabled[$field['form_key']])) {
1776 $field['cid'] = $enabled[$field['form_key']];
1777 webform_component_update($field);
1778 }
1779 else {
1780 $enabled[$field['form_key']] = webform_component_insert($field);
1781 }
1782 }
1783
1784 /**
1785 * Create a fieldset around a contact if it doesn't already exist
1786 * @param $c
1787 * @param $field
1788 * @param $enabled
1789 * @param $settings
1790 */
1791 static function addFieldset($c, &$field, &$enabled, $settings) {
1792 $sid = 'civicrm_' . $c . '_contact_1_fieldset_fieldset';
1793 if (!empty($settings['create_fieldsets']) && !isset($enabled[$sid])) {
1794 $new_set = array(
1795 'nid' => $field['nid'],
1796 'form_key' => $sid,
1797 'type' => 'fieldset',
1798 'name' => wf_crm_contact_label($c, $settings['data']),
1799 'weight' => $c,
1800 );
1801 $new_set += webform_component_invoke('fieldset', 'defaults');
1802 $enabled[$sid] = webform_component_insert($new_set);
1803 }
1804 $field['pid'] = wf_crm_aval($enabled, $sid, 0);
1805 }
1806
1807 /**
1808 * Create a page-break before the contribution-page field
1809 * @param $field
1810 */
1811 static function addPageBreak($field) {
1812 $node = node_load($field['nid']);
1813 // Check if it already exists
1814 foreach (wf_crm_aval($node->webform, 'components', array()) as $component) {
1815 if ($component['form_key'] == 'contribution_pagebreak') {
1816 return;
1817 }
1818 }
1819 $pagebreak = array(
1820 'nid' => $field['nid'],
1821 'form_key' => 'contribution_pagebreak',
1822 'type' => 'pagebreak',
1823 'name' => t('Payment'),
1824 'weight' => $field['weight'] - 9,
1825 );
1826 $pagebreak += webform_component_invoke('pagebreak', 'defaults');
1827 webform_component_insert($pagebreak);
1828 }
1829
1830 /**
1831 * Default value callback
1832 */
1833 static function get_default_contact_cs($fid, $options) {
1834 return CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'checksum_timeout', NULL, 7);
1835 }
1836
1837 /**
1838 * Default value callback
1839 */
1840 static function get_default_contribution_payment_processor_id($fid, $options) {
1841 $default = wf_civicrm_api('payment_processor', 'get', array('is_default' => 1, 'is_test' => 0));
1842 if (!empty($default['id']) && isset($options[$default['id']])) {
1843 return $default['id'];
1844 }
1845 unset($options[0]);
1846 return $options ? key($options) : 0;
1847 }
1848
1849 /**
1850 * Delete civicrm settings for this webform.
1851 */
1852 private function disable() {
1853 db_delete('webform_civicrm_forms')
1854 ->condition('nid', $this->node->nid)
1855 ->execute();
1856 }
1857
1858 private function contactRefOptions($exclude = NULL) {
1859 $ret = array();
1860 foreach ($this->data['contact'] as $num => $contact) {
1861 if ($num != $exclude) {
1862 $ret[$num] = wf_crm_contact_label($num, $this->data, 'plain');
1863 }
1864 }
1865 return $ret;
1866 }
1867 }
1868
1869 /**
1870 * Drupal FAPI form builder callback
1871 */
1872 function wf_crm_configure_form($form, &$form_state, $node) {
1873 $admin_form = new wf_crm_admin_form(array(), $form_state, $node);
1874 return $admin_form->buildForm();
1875 }
1876
1877 /**
1878 * Drupal FAPI submit callback
1879 */
1880 function wf_crm_configure_form_submit($form, &$form_state) {
1881 $node = node_load($form_state['storage']['nid']);
1882 $admin_form = new wf_crm_admin_form($form, $form_state, $node);
1883 $admin_form->postProcess();
1884 }
1885
1886 /**
1887 * FAPI AJAX callback
1888 */
1889 function wf_crm_configure_form_ajax($form, $form_state) {
1890 return wf_crm_aval($form, $form_state['triggering_element']['#ajax']['pathstr']);
1891 }